The CMS offers a flexible interface for fulltext searching. Implementing projects and define their own SearchProviders, or use an existing one or even multiple providers.

Note: Currently, the CMS shipps with an ElasticSearch SearchProvider. Instruction see below.

Search architecture

ch.insign.commons.search

Contains a basic search provider framework, including:

  • SearchManager
  • SearchProvider interface
  • SearchQuery (POJO)
  • SearchResult interface (with a DefaultSearchResult default implementation)

Usage:

SearchManager sm = new SearchManager();
sm.register(new ElasticSearchProvider());
 
SearchQuery query = new SearchQuery(keywords);
List<SearchResult> results = sm.search(query);

From within the cms, you reach the SearchManager via CMS.getSearchManager()

Configuration settings

Defaults in the cms' application.conf:

play-cms/conf/application.conf:

# Search providers
cms.search.elastic.enabled = false
 
# Elastic settings
elastic.host = "http://localhost:9200"
elastic.snippet.number = 2
elastic.snippet.size = 100
 
 
# Needs to match the cluster name in ELs config/elasticsearch.yml
# Ensure different cluster names are used for all independent machines (e.g. test, production, dev) in the same network!
elastic.cluster = "elasticsearch"

Note: ElasticSearch is disabled by default. It is recommended to use a local.conf file to individually enable/disable ElasticSearch and give unique cluster names.

local.conf:
# ElasticSearch search provider
cms.search.elastic.enabled = true
 
# needs to match the cluster name in ELs config/elasticsearch.yml
elastic.cluster = "elasticsearch-local-dev-bachi"

Implementing the frontend

Test search route

By default, there is a search route enabled which gives a rough debug search output:

cms.routes:
GET      /search/:query     ch.insign.cms.controllers.FrontendController.search(query: String)

In production however, you will create your own cms page as a search result page (by adding a SearchResultBlock)

Real search result page

  1. In your Setup subclass, create (on initializing so it will endure /reset) a cms page that contains a SearchResultBlock
  2. Give the page a key, e.g. searchresult
  3. Add the search form to your templates, e.g. :
<form action="@PageBlock.find.byKey(MyCmsSetup.KEY_SEARCHRESULT_PAGE).getNavItem.getURL">
    <input type="text" name="query" class="form-control" placeholder="Search …">
    <button type="submit"></button>
</form>

Custom searches

  • You can add additional SearchProviders (results from each provider are merged) or subclass or replace the default one
  • You can create your own SearchResultBlock or subclass the existing one

Exclude template parts from the search index

To exclude html content from the search index, you need to mark it in your templates:

@if(!Template.isIndexer) { Here goes eg. global content like navigation that you don't want indexed}

Note: The SearchProvider's indexing code needs to add &indexer=true to each request. This param is not protected as it is meant to remove public content from the searchindexer. This makes testing easy, just add &indexer=true to your url.

 

Installing the ElasticSearch server

  1. Download and run the package as described here
    Hint: If you use the .deb package, you can use sudo service start | stop | restart and the service's automatically started on startup
  2. Recommended: Install the elasticsearch-head plugin to have a neat admin UI
  3. Edit conf/elasticsearch.yml and set the cluster name (matching the name defined in your Play's config, see above). Restart the server.
  4. Edit a page - when saving, the indexer should be started and index the page. Or call /reset - this should completely empty and refill the index. 
  5. Search something. 

Troubleshooting

  • Search for Play log entries, such as:

[info] application - Elastic: Trying to connect to cluster 'http://localhost:9200' on 'elasticsearch-local-bachi'

[info] application - ElasticSearchProvider: Added/updating url http://localhost:9000/handtuch?indexer=true

  • Check status and content of the ElasticSearch server (using the Head plugin @ e.g. http://localhost:9200/_plugin/head/
  • Ensure both sides use the same cluster name (and that it is unique in your local network)