PageRenderTime 31ms CodeModel.GetById 2ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/scala/scalastic/elasticsearch/Searching.scala

Relevant Search: With Applications for Solr and Elasticsearch

For more in depth reading about search, ranking and generally everything you could ever want to know about how lucene, elasticsearch or solr work under the hood I highly suggest this book. Easily one of the most interesting technical books I have read in a long time. If you are tasked with solving search relevance problems even if not in Solr or Elasticsearch it should be your first reference. Amazon Affiliate Link
https://github.com/pmanvi/scalastic
Scala | 441 lines | 397 code | 34 blank | 10 comment | 8 complexity | 1cd055456fff28bafdb6f100f504ab4c MD5 | raw file
  1package scalastic.elasticsearch
  2
  3import org.elasticsearch.action.search._
  4import org.elasticsearch.action.support.broadcast._
  5import org.elasticsearch.index.query._, QueryBuilders._
  6import org.elasticsearch.search._, facet._, sort._, SortBuilders._, builder._
  7import scala.collection._, JavaConversions._
  8import org.elasticsearch.common.geo.{GeoPoint, GeoDistance}
  9
 10trait Searching 
 11	extends Query 
 12	with Search 
 13	with SearchScroll 
 14    with MoreLikeThis
 15	with Multisearch 
 16	with Percolate 
 17	with ValidateQuery {
 18  self: Indexer =>
 19}
 20
 21trait Query {
 22  self: Indexer =>
 23  def query(queryString: String) = query_send(queryString).actionGet
 24  def query_send(queryString: String) = query_prepare(queryString).execute
 25  def query_prepare(queryString: String) = client.prepareSearch().setQuery(queryString)
 26}
 27
 28object SearchParameterTypes {
 29  import org.elasticsearch.common.unit._
 30
 31  case class ScriptField(name: String, script: String, parameters: Map[String, Object] = Map(), lang: Option[String] = None)
 32
 33  case class PartialField(name: String, includes: Iterable[String], excludes: Iterable[String]) {
 34    def this(name: String, include: Option[String], exclude: Option[String]) = this(name, include.toIterable, exclude.toIterable)
 35  }
 36
 37  sealed abstract class Sorting(order: SortOrder) {
 38    def newBuilder: SortBuilder
 39    def toBuilder = newBuilder.order(order)
 40  }
 41  case class FieldSort(field: String, ignoreUnmapped: Option[Boolean] = None, missing: Option[Any] = None, order: SortOrder = SortOrder.ASC) extends Sorting(order) {
 42    def newBuilder = {
 43      val builder = fieldSort(field)
 44      ignoreUnmapped.foreach { builder.ignoreUnmapped(_) }
 45      missing.foreach { builder.missing(_) }
 46      builder
 47    }
 48  }
 49  case class ScoreSort(order: SortOrder = SortOrder.ASC) extends Sorting(order) {
 50    def newBuilder = scoreSort
 51  }
 52  case class ScriptSort(script: String, `type`: String, lang: Option[String] = None, parameters: Map[String, Object] = Map(), order: SortOrder = SortOrder.ASC) extends Sorting(order) {
 53    def newBuilder = {
 54      val builder = scriptSort(script, `type`)
 55      lang foreach { builder.lang(_) }
 56      parameters foreach { case (key, value) => builder.param(key, value) }
 57      builder
 58    }
 59  }
 60  case class GeoDistanceSort(field: String, geoDistance: Option[GeoDistance] = None, geohash: Option[String] = None, geoPoint: Option[GeoPoint] = None, unit: Option[DistanceUnit] = None, order: SortOrder = SortOrder.ASC) extends Sorting(order) {
 61    def newBuilder = {
 62      val builder = geoDistanceSort(field)
 63      geoDistance foreach { builder.geoDistance(_) }
 64      geohash foreach { builder.geohash(_) }
 65      geoPoint foreach { each => builder.point(each.lat, each.lon) }
 66      unit foreach { builder.unit(_) }
 67      builder
 68    }
 69  }
 70
 71  case class HighlightField(
 72    name: String,
 73    fragmentSize: Int = -1,
 74    fragmentOffset: Int = -1,
 75    numOfFragments: Int = -1,
 76    requireFieldMatch: Option[Boolean] = None // currently ignored in the Java API
 77  )
 78
 79  case class Highlight(
 80      fields: Iterable[HighlightField] = Nil,
 81      order: Option[String] = None,
 82      requireFieldMatch: Option[Boolean] = None,
 83      encoder: Option[String] = None,
 84      preTags: Iterable[String] = Nil,
 85      postTags: Iterable[String] = Nil,
 86      tagsSchema: Option[String] = None) {
 87
 88    def setIn(request: SearchRequestBuilder) {
 89      fields foreach { f =>
 90        f match {
 91          case HighlightField(name, -1, -1, -1, None) => request.addHighlightedField(name)
 92          case HighlightField(name, fs, -1, -1, None) => request.addHighlightedField(name, fs)
 93          case HighlightField(name, fs, fo, -1, None) => request.addHighlightedField(name, fs, fo)
 94          case HighlightField(name, fs, fo, nf, None) => request.addHighlightedField(name, fs, fo, nf)
 95          case HighlightField(name, fs, fo, nf, Some(r)) => request.addHighlightedField(name, fs, fo, nf)
 96        }
 97      }
 98      order foreach { request.setHighlighterOrder(_) }
 99      requireFieldMatch foreach { request.setHighlighterRequireFieldMatch(_) }
100      encoder foreach { request.setHighlighterEncoder(_) }
101      if (!preTags.isEmpty) request.setHighlighterPreTags(preTags.toArray: _*)
102      if (!postTags.isEmpty) request.setHighlighterPostTags(postTags.toArray: _*)
103      tagsSchema foreach { request.setHighlighterTagsSchema(_) }
104    }
105  }
106}
107
108trait SearchScroll {
109	self: Indexer =>
110	  
111  def searchScroll(
112    scrollId: String,
113    listenerThreaded: Option[Boolean] = None,
114    operationThreading: Option[SearchOperationThreading] = None,
115    scroll: Option[String] = None) = searchScroll_send(scrollId, listenerThreaded, operationThreading, scroll).actionGet
116    
117  def searchScroll_send(
118    scrollId: String,
119    listenerThreaded: Option[Boolean] = None,
120    operationThreading: Option[SearchOperationThreading] = None,
121    scroll: Option[String] = None) = searchScroll_prepare(scrollId, listenerThreaded, operationThreading, scroll).execute
122    
123  def searchScroll_prepare(
124    scrollId: String,
125    listenerThreaded: Option[Boolean] = None,
126    operationThreading: Option[SearchOperationThreading] = None,
127    scroll: Option[String] = None) = {
128		  /* method body */
129    val request = client.prepareSearchScroll(scrollId)
130    listenerThreaded foreach { request.listenerThreaded(_) }
131    operationThreading foreach { request.setOperationThreading(_) }
132    scroll foreach { request.setScroll(_) }
133    request
134  }
135}
136
137trait Search {
138  self: Indexer =>
139
140  import SearchParameterTypes._
141
142  def search(
143    indices: Iterable[String] = Nil,
144    types: Iterable[String] = Nil,
145    query: QueryBuilder = matchAllQuery,
146    /* the rest ... */
147    explain: Option[Boolean] = None,
148    extraSource: Option[Map[String, Object]] = None,
149    facets: Iterable[FacetBuilder] = Nil,
150    fields: Iterable[String] = Nil,
151    filter: Option[FilterBuilder] = None,
152    from: Option[Int] = None,
153    highlight: Highlight = Highlight(),
154    indexBoosts: Map[String, Float] = Map(),
155    internalBuilder: Option[SearchSourceBuilder] = None,
156    minScore: Option[Float] = None,
157    operationThreading: Option[SearchOperationThreading] = None,
158    partialFields: Iterable[PartialField] = Nil,
159    preference: Option[String] = None,
160    queryHint: Option[String] = None,
161    routing: Option[String] = None,
162    scriptFields: Iterable[ScriptField] = Nil,
163    scroll: Option[String] = None,
164    searchType: Option[SearchType] = None,
165    size: Option[Int] = None,
166    sortings: Iterable[Sorting] = Nil,
167    source: Option[String] = None,
168    statsGroups: Iterable[String] = Nil,
169    timeout: Option[String] = None,
170    trackScores: Option[Boolean] = None) = search_send(indices, types, query, explain, extraSource, facets, fields, filter, from, highlight, indexBoosts, internalBuilder, minScore, operationThreading, partialFields, preference, queryHint, routing, scriptFields, scroll, searchType, size, sortings, source, statsGroups, timeout, trackScores).actionGet
171
172  def search_send(
173    indices: Iterable[String] = Nil,
174    types: Iterable[String] = Nil,
175    query: QueryBuilder = matchAllQuery,
176    /* the rest ... */
177    explain: Option[Boolean] = None,
178    extraSource: Option[Map[String, Object]] = None,
179    facets: Iterable[FacetBuilder] = Nil,
180    fields: Iterable[String] = Nil,
181    filter: Option[FilterBuilder] = None,
182    from: Option[Int] = None,
183    highlight: Highlight = Highlight(),
184    indexBoosts: Map[String, Float] = Map(),
185    internalBuilder: Option[SearchSourceBuilder] = None,
186    minScore: Option[Float] = None,
187    operationThreading: Option[SearchOperationThreading] = None,
188    partialFields: Iterable[PartialField] = Nil,
189    preference: Option[String] = None,
190    queryHint: Option[String] = None,
191    routing: Option[String] = None,
192    scriptFields: Iterable[ScriptField] = Nil,
193    scroll: Option[String] = None,
194    searchType: Option[SearchType] = None,
195    size: Option[Int] = None,
196    sortings: Iterable[Sorting] = Nil,
197    source: Option[String] = None,
198    statsGroups: Iterable[String] = Nil,
199    timeout: Option[String] = None,
200    trackScores: Option[Boolean] = None) = search_prepare(indices, types, query, explain, extraSource, facets, fields, filter, from, highlight, indexBoosts, internalBuilder, minScore, operationThreading, partialFields, preference, routing, scriptFields, scroll, searchType, size, sortings, source, statsGroups, timeout, trackScores).execute
201
202  def search_prepare(
203    indices: Iterable[String] = Nil,
204    types: Iterable[String] = Nil,
205    query: QueryBuilder = matchAllQuery,
206    /* the rest ... */
207    explain: Option[Boolean] = None,
208    extraSource: Option[Map[String, Object]] = None,
209    facets: Iterable[FacetBuilder] = Nil,
210    fields: Iterable[String] = Nil,
211    filter: Option[FilterBuilder] = None,
212    from: Option[Int] = None,
213    highlight: Highlight = Highlight(),
214    indexBoosts: Map[String, Float] = Map(),
215    internalBuilder: Option[SearchSourceBuilder] = None,
216    minScore: Option[Float] = None,
217    operationThreading: Option[SearchOperationThreading] = None,
218    partialFields: Iterable[PartialField] = Nil,
219    preference: Option[String] = None,
220    routing: Option[String] = None,
221    scriptFields: Iterable[ScriptField] = Nil,
222    scroll: Option[String] = None,
223    searchType: Option[SearchType] = None,
224    size: Option[Int] = None,
225    sortings: Iterable[Sorting] = Nil,
226    source: Option[String] = None,
227    statsGroups: Iterable[String] = Nil,
228    timeout: Option[String] = None,
229    trackScores: Option[Boolean] = None) = {
230		  /* method body */
231    // ... essentials
232    val request = client.prepareSearch(indices.toArray: _*)
233    request.setTypes(types.toArray: _*)
234    request.setQuery(query)
235    // ... and the rest
236    explain foreach { request.setExplain(_) }
237    extraSource foreach { request.setExtraSource(_) }
238    facets foreach { request.addFacet(_) }
239    fields foreach { request.addField(_) }
240    filter foreach { request.setFilter(_) }
241    from foreach { request.setFrom(_) }
242    highlight.setIn(request)
243    indexBoosts foreach { case (key, value) => request.addIndexBoost(key, value) }
244    internalBuilder foreach { request.internalBuilder(_) }
245    minScore foreach { request.setMinScore(_) }
246    operationThreading foreach { request.setOperationThreading(_) }
247    partialFields foreach { each => request.addPartialField(each.name, each.includes.toArray, each.excludes.toArray) }
248    preference foreach { request.setPreference(_) }
249    routing foreach { request.setRouting(_) }
250    scriptFields foreach { each => request.addScriptField(each.name, each.lang getOrElse (null), each.script, each.parameters) }
251    scroll foreach { request.setScroll(_) }
252    searchType foreach { request.setSearchType(_) }
253    size foreach { request.setSize(_) }
254    sortings foreach { each => request.addSort(each.toBuilder) }
255    source foreach { request.setSource(_) }
256    if (!statsGroups.isEmpty) request.setStats(statsGroups.toArray: _*)
257    timeout foreach { request.setTimeout(_) }
258    trackScores foreach { request.setTrackScores(_) }
259    request
260  }
261}
262
263trait Multisearch {
264  self: Indexer =>
265
266  def multisearch(requests: Iterable[SearchRequestBuilder] = Seq(search_prepare())) = multisearch_send(requests = requests).actionGet
267  def multisearch_send(requests: Iterable[SearchRequestBuilder] = Seq(search_prepare())) = multisearch_prepare(requests = requests).execute
268  def multisearch_prepare(requests: Iterable[SearchRequestBuilder] = Seq(search_prepare())) = {
269    val request = client.prepareMultiSearch
270    for (each <- requests) request.add(each)
271    request
272  }
273
274  def multisearchByQuery(queries: Iterable[QueryBuilder] = Seq(matchAllQuery)) = multisearchByQuery_send(queries = queries).actionGet
275  def multisearchByQuery_send(queries: Iterable[QueryBuilder] = Seq(matchAllQuery)) = multisearchByQuery_prepare(queries = queries).execute
276  def multisearchByQuery_prepare(queries: Iterable[QueryBuilder] = Seq(matchAllQuery)) = multisearch_prepare(queries map (each => search_prepare(query = each)))
277}
278
279trait MoreLikeThis {
280  self: Indexer =>
281    
282  def moreLikeThis(
283    index: String,
284    `type`: String,
285    id: String,
286    boostTerms: Option[Float] = None,
287    fields: Iterable[String] = Nil,
288    maxDocFreq: Option[Int] = None,
289    maxQueryTerms: Option[Int] = None,
290    maxWordLen: Option[Int] = None,
291    minDocFreq: Option[Int] = None,
292    minTermFreq: Option[Int] = None,
293    minWordLen: Option[Int] = None,
294    percentTermsToMatch: Option[Float] = None,
295    from: Option[Int] = None,
296    searchIndices: Iterable[String] = Nil,
297    searchScroll: Option[Scroll] = None,
298    searchSize: Option[Int] = None,
299    searchSource: Option[Map[String, Object]] = None,
300    searchType: Option[SearchType] = None,
301    searchTypes: Iterable[String] = Nil,
302    stopwords: Iterable[String] = Nil) = moreLikeThis_send(index, `type`, id, boostTerms, fields, maxDocFreq, maxQueryTerms, maxWordLen, minDocFreq, minTermFreq, minWordLen, percentTermsToMatch, from, searchIndices, searchScroll, searchSize, searchSource, searchType, searchTypes, stopwords).actionGet
303  
304  def moreLikeThis_send(
305    index: String,
306    `type`: String,
307    id: String,
308    boostTerms: Option[Float] = None,
309    fields: Iterable[String] = Nil,
310    maxDocFreq: Option[Int] = None,
311    maxQueryTerms: Option[Int] = None,
312    maxWordLen: Option[Int] = None,
313    minDocFreq: Option[Int] = None,
314    minTermFreq: Option[Int] = None,
315    minWordLen: Option[Int] = None,
316    percentTermsToMatch: Option[Float] = None,
317    from: Option[Int] = None,
318    searchIndices: Iterable[String] = Nil,
319    searchScroll: Option[Scroll] = None,
320    searchSize: Option[Int] = None,
321    searchSource: Option[Map[String, Object]] = None,
322    searchType: Option[SearchType] = None,
323    searchTypes: Iterable[String] = Nil,
324    stopwords: Iterable[String] = Nil) = moreLikeThis_prepare(index, `type`, id, boostTerms, fields, maxDocFreq, maxQueryTerms, maxWordLen, minDocFreq, minTermFreq, minWordLen, percentTermsToMatch, from, searchIndices, searchScroll, searchSize, searchSource, searchType, searchTypes, stopwords).execute
325  
326  def moreLikeThis_prepare(
327    index: String,
328    `type`: String,
329    id: String,
330    boostTerms: Option[Float] = None,
331    fields: Iterable[String] = Nil,
332    maxDocFreq: Option[Int] = None,
333    maxQueryTerms: Option[Int] = None,
334    maxWordLen: Option[Int] = None,
335    minDocFreq: Option[Int] = None,
336    minTermFreq: Option[Int] = None,
337    minWordLen: Option[Int] = None,
338    percentTermsToMatch: Option[Float] = None,
339    from: Option[Int] = None,
340    searchIndices: Iterable[String] = Nil,
341    searchScroll: Option[Scroll] = None,
342    searchSize: Option[Int] = None,
343    searchSource: Option[Map[String, Object]] = None,
344    searchType: Option[SearchType] = None,
345    searchTypes: Iterable[String] = Nil,
346    stopwords: Iterable[String] = Nil) = {
347		  /* method body */
348    val request = client.prepareMoreLikeThis(index, `type`, id)
349    boostTerms foreach { request.setBoostTerms(_) }
350    if (!fields.isEmpty) request.setField(fields.toArray: _*)
351    maxDocFreq foreach { request.setMaxDocFreq(_) }
352    maxQueryTerms foreach { request.maxQueryTerms(_) }
353    maxWordLen foreach { request.setMaxWordLen(_) }
354    minDocFreq foreach { request.setMinDocFreq(_) }
355    minTermFreq foreach { request.setMinTermFreq(_) }
356    minWordLen foreach { request.setMinWordLen(_) }
357    percentTermsToMatch foreach { request.setPercentTermsToMatch(_) }
358    from foreach { request.setSearchFrom(_) }
359    if (!searchIndices.isEmpty) request.setSearchIndices(searchIndices.toArray: _*)
360    searchScroll foreach { request.setSearchScroll(_) }
361    searchSize foreach { request.setSearchSize(_) }
362    searchSource foreach { request.setSearchSource(_) }
363    searchType foreach { request.setSearchType(_) }
364    if (!searchTypes.isEmpty) request.setSearchTypes(searchTypes.toArray: _*)
365    if (!stopwords.isEmpty) request.setStopWords(stopwords.toArray: _*)
366    request
367  }
368}
369
370trait Percolate {
371  self: Indexer =>
372
373  def percolate(
374    index: String,
375    `type`: String,
376    listenerThreaded: Option[Boolean] = None,
377    operationThreaded: Option[Boolean] = None,
378    preferLocal: Option[Boolean] = None,
379    source: Option[String] = None) = percolate_send(index, `type`, listenerThreaded, operationThreaded, preferLocal, source).actionGet
380
381  def percolate_send(
382    index: String,
383    `type`: String,
384    listenerThreaded: Option[Boolean] = None,
385    operationThreaded: Option[Boolean] = None,
386    preferLocal: Option[Boolean] = None,
387    source: Option[String] = None) = percolate_prepare(index, `type`, listenerThreaded, operationThreaded, preferLocal, source).execute
388
389  def percolate_prepare(
390    index: String,
391    `type`: String,
392    listenerThreaded: Option[Boolean] = None,
393    operationThreaded: Option[Boolean] = None,
394    preferLocal: Option[Boolean] = None,
395    source: Option[String] = None) = {
396		  /* method body */
397    val request = client.preparePercolate(index, `type`)
398    listenerThreaded foreach { request.setListenerThreaded(_) }
399    operationThreaded foreach { request.setOperationThreaded(_) }
400    preferLocal foreach { request.setPreferLocal(_) }
401    source foreach { request.setSource(_) }
402    request
403  }
404}
405
406trait ValidateQuery {
407  self: Indexer =>
408
409  def validateQuery(
410    indices: Iterable[String] = Nil,
411    types: Iterable[String] = Nil,
412    query: QueryBuilder = matchAllQuery,
413    explain: Option[Boolean] = None,
414    listenerThreaded: Option[Boolean] = None,
415    operationThreading: Option[BroadcastOperationThreading] = None) = validateQuery_send(indices, types, query, explain, listenerThreaded, operationThreading).actionGet
416
417  def validateQuery_send(
418    indices: Iterable[String] = Nil,
419    types: Iterable[String] = Nil,
420    query: QueryBuilder = matchAllQuery,
421    explain: Option[Boolean] = None,
422    listenerThreaded: Option[Boolean] = None,
423    operationThreading: Option[BroadcastOperationThreading] = None) = validateQuery_prepare(indices, types, query, explain, listenerThreaded, operationThreading).execute
424
425  def validateQuery_prepare(
426    indices: Iterable[String] = Nil,
427    types: Iterable[String] = Nil,
428    query: QueryBuilder = matchAllQuery,
429    explain: Option[Boolean] = None,
430    listenerThreaded: Option[Boolean] = None,
431    operationThreading: Option[BroadcastOperationThreading] = None) = {
432		  /* method body */
433    val request = client.admin.indices.prepareValidateQuery(indices.toArray: _*)
434    request.setTypes(types.toArray: _*)
435    request.setQuery(query)
436    explain foreach { request.setExplain(_) }
437    listenerThreaded foreach { request.setListenerThreaded(_) }
438    operationThreading foreach { request.setOperationThreading(_) }
439    request
440  }
441}