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.
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.
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.
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. Die
condition
kann die folgenden Operatoren enthalten:
and
: dieses Element verknüpft die darin
enthaltenen Elemente logisch mit und.contains
: sucht nach Dateien, bei denen das
Feld field
die Zeichenkette value
enthält. Beispiel:
<contains> <field>keywords</field> <value>Dienstleistung</value> </contains>
contains-match
: sucht nach Dateien, bei denen
das Wildcard-Muster in value
auf den Wert des Feldes
field
passt. Erlaubte Wildcards sind Stern (*
) und
Fragezeichen (?
).equals
: sucht nach Dateien, bei denen das Feld
field
exakt dem Wert value
entspricht. 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
Feld field
mit der Zeichenkette value
beginnt.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 seinen
field
-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 Feldnamen field
, dessen Inhalt zur Sortierung herangezogen wird,
sowie optional einem der Elemente ascending
oder
descending
, 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 sind context
, login
und
query
. Der Eintrag context
muss 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).
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
Wortes word
im Text text
in die Zeichenketten
prefix
und suffix
ein.$result
: bietet mit den folgenden Methoden Zugriff auf die
Trefferliste:
int getHitCount()
: liefert die Anzahl der Treffer.List getPages()
: liefert die Liste der
Page
-Objekte im Suchergebnis.Page getCurrentPage()
: liefert das
Page
-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
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>
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.
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
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 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)
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.
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>