Mit Hilfe des Such-Portlets lassen sich Suchformulare und Trefferlisten in eine Website integrieren.
Sowohl die Funktion als auch das Layout der Suche können angepasst werden, ohne dass Java-Code
geändert zu werden braucht. Das Portlet kann sowohl Anfragen an den Content Management Server als
auch an den Search Server senden. Es verwendet die in der Konfigurationsdatei pm.xml im
dem Eintrag searchEngine konfigurierte Suchmaschine.
Jede Suche wird in der Portlet-Web-Applikation in einem Verzeichnis unterhalb des
instanzenspezifischen Web-Applikationsverzeichnisses WEB-INF/templates/search
definiert.
Verwendung
Das Such-Portlet wird folgendermaßen in Layoutdateien eingebunden:
<npspm includeportlet="/PM-PL/search" instance="dealer" language="de" />
Der Instanzenname dealer entspricht hierbei dem Namen des Verzeichnisses, das die
Definition der Suche enthält. Mit language kann optional die vom Portlet zu verwendende
Sprache angegeben werden. Fehlt diese Angabe, wird die im Browser eingestellte Sprache
verwendet.
Konfiguration
Definition einer Suche
Eine Suche wird mit Hilfe zweier Velocity-Templates definiert, die sich im oben angegebenen
Verzeichnis unterhalb der jeweiligen Web-Applikation befinden müssen. Die Datei view.vm
legt das Layout des Suchformulars und der Trefferliste fest. Mit Hilfe der Datei
config.vm wird die vom Portlet auszuführende Suchanfrage definiert.
Da das Portlet sich mehrsprachig darstellen kann, wird je Sprache bzw. Locale der
Verity-Suchmaschine eine Lokalisierungsdatei mit dem Namen
localizer_xy.properties benötigt, wobei xy im obigen
Dateinamen durch das jeweilige Sprachkürzel ersetzt werden muss. Diese Dateien enthalten benannte
Zeichenketten in der folgenden Form:
title: Händler buttonSearch: Suchen errorNoResults: Ihre Suchanfrage hat keine Ergebnisse geliefert.
Beachten Sie bitte, dass die Kodierung der Localizer-Dateien UTF-8 sein muss.
Aufbau der Konfigurationsdatei config.vm
Nachdem das vom Portlet generierte Suchformular abgeschickt wurde, lädt und evaluiert das Portlet
das Velocity-Template config.vm, um aus den Eingaben im Formular die Suchanfrage zu
erzeugen. Die Parameter aus dem Suchformular stehen im Template unter ihrem Namen zur Verfügung.
Die Auswertung des Templates ergibt ein XML-Dokument, aus dem das Portlet ein Suchanfrage-XML-Dokument erzeugt, das der Search Server verarbeiten kann. Das Portlet sendet dieses Dokument an den Search Server und erhält als Antwort ein XML-Dokument, das die anzuzeigenden Suchergebnisse enthält.
Das vom Velocity-Template erzeugte XML-Dokument muss die folgende Struktur haben:
<query> <condition>...</condition> <result-fields>...</result-fields> <sort>...</sort> <collections>...</collections> <page-size>...</page-size> <max-hits>...</max-hits> <min-score>...</min-score> </query>
Mit Ausnahme der condition sind alle Elemente optional. Hier als Beispiel die Datei
config.vm für eine Suche nach Dokumenten, die einen Suchbegriff enthalten, und die für
jeden Benutzer frei zugänglich sind:
<query> <condition> <and> <vql-statement> <#MANY><#STEM>${searchText} </vql-statement> <vql-statement> <#MANY><#STEM>free <#IN> noPermissionLiveServerRead </vql-statement> </and> </condition> <result-fields> <field>title</field> <field>name</field> <field>visiblePath</field> <field>ip_abstract</field> </result-fields> <sort> <criterion> <field>pl_PLZ</field> <ascending/> </criterion> <criterion> <field>name</field> <ascending/> </criterion> </sort> <page-size>5</page-size> <collections> <collection>cm-contents-${language}</collection> </collections> <log> <context>search</context> #if ($user.isLoggedIn()) <login>${user.login}</login> #end <query>${searchText}</query> </log> </query>
Die Elemente der Suchanfrage haben die im Folgenden erläuterte Bedeutung:
-
condition: Dies legt die Suchanfrage fest. Dieconditionkann die folgenden Operatoren enthalten:-
and: dieses Element verknüpft die darin enthaltenen Elemente logisch mit und. -
contains: sucht nach Dateien, bei denen das Feldfielddie Zeichenkettevalueenthält. Beispiel:<contains> <field>keywords</field> <value>Dienstleistung</value> </contains>
-
contains-match: sucht nach Dateien, bei denen das Wildcard-Muster invalueauf den Wert des Feldesfieldpasst. Erlaubte Wildcards sind Stern (*) und Fragezeichen (?). -
equals: sucht nach Dateien, bei denen das Feldfieldexakt dem Wertvalueentspricht. Beispiel:<equals> <field>name</field> <value>mastertemplate</value> </equals>
-
or: verknüpft die im Element enthaltenen Elemente logisch mit oder. -
starts-with: sucht nach Dateien, bei denen das Feldfieldmit der Zeichenkettevaluebeginnt. -
vql-statement: enthält die Suchanfrage in der expliziten Verity-Anfrage-Sprache. Details zur Syntax finden Sie im Handbuch zum Search Server. Beachten Sie bitte, dass Sonderzeichen als HTML-Entities angegeben werden müssen, also beispielsweise<als<.
-
-
result-fields: Dieses Element spezifiziert in seinenfield-Unterelementen die Felder der gefundenen Dokumente, die ins Suchergebnis aufgenommen werden sollen, damit sie auf den Ergebnisseiten angezeigt werden können. -
sort: Hier lassen sich ein oder mehrere Kriterien spezifizieren, nach denen die Treffer sortiert werden sollen. Jedes Kriterium besteht aus dem Feldnamenfield, dessen Inhalt zur Sortierung herangezogen wird, sowie optional einem der Elementeascendingoderdescending, um die Sortierreihenfolge zu bestimmen. -
page-size: Mit diesem Element kann die Anzahl der Treffer angegeben werden, die das Portlet je Ergebnisseite anzeigen soll. -
collections: Geben Sie hier die zu durchsuchenden Collections an. Wird diese Angabe weggelassen, werden alle Collections durchsucht. -
log: Geben Sie hier die zu protokollierenden Einträge an. Mögliche Einträge sindcontext,loginundquery. Der Eintragcontextmuss angegeben sein, andernfalls findet keine Protokollierung statt.
Bitte beachten Sie, dass die zu durchsuchenden und auch die von der Suchmaschine
zurückzugebenden Felder (siehe oben result-fields, sort ) in
der Verity-Konfiguration definiert worden sein müssen, bevor die betreffende Collection
erzeugt wird (siehe die Dokumentation zur Search Cartridge).
Aufbau der Konfigurationsdatei view.vm
Mit diesem Velocity-Template wird der HTML-Text des Suchformulars und der Trefferliste generiert.
Mit den folgenden Schlüsselwörtern kann man im Template auf Objekte im Velocity-Kontext zugreifen:
-
$action: Die im Suchformular zu verwendende Aktion. -
$params: Liste der bisherigen Suchparameter. Interne Parameter (deren Name beginnt mit einem Unterstrich) tauchen in dieser Liste nicht auf. -
$text: bietet Zugriff auf lokalisierte Texte (aus den Lokalisierungsdateien im Definitionsverzeichnis). -
$locale: das aktuelle Locale. -
$search: Tool, mit dem URLs erzeugt werden können. Die folgenden Methoden sind verfügbar:-
String getPageUrl(Page page): liefert eine URL, mit der auf die angegebene Seite der Trefferliste gesprungen werden kann. -
String getSearchUrl(String parameter, String value): liefert eine URL, mit der eine Suche mit dem angegebenen Parameter durchgeführt werden kann. -
String highlight(String word, String text, String prefix, String suffix): Klammert jedes Vorkommen des angegebenen Worteswordim Texttextin die Zeichenkettenprefixundsuffixein.
-
-
$result: bietet mit den folgenden Methoden Zugriff auf die Trefferliste:-
int getHitCount(): liefert die Anzahl der Treffer. -
List getPages(): liefert die Liste derPage-Objekte im Suchergebnis. -
Page getCurrentPage(): liefert dasPage-Objekt, das die aktuelle Seite der Trefferliste repräsentiert.
-
Die Eigenschaften der oben aufgeführten Objekte sind in der mit dem Portlet gelieferten javadoc-Dokumentation beschrieben. Beispiel (oben das Formular, unten das Verlocity-Template):
<form method="get" action="$action"> <input type="text" name="searchText" value="$!params.searchText"/> <input type="submit" name="_buttonSearch" value="$text.buttonSearch"/> </form> #if ($result) #if ($result.hitCount == 0) $text.errorNoResults #else <ul> #foreach ($item in $result.currentPage.hits) #set($path = $document.getUrl($item.visiblePath)) <li><a href="$path">$item.title</a></li> #end </ul> #end #end
Den Zugriff auf die Suchmaschine konfigurieren
Die Suchmaschine wird in der Datei pm.xml als bean
searchEngine konfiguriert. Es stehen zwei Implementierungen zur Auswahl, der
direkte Zugriff über den Search Server und der Zugriff über den Content Management
Server.
SesSearchEngine: Für die Suche auf dem Live-System werden die
Suchanfragen direkt an den dort laufenden Search Engine Server geschickt:
<bean id="searchEngine" class="com.infopark.libs.search.ses.SesSearchEngine"> <property name="host"><value>localhost</value></property> <property name="port"><value>3011</value></property> </bean>
AdvancedCmSearchEngine: Bei der Suche über den Content Management Server
wird das Redaktionssystem durchsucht. Der Content Management Server leitet die Anfragen
an den für das Redaktionssystem zuständigen Search Engine Server weiter, fügt zu jedem
Treffer jedoch den Pfad der gefundenen CMS-Datei hinzu:
<bean id="searchEngine" class="com.infopark.libs.search.cm.AdvancedCmSearchEngine"> <property name="host"><value>localhost</value></property> <property name="port"><value>3002</value></property> <property name="user"><value>root</value></property> <property name="tokenManager"> <ref bean="tokenManager"/> </property> </bean>
Beispiel
Das folgende Beispiel zeigt, wie eine neue Suche im Democontent-Portal erstellt wird. Ein einzugebender Suchbegriff soll im Hauptinhalt und im Titel sowie in der Zusammenfassung gesucht werden, also in den Feldern mit den Namen blob, title und ip_abstract. Auf den Ergebnisseiten sollen die Felder title und ip_abstract ausgegeben werden. Die Zusammenfassung soll nur angezeigt werden, wenn sie Text enthält, also nicht leer ist.
Vorbereitung der Suchmaschinen-Indizes
Die oben genannten Felder können erst verwendet werden, nachdem die Konfiguration der Suchmaschine auf der Live-Seite so erweitert wurde, dass die zusätzlichen Felder zur Verfügung stehen und beim Indizieren der Dokumente gefüllt werden.
Öffnen Sie hierfür die zu der Instanz und der betreffenden (zu durchsuchenden) Collection gehörende Datei
instance/instanceName/config/vdk/styles/collectionName/style.ufl
und tragen Sie zuätzlich zu den bestehenden Feldern die folgenden Felder ein:
# ----------------------------------------------------------------- # Specify additional application-specific fields here in their own # data-table[s]. data-table: nps { **** Bisherige Felder stehen hier **** **** Neue Felder varwidth: ip_abstract dxa autoval: collection DBNAME }
Stoppen Sie vor den nachfolgenden Schritten den Search Engine Server:
./rc.npsd stop SES
Damit die Änderungen wirksam werden, muss die Collection neu angelegt und die Dokumente müssen neu indiziert werden. Starten Sie hierfür den Search Engine Server im Singlemodus:
./SES -single
Führen Sie nun die folgenden Schritte für die betreffende Collection aus:
% deleteCollection collectionName % createCollection collectionName % exit
Starten Sie den Search Engine Server:
./rc.npsd start SES
Melden Sie sich nun am Content Management Server an:
./client localhost 3001 root demo
Indizieren Sie mit dem folgenden Kommando alle NPS-Dateien neu:
CM>indexAllObjects CM>exit
Die neue Suche erstellen
Wechseln Sie in das Verzeichnis
/instance/instanceName/webapps/PM-PL/WEB-INF/templates/search
und legen Sie unter dem Namen bodySubjects eine Kopie des vorhandenen Verzeichnisses nameTitle an. Wechseln Sie nun in den Ordner und bearbeiten Sie die beiden Dateien config.vm und view.vm.
In der Datei config.vm wird die Suchanfrage konfiguriert. Ändern Sie zu diesem Zweck den Inhalt des condition-Elements so, dass er nur das folgende vql-statement-Element enthält:
<vql-statement> ("${suche}" <#IN> blob) <#OR> (title <#SUBSTRING> "${suche}") <#OR> (ip_abstract <#SUBSTRING> "${suche}") </vql-statement>
Beachten Sie, dass die Suchanfrage aus mehreren Teilen (eines pro Feld) besteht, die miteinander mit OR verknüpft sind. Da der blob (der Hauptinhalt) eine Dokumentzone und kein Feld ist (wie title und ip_abstract), wird für ihn der Operator IN verwendet, der Dokumentzonen durchsucht. Der Operator SUBSTRING dagegen durchsucht Feldinhalte.
Da in den Suchergebnissen die Inhalte des Feldes ip_abstract vorkommen sollen, muss das Element result-fields um dieses Feld ergänzt werden:
<result-fields> <field>objId</field> <field>name</field> <field>title</field> <field>score</field> <field>visiblePath</field> <field>ip_abstract</field> </result-fields>
Die Such- und Ergebnisseite erstellen
Die Such- und Ergebnisseite werden in der Datei view.vm zusammengestellt. Der obere Teil definiert das Suchformular:
<form action="$action" method="post"> <div> Ihre Suche <input type="text" name="suche" value="$!params.suche" /> </div> <input type="submit" name="dialog.buttonOk" value="$text.buttonOk" /> </form>
Der untere Teil der Datei view.vm sorgt dafür, dass die Ergebnisse angezeigt werden, nachdem der Benutzer das Suchformular abgeschickt hat. Alle Ergebnisse sollen als Liste dargestellt werden, die je Treffer dessen Titel (verlinkt) und die Zusammenfassung enthält, also in folgender Form:
<ul> <li>Verlinkter Titel<br /> ip_abstract</li> <li>...</li> <li>...</li> </ul>
Um diese Darstellung zu erreichen, wird der folgende Code verwendet:
#if ($result) #if ($result.hitCount == 0) <div>$text.noHits</div> #else <!-- Anzahl der Ergebnisse --> <div>$text.hitCount $result.hitCount</div> <!-- Beginn Auflistung der Ergebnisse --> <ul> #foreach ($item in $result.currentPage.hits) <li> #set($path = $document.getUrl($item.visiblePath)) #if ($path)<a href="$path">#end $item.title #if ($path)</a>#end #if ($item.ip_abstract)<br />$itm.ip_abstract#end </li> #end </ul> <!-- Ende Auflistung der Ergebnisse --> <!-- Links zu anderen Ergebnisseiten erzeugen --> <div> #foreach ($page in $result.pages) #if ($page.isCurrent()) $page.number #else <a href="$search.getPageUrl($page)">$page.number</a> #end #end </div> <div>$text.page $result.currentPage.number $text.pageOf $result.pages.size() </div> <!-- Ende Übersicht Ergebnisseiten --> #end #end
Um die Pfade in der Ergebnisliste vom Anfang her um ein Verzeichnis zu kürzen, so dass ein übergeordneter Ordner nicht angezeigt wird, verwenden Sie in der foreach-Schleife den folgenden Code:
## Verzeichnistrenner (slash) suchen #set( prefix $path.indexOf("/", 1) ) ## Statt mit $path folgendermaßen auf den Pfad zugreifen $path.substring($prefix + 1)
Das Portlet in eine Webseite einbinden
Um das Portlet in eine Webseite einzubinden, fügen Sie bitte die folgende Zeile in eine Layoutdatei ein, mit der anzuzeigende Seiten erzeugt werden:
<npspm includePortlet="/PM-PL/search" instance="bodySubjects" />
In der separaten Vorschau wird nun das Portlet angezeigt und kann verwendet werden.
Eingabefelder des Suchformulars leeren
Das Suchportlet speichert die in seinem Suchformular enthaltenen Eingaben. Ruft ein Website-Besucher nach einer Suche erneut die Suchseite auf (die Seite, die das Suchportlet enthält), so enthält das Formular die letzten Eingaben, auch wenn die Suchseite zwischenzeitlich verlassen wurde.
Da dieses Verhalten normalerweise nicht erwünscht ist, kann man das Portlet die
Eingabefelder leeren lassen. Bis Version 6.0.x fügen Sie hierzu in die URL auf
die Suchseite den Parameter reset=true hinzu. Beispiel:
<a href="/suchen.html?reset=true">Suche</a>
Ab Version 6.5.1 fügen Sie stattdessen einen Link auf das Remote-Control-Portlet ein. Beispiel:
<npspm includePortlet="/PM-PL/remoteControl" instance="search"> targetUrl=/suchen.html emptySearch=true emptySearchLinkText=Zur Suche </npspm>
Der verlinkte Text ist im Portlet selbst konfiguriert und lautet "Neue Suche". Wenn Sie den verlinkten Text wie im obigen Beispiel mit dem Parameter emptySearchLinkText beim Portlet-Aufruf angeben können möchten, ersetzen Sie bitte in der zum Control-Portlet gehörenden Template-Datei
webapps/PM-PL/WEB-INF/templates/remote/search/view.vm die Zeile
<a href="javascript:document.emptySearch.submit();">$text.emptySearch</a>
durch folgenden Code:
#if ($params.emptySearchLinkText) #set ($linkText = $params.emptySearchLinkText) #else #set ($linkText = $text.emptySearch) #end <a href="javascript:document.emptySearch.submit();">$linkText</a>