sort.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. // Copyright 2012-2015 Oliver Eilhard. All rights reserved.
  2. // Use of this source code is governed by a MIT-license.
  3. // See http://olivere.mit-license.org/license.txt for details.
  4. package elastic
  5. // -- Sorter --
  6. // Sorter is an interface for sorting strategies, e.g. ScoreSort or FieldSort.
  7. // See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html.
  8. type Sorter interface {
  9. Source() interface{}
  10. }
  11. // -- SortInfo --
  12. // SortInfo contains information about sorting a field.
  13. type SortInfo struct {
  14. Sorter
  15. Field string
  16. Ascending bool
  17. Missing interface{}
  18. IgnoreUnmapped *bool
  19. SortMode string
  20. NestedFilter Filter
  21. NestedPath string
  22. }
  23. func (info SortInfo) Source() interface{} {
  24. prop := make(map[string]interface{})
  25. if info.Ascending {
  26. prop["order"] = "asc"
  27. } else {
  28. prop["order"] = "desc"
  29. }
  30. if info.Missing != nil {
  31. prop["missing"] = info.Missing
  32. }
  33. if info.IgnoreUnmapped != nil {
  34. prop["ignore_unmapped"] = *info.IgnoreUnmapped
  35. }
  36. if info.SortMode != "" {
  37. prop["sort_mode"] = info.SortMode
  38. }
  39. if info.NestedFilter != nil {
  40. prop["nested_filter"] = info.NestedFilter
  41. }
  42. if info.NestedPath != "" {
  43. prop["nested_path"] = info.NestedPath
  44. }
  45. source := make(map[string]interface{})
  46. source[info.Field] = prop
  47. return source
  48. }
  49. // -- ScoreSort --
  50. // ScoreSort sorts by relevancy score.
  51. type ScoreSort struct {
  52. Sorter
  53. ascending bool
  54. }
  55. // NewScoreSort creates a new ScoreSort.
  56. func NewScoreSort() ScoreSort {
  57. return ScoreSort{ascending: false} // Descending by default!
  58. }
  59. // Order defines whether sorting ascending (default) or descending.
  60. func (s ScoreSort) Order(ascending bool) ScoreSort {
  61. s.ascending = ascending
  62. return s
  63. }
  64. // Asc sets ascending sort order.
  65. func (s ScoreSort) Asc() ScoreSort {
  66. s.ascending = true
  67. return s
  68. }
  69. // Desc sets descending sort order.
  70. func (s ScoreSort) Desc() ScoreSort {
  71. s.ascending = false
  72. return s
  73. }
  74. // Source returns the JSON-serializable data.
  75. func (s ScoreSort) Source() interface{} {
  76. source := make(map[string]interface{})
  77. x := make(map[string]interface{})
  78. source["_score"] = x
  79. if s.ascending {
  80. x["reverse"] = true
  81. }
  82. return source
  83. }
  84. // -- FieldSort --
  85. // FieldSort sorts by a given field.
  86. type FieldSort struct {
  87. Sorter
  88. fieldName string
  89. ascending bool
  90. missing interface{}
  91. ignoreUnmapped *bool
  92. unmappedType *string
  93. sortMode *string
  94. nestedFilter Filter
  95. nestedPath *string
  96. }
  97. // NewFieldSort creates a new FieldSort.
  98. func NewFieldSort(fieldName string) FieldSort {
  99. return FieldSort{
  100. fieldName: fieldName,
  101. ascending: true,
  102. }
  103. }
  104. // FieldName specifies the name of the field to be used for sorting.
  105. func (s FieldSort) FieldName(fieldName string) FieldSort {
  106. s.fieldName = fieldName
  107. return s
  108. }
  109. // Order defines whether sorting ascending (default) or descending.
  110. func (s FieldSort) Order(ascending bool) FieldSort {
  111. s.ascending = ascending
  112. return s
  113. }
  114. // Asc sets ascending sort order.
  115. func (s FieldSort) Asc() FieldSort {
  116. s.ascending = true
  117. return s
  118. }
  119. // Desc sets descending sort order.
  120. func (s FieldSort) Desc() FieldSort {
  121. s.ascending = false
  122. return s
  123. }
  124. // Missing sets the value to be used when a field is missing in a document.
  125. // You can also use "_last" or "_first" to sort missing last or first
  126. // respectively.
  127. func (s FieldSort) Missing(missing interface{}) FieldSort {
  128. s.missing = missing
  129. return s
  130. }
  131. // IgnoreUnmapped specifies what happens if the field does not exist in
  132. // the index. Set it to true to ignore, or set it to false to not ignore (default).
  133. func (s FieldSort) IgnoreUnmapped(ignoreUnmapped bool) FieldSort {
  134. s.ignoreUnmapped = &ignoreUnmapped
  135. return s
  136. }
  137. // UnmappedType sets the type to use when the current field is not mapped
  138. // in an index.
  139. func (s FieldSort) UnmappedType(typ string) FieldSort {
  140. s.unmappedType = &typ
  141. return s
  142. }
  143. // SortMode specifies what values to pick in case a document contains
  144. // multiple values for the targeted sort field. Possible values are:
  145. // min, max, sum, and avg.
  146. func (s FieldSort) SortMode(sortMode string) FieldSort {
  147. s.sortMode = &sortMode
  148. return s
  149. }
  150. // NestedFilter sets a filter that nested objects should match with
  151. // in order to be taken into account for sorting.
  152. func (s FieldSort) NestedFilter(nestedFilter Filter) FieldSort {
  153. s.nestedFilter = nestedFilter
  154. return s
  155. }
  156. // NestedPath is used if sorting occurs on a field that is inside a
  157. // nested object.
  158. func (s FieldSort) NestedPath(nestedPath string) FieldSort {
  159. s.nestedPath = &nestedPath
  160. return s
  161. }
  162. // Source returns the JSON-serializable data.
  163. func (s FieldSort) Source() interface{} {
  164. source := make(map[string]interface{})
  165. x := make(map[string]interface{})
  166. source[s.fieldName] = x
  167. if s.ascending {
  168. x["order"] = "asc"
  169. } else {
  170. x["order"] = "desc"
  171. }
  172. if s.missing != nil {
  173. x["missing"] = s.missing
  174. }
  175. if s.ignoreUnmapped != nil {
  176. x["ignore_unmapped"] = *s.ignoreUnmapped
  177. }
  178. if s.unmappedType != nil {
  179. x["unmapped_type"] = *s.unmappedType
  180. }
  181. if s.sortMode != nil {
  182. x["mode"] = *s.sortMode
  183. }
  184. if s.nestedFilter != nil {
  185. x["nested_filter"] = s.nestedFilter.Source()
  186. }
  187. if s.nestedPath != nil {
  188. x["nested_path"] = *s.nestedPath
  189. }
  190. return source
  191. }
  192. // -- GeoDistanceSort --
  193. // GeoDistanceSort allows for sorting by geographic distance.
  194. // See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_geo_distance_sorting.
  195. type GeoDistanceSort struct {
  196. Sorter
  197. fieldName string
  198. points []*GeoPoint
  199. geohashes []string
  200. geoDistance *string
  201. unit string
  202. ascending bool
  203. sortMode *string
  204. nestedFilter Filter
  205. nestedPath *string
  206. }
  207. // NewGeoDistanceSort creates a new sorter for geo distances.
  208. func NewGeoDistanceSort(fieldName string) GeoDistanceSort {
  209. return GeoDistanceSort{
  210. fieldName: fieldName,
  211. points: make([]*GeoPoint, 0),
  212. geohashes: make([]string, 0),
  213. ascending: true,
  214. }
  215. }
  216. // FieldName specifies the name of the (geo) field to use for sorting.
  217. func (s GeoDistanceSort) FieldName(fieldName string) GeoDistanceSort {
  218. s.fieldName = fieldName
  219. return s
  220. }
  221. // Order defines whether sorting ascending (default) or descending.
  222. func (s GeoDistanceSort) Order(ascending bool) GeoDistanceSort {
  223. s.ascending = ascending
  224. return s
  225. }
  226. // Asc sets ascending sort order.
  227. func (s GeoDistanceSort) Asc() GeoDistanceSort {
  228. s.ascending = true
  229. return s
  230. }
  231. // Desc sets descending sort order.
  232. func (s GeoDistanceSort) Desc() GeoDistanceSort {
  233. s.ascending = false
  234. return s
  235. }
  236. // Point specifies a point to create the range distance facets from.
  237. func (s GeoDistanceSort) Point(lat, lon float64) GeoDistanceSort {
  238. s.points = append(s.points, GeoPointFromLatLon(lat, lon))
  239. return s
  240. }
  241. // Points specifies the geo point(s) to create the range distance facets from.
  242. func (s GeoDistanceSort) Points(points ...*GeoPoint) GeoDistanceSort {
  243. s.points = append(s.points, points...)
  244. return s
  245. }
  246. // GeoHashes specifies the geo point to create the range distance facets from.
  247. func (s GeoDistanceSort) GeoHashes(geohashes ...string) GeoDistanceSort {
  248. s.geohashes = append(s.geohashes, geohashes...)
  249. return s
  250. }
  251. // GeoDistance represents how to compute the distance.
  252. // It can be sloppy_arc (default), arc, or plane.
  253. // See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_geo_distance_sorting.
  254. func (s GeoDistanceSort) GeoDistance(geoDistance string) GeoDistanceSort {
  255. s.geoDistance = &geoDistance
  256. return s
  257. }
  258. // Unit specifies the distance unit to use. It defaults to km.
  259. // See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#distance-units
  260. // for details.
  261. func (s GeoDistanceSort) Unit(unit string) GeoDistanceSort {
  262. s.unit = unit
  263. return s
  264. }
  265. // SortMode specifies what values to pick in case a document contains
  266. // multiple values for the targeted sort field. Possible values are:
  267. // min, max, sum, and avg.
  268. func (s GeoDistanceSort) SortMode(sortMode string) GeoDistanceSort {
  269. s.sortMode = &sortMode
  270. return s
  271. }
  272. // NestedFilter sets a filter that nested objects should match with
  273. // in order to be taken into account for sorting.
  274. func (s GeoDistanceSort) NestedFilter(nestedFilter Filter) GeoDistanceSort {
  275. s.nestedFilter = nestedFilter
  276. return s
  277. }
  278. // NestedPath is used if sorting occurs on a field that is inside a
  279. // nested object.
  280. func (s GeoDistanceSort) NestedPath(nestedPath string) GeoDistanceSort {
  281. s.nestedPath = &nestedPath
  282. return s
  283. }
  284. // Source returns the JSON-serializable data.
  285. func (s GeoDistanceSort) Source() interface{} {
  286. source := make(map[string]interface{})
  287. x := make(map[string]interface{})
  288. source["_geo_distance"] = x
  289. // Points
  290. ptarr := make([]interface{}, 0)
  291. for _, pt := range s.points {
  292. ptarr = append(ptarr, pt.Source())
  293. }
  294. for _, geohash := range s.geohashes {
  295. ptarr = append(ptarr, geohash)
  296. }
  297. x[s.fieldName] = ptarr
  298. if s.unit != "" {
  299. x["unit"] = s.unit
  300. }
  301. if s.geoDistance != nil {
  302. x["distance_type"] = *s.geoDistance
  303. }
  304. if !s.ascending {
  305. x["reverse"] = true
  306. }
  307. if s.sortMode != nil {
  308. x["mode"] = *s.sortMode
  309. }
  310. if s.nestedFilter != nil {
  311. x["nested_filter"] = s.nestedFilter.Source()
  312. }
  313. if s.nestedPath != nil {
  314. x["nested_path"] = *s.nestedPath
  315. }
  316. return source
  317. }
  318. // -- ScriptSort --
  319. // ScriptSort sorts by a custom script. See
  320. // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-scripting.html#modules-scripting
  321. // for details about scripting.
  322. type ScriptSort struct {
  323. Sorter
  324. lang string
  325. script string
  326. typ string
  327. params map[string]interface{}
  328. ascending bool
  329. sortMode *string
  330. nestedFilter Filter
  331. nestedPath *string
  332. }
  333. // NewScriptSort creates a new ScriptSort.
  334. func NewScriptSort(script, typ string) ScriptSort {
  335. return ScriptSort{
  336. script: script,
  337. typ: typ,
  338. ascending: true,
  339. params: make(map[string]interface{}),
  340. }
  341. }
  342. // Lang specifies the script language to use. It can be one of:
  343. // groovy (the default for ES >= 1.4), mvel (default for ES < 1.4),
  344. // js, python, expression, or native. See
  345. // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-scripting.html#modules-scripting
  346. // for details.
  347. func (s ScriptSort) Lang(lang string) ScriptSort {
  348. s.lang = lang
  349. return s
  350. }
  351. // Type sets the script type, which can be either string or number.
  352. func (s ScriptSort) Type(typ string) ScriptSort {
  353. s.typ = typ
  354. return s
  355. }
  356. // Param adds a parameter to the script.
  357. func (s ScriptSort) Param(name string, value interface{}) ScriptSort {
  358. s.params[name] = value
  359. return s
  360. }
  361. // Params sets the parameters of the script.
  362. func (s ScriptSort) Params(params map[string]interface{}) ScriptSort {
  363. s.params = params
  364. return s
  365. }
  366. // Order defines whether sorting ascending (default) or descending.
  367. func (s ScriptSort) Order(ascending bool) ScriptSort {
  368. s.ascending = ascending
  369. return s
  370. }
  371. // Asc sets ascending sort order.
  372. func (s ScriptSort) Asc() ScriptSort {
  373. s.ascending = true
  374. return s
  375. }
  376. // Desc sets descending sort order.
  377. func (s ScriptSort) Desc() ScriptSort {
  378. s.ascending = false
  379. return s
  380. }
  381. // SortMode specifies what values to pick in case a document contains
  382. // multiple values for the targeted sort field. Possible values are:
  383. // min or max.
  384. func (s ScriptSort) SortMode(sortMode string) ScriptSort {
  385. s.sortMode = &sortMode
  386. return s
  387. }
  388. // NestedFilter sets a filter that nested objects should match with
  389. // in order to be taken into account for sorting.
  390. func (s ScriptSort) NestedFilter(nestedFilter Filter) ScriptSort {
  391. s.nestedFilter = nestedFilter
  392. return s
  393. }
  394. // NestedPath is used if sorting occurs on a field that is inside a
  395. // nested object.
  396. func (s ScriptSort) NestedPath(nestedPath string) ScriptSort {
  397. s.nestedPath = &nestedPath
  398. return s
  399. }
  400. // Source returns the JSON-serializable data.
  401. func (s ScriptSort) Source() interface{} {
  402. source := make(map[string]interface{})
  403. x := make(map[string]interface{})
  404. source["_script"] = x
  405. x["script"] = s.script
  406. x["type"] = s.typ
  407. if !s.ascending {
  408. x["reverse"] = true
  409. }
  410. if s.lang != "" {
  411. x["lang"] = s.lang
  412. }
  413. if len(s.params) > 0 {
  414. x["params"] = s.params
  415. }
  416. if s.sortMode != nil {
  417. x["mode"] = *s.sortMode
  418. }
  419. if s.nestedFilter != nil {
  420. x["nested_filter"] = s.nestedFilter.Source()
  421. }
  422. if s.nestedPath != nil {
  423. x["nested_path"] = *s.nestedPath
  424. }
  425. return source
  426. }