By means of the search portlet, search forms and results lists can be integrated into a website.
Both the function and the layout of the search can be adapted to meet individual needs without having to modify Java code. The portlet supports sending requests to the Content Management Server as well as to the Search Engine Server. It uses the search engine configured in the searchEngine
entry of the pm.xml
configuration file.
Each search is represented by an individual directory below the instance-specific web application directory WEB-INF/templates/search
.
The search portlet can be included in layout files in the following way:
<npspm includeportlet="/PM-PL/search" instance="dealer" language="de" />
The instance name, dealer
, corresponds to the name of the directory containing the search definition. language
optionally lets you define the language to be used by the portlet. If it is not specified, the language set in the browser is used.
Any number of searches can be defined. Each of them is defined by means of two Velocity templates located in the web application directory mentioned above. The view.vm
file determines the layout of the search form and the results list while config.vm
determines the search query to be executed by the portlet.
Since the portlet is capable of displaying itself in several languages, a localization file, localizer_xy.properties
, is required for each locale of the Verity search engine. In the file name mentioned, xy
stands for the language code concerned. In these files, named strings are defined in the following form:
title: Dealer buttonSearch: Search errorNoResults: Your search query did not return any results.
Please note that the localizer files need to be UTF-8-encoded.
config.vm
Configuration FileAfter the search form generated by the portlet has been sent, the portlet loads and evaluates the config.vm
Velocity template to generate the search query from the data given in the input elements of the form. The parameters from the search form are available in the template under their names.
The evaluation of the template yields an XML document the Search Server is able to process. The portlet sends this document to the Search Server and receives as response an XML document containing the search results to be displayed.
The XML document generated by the Velocity template is required to have the following structure:
<query> <condition>...</condition> <result-fields>...</result-fields> <sort>...</sort> <collections>...</collections> <page-size>...</page-size> <max-hits>...</max-hits> <min-score>...</min-score> </query>
All elements except condition
are optional. In the following config.vm
example file, a search for documents containing a search term is defined. Only documents without any access restrictions are returned:
<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>
In the following, the meaning of the elements of which the search query consists is explained:
condition
: This defines the search query. The
condition
may contain the following operators:
and
: this element combines the elements
contained in it with a logical and.contains
: searches files, whose field with name
field
contains the string value
. Example:
<contains> <field>keywords</field> <value>service</value> </contains>
contains-match
: searches files, where the
wildcard pattern value
matches the content of the field named
field
. Valid wildcards are asterisk (*
) and
question mark (?
).equals
: searches files, where the field named
field
equals exactly the string value
. Example:
<equals> <field>name</field> <value>mastertemplate</value> </equals>
or
: combines the elements contained in it using
or.starts-with
: searches files, where the field
with name field
begins with the string value
.vql-statement
: contains the search query in the
explicit Verity query language. For a detailed explanation of the syntax,
please refer to the Search Server manual. Note that special characters need to be specified
as HTML entities, for example <
as <
.result-fields
: This element specifies in its field
subelements the fields of the resulting documents to be added to the search results.
This makes it possible to display the values of these fields on the result pages.sort
: Here, one or more criteria for sorting the search results
can be specified. Each criterion consists of a field name, field
, whose
contents is used for sorting, as well as optionally either ascending
or
descending
to define the sort order.page-size
: By means of this element, the number of hits to be
displayed on each result page can be specified.collections
: Specify here the collections to be searched. If
this information is omitted, all collecions are searched.log
: Specify here the elements to be tracked. Permitted
elements are context
, login
, and query
.
context
must be specified, otherwise tracking is disabled.Please note that the fields to be searched and also to be returned by the search
engine (see result-fields
, sort
above) must have been defined
in the Verity configuration prior to creating the collection concerned (see the
Search Cartridge
documentation).
This Velocity template serves to generate the HTML text of the search form and the results list.
In the template, you can use the following keywords to access objects in the Velocity context:
$action
: The action to use in the search form.$params
: The list of search parameters used so far.
Internal parameters (whose name begins with a underscore character) do not show up in
this list.$text
: offers access to localized texts (originating from
the localization files in the definition directory).$locale
: the current locale.$search
: Tool with which URLs can be generated. The
following methods are available:
String getPageUrl(Page page)
: returns an URL
for jumping to the specified page of the results list.String getSearchUrl(String parameter, String value)
: returns an URL for performing a search using the given
parameter.String highlight(String word, String text, String prefix, String suffix)
: encloses each occurrence of the specified
word
in text
into the strings prefix
and suffix
ein.$result
: allows accessing the results list by means of the
following methods:
int getHitCount()
: returns the number of hits.List getPages()
: returns the list of
Page
objects in the search result.Page getCurrentPage()
: returns the
Page
object which represents the current page of the results
list.The properties of the the objects listed above are described in the portlet's javadoc documentation. Example (starting with the form, then comes the Velocity 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
The search engine is configured in the pm.xml
file as a the searchEngine
bean. Two implementations are available, direct access via the Search Server, and access via the Content Management Server.
SesSearchEngine
: For the live system search the search queries are sent directly to the Search Server running on the live system:
<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
: When searching via the Content Management Server, the editorial system is searched. Der Content Management Server redirects the queries to the Search Server associated with the editorial system. However, it adds to each hit the path of the CMS file found:
<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>
The following example illustrates how a new search can be created in the portal included in the demo content. The search term that was entered is to be found in the main content, the title, or the abstract, i.e. in the fields named blob
, title
, and ip_abstract
. On the result pages, the fields title
and ip_abstract
are to be output. The abstract is to be displayed only if it contains text, i.e. if it is not empty.
The fields mentioned above can only be used after the configuration of the search engine on the live server side has been extended so that the additional fields are available and filled-in when documents are indexed.
For this, open the file belonging to the collection which is to be searched, located in the instance concerned.
instance/instanceName/config/vdk/styles/collectionName/style.ufl
Add the following fields:
# ----------------------------------------------------------------- # Specify additional application-specific fields here in their own # data-table[s]. data-table: nps { **** Existing fields **** **** New fields varwidth: ip_abstract dxa autoval: collection DBNAME }
Stop the Search Engine Server:
./rc.npsd stop SES
For the changes to become effective, the collection needs to be created again and the documents need to be reindexed. To do this, start the Search Server in single mode:
./SES -single
Now, perform the following steps for the collection concerned:
SES>deleteCollection collectionName SES>createCollection collectionName SES>exit
Start the Search Engine Server:
./rc.npsd start SES
Now, connect to the Content Management Server:
./client localhost 3001 root demo
Reindex all NPS files using the following command:
CM>indexAllObjects CM>exit
Change to the directory
/instance/instanceName/webapps/PM-PL/WEB-INF/templates/search
and make a copy of the existing directory nameTitle
and name it bodySubjects
. Then change to this directory and edit the files named config.vm
and view.vm
.
In the file config.vm
the search query is configured. For this purpose change the contents of the condition
element so that it contains only the following vql-statement
element:
<vql-statement> ("${suche}" <#IN> blob) <#OR> (title <#SUBSTRING> "${suche}") <#OR> (ip_abstract <#SUBSTRING> "${suche}") </vql-statement>
Please note that the serach query consists of several parts (one per field), all of which are combined with OR. Since the main content (blob
) is a document zone and not a field (like title
and ip_abstract
), the operator IN, which searches document zones, is used for searching it. The SUBSTRING operator, on the other hand, searches the contents of fields.
Since the search results are to include the contents of the ip_abstract
field, it needs to be added to the result-fields
element:
<result-fields> <field>objId</field> <field>name</field> <field>title</field> <field>score</field> <field>visiblePath</field> <field>ip_abstract</field> </result-fields>
The search and results page are created in the file view.vm
. Its upper section defines the search form:
<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>
The lower section of the file view.vm
makes it possible to display the results after the user has submitted the search form. All results are to be displayed as a list. For each hit, the (linked) title and the abstract of the document is to be displayed:
<ul> <li>Verlinkter Titel<br /> ip_abstract</li> <li>...</li> <li>...</li> </ul>
To achieve this display format, the following code is used:
#if ($result) #if ($result.hitCount == 0) <div>$text.noHits</div> #else <!-- Number of results --> <div>$text.hitCount $result.hitCount</div> <!-- Begin of results list generation --> <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 />$item.ip_abstract#end </li> #end </ul> <!-- End of results list generation --> <!-- Create links to other results pages --> <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> <!-- End of results pages overview --> #end #end
In order to remove the first directory from the paths in the results list (so that the root folder is not displayed), use the following code in the foreach
loop:
## Search for directory delimiter (slash) #set( prefix $path.indexOf("/", 1) ) ## Do not use $path to access the path, instead use: $path.substring($prefix + 1)
To include the portlet in a web page, add the following line to a layout file used for generating the pages to be displayed:
<npspm includePortlet="/PM-PL/search" instance="bodySubjects" />
The portlet is now displayed in the separate preview and can be used.
The search portlet stores the values contained in its input fields. If, after a search, a website visitor reenters the search page (the page containing the search portlet), the form contains the values that were entered before.
Since this behavior is normally unwanted, you can have the portlet clear the input
fields. For this, up to version 6.5.0, add the reset=true
parameter to the
URL that links to the search page. Example:
<a href="/suchen.html?reset=true">Search</a>
From version 6.5.1, add a link to the remote control portlet instead. Example.
<npspm includePortlet="/PM-PL/remoteControl" instance="search"> targetUrl=/search.html emptySearch=true emptySearchLinkText=Search </npspm>
The linked text is configured in the portlet itself and reads "New Search". If you
wish to be able to specify the linked text in each call to the portlet, using the
parameter emptySearchLinkText
like in the example above, replace in the
webapps/PM-PL/WEB-INF/templates/remote/search/view.vm
template file the
line
<a href="javascript:document.emptySearch.submit();">$text.emptySearch</a>
with the following code:
#if ($params.emptySearchLinkText) #set ($linkText = $params.emptySearchLinkText) #else #set ($linkText = $text.emptySearch) #end <a href="javascript:document.emptySearch.submit();">$linkText</a>