« Zurück zu Development

Adding search capabilities to a portlet

This article needs updating. For more information, see Wiki - Need Updating.

Introduction#

This article shows how to add search capabilities to a portlet.

Example - Bookmark Portlet #

1. Implement a com.liferay.portal.kernel.search.Indexer class, like this one: http://lportal.svn.sourceforge.net/viewvc/lportal/portal/trunk/portal-impl/src/com/liferay/portlet/bookmarks/util/Indexer.java?view=markup

This class is responsible for adding/updating/deleting documents to the index, it uses SearchEngineUtil which is an abstraction to the underlying search engine that is being used (currently you can use Solr or Lucene, Lucene is the default engine).

When adding a document you create a Document instance and pass it to SearchEngineUtil.addDocument along with the companyId. A com.liferay.portal.kernel.search.Document is just a collection of Fields, a com.liferay.portal.kernel.search.Field has a name and a value which is the content that you want to search for, for example, a Bookmark entry has a name "This is a Bruno bookmark entry.", later on, you can search for it with this query: name:"bruno".

A call to document.addText will add a Field to the document and its value will be filtered before indexed. All words that don't help with to bring relevant search results will be removed (like punctuation, pronouns, adverbs), in the example above the bookmark entry name would become "bruno bookmark entry". addText is usually called when the content to be indexed is a long text.

A call to document.addKeyword will add a Field to the document and its value will be indexed with no modification.

document.addUID is very important because it's used to create a unique identifier to the document in the index. You will need it to update or delete the document later. There are some other useful methods to Document, like addFile, that extracts contents from many file formats, and addModifiedDate which adds the current Date as a field to the document.

Some fields are commonly used: groupId, portletId, companyId, they are useful because you can narrow your searches to only show documents that were created in a certain community or company or even a specific portlet instance.

Indexer.getDocumentSummary is used by the Search portlet to aggregate all results from all portlets in just one place, DocumentSummary will be used to render each document in the search result listing.

2. Add a <indexer-class> to liferay-portlet.xml pointing to this class. Whenever you hit the button Re-index the Indexer re-index method will be called.

3. Whenever a Bookmark entry is added/updated/deleted from the database the Indexer is called to update the index accordingly. Search for Indexer at: http://lportal.svn.sourceforge.net/viewvc/lportal/portal/trunk/portal-impl/src/com/liferay/portlet/bookmarks/service/impl/BookmarksEntryLocalServiceImpl.java?view=markup

Observe the places where Indexer is called:

Indexer.addEntry(entry.getCompanyId(), folder.getGroupId(), folderId, entryId, name, url, comments, tagsEntries); Indexer.deleteEntry(entry.getCompanyId(), entry.getEntryId()); Indexer.updateEntry(entry.getCompanyId(), folder.getGroupId(), entry.getFolderId(), entry.getEntryId(), name, url, comments, tagsEntries);

If you encounter a NullPointerException while retrieving your portlet's indexer (portlet.getIndexerInstance() returning null), check the portletId returned by YourIndexer.getPortletId() and keep in mind the portletId outside the portal will be "<portlet-name in portlet.xml>_WAR_<webapp name>"

4. Now that Bookmark entries can be added/updated and removed from the index you are able to make searches requests to SearchEngineUtil, take a look at: http://lportal.svn.sourceforge.net/viewvc/lportal/portal/trunk/portal-impl/src/com/liferay/portlet/bookmarks/service/impl/BookmarksFolderLocalServiceImpl.java?view=markup

Look at the search method: public Hits search(long companyId, long groupId, long[] folderIds, String keywords, int start, int end)

It constructs a com.liferay.portal.kernel.search.Query instance and calls SearchEngineUtil.search(companyId, fullQuery, start, end) which returns a Hits instance.

A BooleanQuery is one implementation of Query, you can specify which field values MUST (AND operator), SHOULD (OR operator) or MUST_NOT (NOT AND operator) occurrences in the results. You can create composite BooleanQueries by adding one to another.

Start and end parameters are used to paginate the results, for example if start == 0 and end == 2, only the first two entries will appear in the result, if both are equal to QueryUtil.ALL_POS (-1) than all results will be returned.

5. Now that you have the search method you can use it in a jsp, for example: http://lportal.svn.sourceforge.net/viewvc/lportal/portal/trunk/portal-web/docroot/html/portlet/bookmarks/search.jsp?view=markup

This jsp calls the search method and iterates over com.liferay.portal.kernel.search.Hits which is a collection of Documents and represents the result of the search. The Hits class gives the score (the importance) of each document, tells you how long the search took and how many documents were found.

On each Document you can get the values of each field by calling document.get(String fieldName) or getValues in case the Field has multiples stored values.

6. If you want that your portlet will be listed in the Search portlet results you need to do one more step, create a com.liferay.portal.kernel.search.OpeanSearch implementation and add a <open-search-class> to your liferay-portlet.xml. Take a look at how this is implemented for Bookmark portlet:

http://lportal.svn.sourceforge.net/viewvc/lportal/portal/trunk/portal-impl/src/com/liferay/portlet/bookmarks/util/BookmarksOpenSearchImpl.java?view=markup

With this implementation you will also be able to expose search results in the OpenSearch standard format which can be interpreted by many OpenSearch clients, for more information, go to: http://www.opensearch.org

0 Anhänge
93134 Angesehen
Durchschnitt (2 Stimmen)
Die durchschnittliche Bewertung ist 4.5 von max. 5 Sternen.
Kommentare
Antworten im Thread Autor Datum
Will it search only "Bruno" what will be the... Ankur Bhargava 9. Februar 2009 06:11
Are there any more updated documents/examples... Aaron Daubman 29. Oktober 2010 10:47
Succesfuly done it in a portlet. Thanks for the... Sergey Stepanenko 8. April 2011 05:03
Great article helped me a lot .. Thanks a lot GAURAV RAWAT 6. Januar 2012 22:57
poxa, que artigo util, o exemplo entao!!... ricardo wolosker 11. Januar 2012 05:39
I am trying to find out how to index entities... Beate Biller 22. Februar 2012 06:25
I'm with Sergey on this. Does anyone have a... Lee PM 23. März 2012 12:28
Hi i am struggling with point 6, more precisely... Botty Dimanov 21. Juni 2013 06:38

Will it search only "Bruno" what will be the results when we search "Bruno bookmark" ?
Gepostet am 09.02.09 06:11.
Are there any more updated documents/examples for this. I'm finding this guide difficult to follow for Liferay 6.0EE and Solr 1.4.1 with solr-web-6.0.10.1
Gepostet am 29.10.10 10:47.
Succesfuly done it in a portlet. Thanks for the info.

However I cannot figure out how to work with opensearch - it does work and displays results, but summary link misses p_p_auth token while other assets do have it. Hence the link from opensearch resolver into permission error for portlet.
Gepostet am 08.04.11 05:03.
Great article helped me a lot .. Thanks a lot
Gepostet am 06.01.12 22:57.
poxa, que artigo util, o exemplo entao!! Fantastico, Muito bom. Quando é o curso? R$ R$ R$ R$ R$ R$ R$ R$ R$ R$ R$ R$ R$ R$ R$
Gepostet am 11.01.12 05:39 als Antwort auf GAURAV RAWAT.
I am trying to find out how to index entities with a one-to-many relationship. Does anyone have an example for this?
Gepostet am 22.02.12 06:25.
I'm with Sergey on this. Does anyone have a good resource on opensearch basics?
I just want to add a simple external site, say yahoo through opensearch and have results in my CE 6.0/6.1 site. Does there exist a tutorial/howto for this? Thanks in advance.
Gepostet am 23.03.12 12:28 als Antwort auf Beate Biller.
Hi i am struggling with point 6, more precisely where should the search path of OpenSearch point to?
Gepostet am 21.06.13 06:38.