(Quick Reference)

5 Searching - Reference Documentation

Authors: Noam Y. Tenne, Manuarii Stein, Stephane Maldini, Serge P. Nekoval, Marcos Carceles

Version: 0.0.4.6

5 Searching

The plugin provides 2 ways to send search requests.
  • You can use the elasticSearchService and its public search method for cross-domain searching, meaning that ElasticSearch

may analyze multiple indices and return hits of different types (=different domains).

def res = elasticSearchService.search("${params.query}")
// 'res' search results may contains multiple types of results
  • You can use the injected dynamic method in the domain for domain-specific searching.

def res = Tweet.search("${params.query}")
// 'res' search results contains only Tweet instances

These search methods return a Map containing 3 entries:

  • a total entry, representing the total number of hits found
  • a searchResults entry, containing the hits
  • a scores entry, containing the hits scores

Example

def res = Tweet.search("${params.query}")
println "Found ${res.total} result(s)"
res.searchResults.each {
    println it.message
}

def res = elasticSearchService.search("${params.query}") println "Found ${res.total} result(s)" res.searchResults.each { if(it instanceof Tweet) { println it.message } else { println it.toString() } }

If you're willing to retrieve only the number of hits for a peculiar query, you can use the countHits() method. It will only return an Integer representing the total hits matching your query.

Example

def res = Tweet.countHits("${params.query}")
println "Found ${res} result(s)"

def res = elasticSearchService.countHits("${params.query}", [indices:'test']) println "Found ${res} result(s)"

5.1 Query Strings

The search method injected in the domain or the ElasticSearchService has multiple signatures available. You can pass it a simple String to compute your search request. That string will be parsed by the Lucene query parser so feel free to use its syntax to do more specific search query.

You can find out about the syntax on the Apache Lucene website.

Example

def results = elasticSearchService.search("${params.query}")
def resultsTweets = Tweet.search("message:${params.query}")

5.2 Query Closure

You can use the Groovy Query DSL to build your search query as a Closure. The format of the search Closure follow the same JSON syntax as the ElasticSearch REST API and the Java Query DSL.

Example

def result = elasticSearchService.search(searchType:'dfs_query_and_fetch') {
  bool {
      must {
          query_string(query: params.query)
      }
      if (params.firstname) {
          must {
              term(firstname: params.firstname)
          }
      }
  }
}

5.3 Query QueryBuilder

A QueryBuilder can be passed to the search method.

Example

QueryBuilder query = QueryBuilders.matchAllQuery()
def result = elasticSearchService.search(query)

5.4 Filter Closure

A filter closure can be passed as a second argument after the search closure to the search method.

Example

def result = elasticSearchService.search(
    [indices: Building, types: Building, sort: sortBuilder],
    null as Closure,
    {
        geo_distance(
            'distance': '5km',
            'location': [lat: 48.141, lon: 11.57]
        )
    })

5.5 Filter FilterBuilder

A FilterBuilder filter can be passed as a second argument after the search parameter to the search method.

Example

FilterBuilder filter = FilterBuilders.rangeFilter("price").gte(1.99).lte(2.3)
def result = elasticSearchService.search(
    [indices: Building, types: Building, sort: sortBuilder],
    null as Closure,
    filter)

5.6 Highlighting

The search method support highlighting: automatic wrapping of the matching terms in the search results with HTML/XML/Whatever tags. You can activate this with a Closure containing the highlight settings in the search method highlight parameter. The format of the Closure for defining the highlight settings is the same as the ElasticSearch REST API.

Example

// Define the pre & post tag that will wrap each term matched in the document.
def highlighter = {
  field 'message'
  field 'tags.name'
  preTags '<strong>'
  postTags '</strong>'
}

def results = Tweet.search("${params.query}", [highlight: highlightSettings])

Highlight results

If a search result is found, the search method will add a highlight entry in the map result. That entry contains a List with every highlighted fragments/fields found for each hit.

def results = Tweet.search("${params.query}", [highlight: { field 'message' }])
def highlighted = results.highlight

results?.searchResults?.eachWithIndex { hit, index -> // Retrieve the 'message' field fragments for the current hits def fragments = highlighted[index].message?.fragments

// Print the fragment println fragments?.size() ? fragments[0] : '' }

Highlighted fields

To determine which fields are to be processed by ElasticSearch, use the field setting. You can call the field setting as many time as you want to add any field.

Signature

field <fieldName>[, <fragmentSize>[, <numberOfFragment>]]

Examples

def highlightSettings = {
    field 'message'                    // Add the 'message' field in the highlighted fields list
    field 'tags.name'                  // Add the 'name' field contained in the 'tags' field of
                                       // the document in the highlighted fields list
    field 'thatAwesomeField', 0, 20    // Add the 'thatAwesomeField' field with
                                       // some values fixed for fragmentSize and numberOfFragment parameters
}

def highlightSettings2 = { field '_all' // Add the special '_all' field in the highlighted fields list }

def results = Tweet.search("${params.query}", [highlight: highlightSettings]) def results2 = Tweet.search("${params.query}", [highlight: highlightSettings2])

Highlighting tags

By default, ElasticSearch will use emphasis tag "<em>...</em>" to wrap the matching text. You can customize the tags with the preTags and postTags settings.

def highlightSettings = {
    field 'message'
    preTags '<myAweSomeTag>'
    postTags '</myAweSomeTag>'
}

5.7 Sorting

To sort the search results, either a field name or a SortBuilder must be passed.

Returned sort values

The sort values are not part of the search results themselves but are part of result.sort. sort contains all search values calculated by the ElasticSearch server as a list mapped to the id of the respective domain objects

Example

assert [1:[23, 42], 2: [24, 40]] == result.sort

5.7.1 geoDistanceSorting

To sort for geo distances, a SortBuilder must be passed to search()

Example

def sortBuilder = SortBuilders.geoDistanceSort("location")
    .point(48.141, 11.57)
    .unit(DistanceUnit.KILOMETERS)
    .order(SortOrder.ASC)

def result = elasticSearchService.search( [indices: Building, types: Building, sort: sortBuilder], null as Closure, { geo_distance( 'distance': '5km', 'location': [lat: 48.141, lon: 11.57] ) })

The calculated distances are not part of the search results themselves but are part of result.sort. sort contains all search values calculated by the ElasticSearch server as a list mapped to the id of the respective domain objects

assert [1:[2.34567], 2: [2.4402342]] == result.sort