highlight.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. // Copyright 2012-present 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. // Highlight allows highlighting search results on one or more fields.
  6. // For details, see:
  7. // https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-request-highlighting.html
  8. type Highlight struct {
  9. fields []*HighlighterField
  10. tagsSchema *string
  11. highlightFilter *bool
  12. fragmentSize *int
  13. numOfFragments *int
  14. preTags []string
  15. postTags []string
  16. order *string
  17. encoder *string
  18. requireFieldMatch *bool
  19. boundaryMaxScan *int
  20. boundaryChars *string
  21. boundaryScannerType *string
  22. boundaryScannerLocale *string
  23. highlighterType *string
  24. fragmenter *string
  25. highlightQuery Query
  26. noMatchSize *int
  27. phraseLimit *int
  28. options map[string]interface{}
  29. forceSource *bool
  30. useExplicitFieldOrder bool
  31. }
  32. func NewHighlight() *Highlight {
  33. hl := &Highlight{
  34. options: make(map[string]interface{}),
  35. }
  36. return hl
  37. }
  38. func (hl *Highlight) Fields(fields ...*HighlighterField) *Highlight {
  39. hl.fields = append(hl.fields, fields...)
  40. return hl
  41. }
  42. func (hl *Highlight) Field(name string) *Highlight {
  43. field := NewHighlighterField(name)
  44. hl.fields = append(hl.fields, field)
  45. return hl
  46. }
  47. func (hl *Highlight) TagsSchema(schemaName string) *Highlight {
  48. hl.tagsSchema = &schemaName
  49. return hl
  50. }
  51. func (hl *Highlight) HighlightFilter(highlightFilter bool) *Highlight {
  52. hl.highlightFilter = &highlightFilter
  53. return hl
  54. }
  55. func (hl *Highlight) FragmentSize(fragmentSize int) *Highlight {
  56. hl.fragmentSize = &fragmentSize
  57. return hl
  58. }
  59. func (hl *Highlight) NumOfFragments(numOfFragments int) *Highlight {
  60. hl.numOfFragments = &numOfFragments
  61. return hl
  62. }
  63. func (hl *Highlight) Encoder(encoder string) *Highlight {
  64. hl.encoder = &encoder
  65. return hl
  66. }
  67. func (hl *Highlight) PreTags(preTags ...string) *Highlight {
  68. hl.preTags = append(hl.preTags, preTags...)
  69. return hl
  70. }
  71. func (hl *Highlight) PostTags(postTags ...string) *Highlight {
  72. hl.postTags = append(hl.postTags, postTags...)
  73. return hl
  74. }
  75. func (hl *Highlight) Order(order string) *Highlight {
  76. hl.order = &order
  77. return hl
  78. }
  79. func (hl *Highlight) RequireFieldMatch(requireFieldMatch bool) *Highlight {
  80. hl.requireFieldMatch = &requireFieldMatch
  81. return hl
  82. }
  83. func (hl *Highlight) BoundaryMaxScan(boundaryMaxScan int) *Highlight {
  84. hl.boundaryMaxScan = &boundaryMaxScan
  85. return hl
  86. }
  87. func (hl *Highlight) BoundaryChars(boundaryChars string) *Highlight {
  88. hl.boundaryChars = &boundaryChars
  89. return hl
  90. }
  91. func (hl *Highlight) BoundaryScannerType(boundaryScannerType string) *Highlight {
  92. hl.boundaryScannerType = &boundaryScannerType
  93. return hl
  94. }
  95. func (hl *Highlight) BoundaryScannerLocale(boundaryScannerLocale string) *Highlight {
  96. hl.boundaryScannerLocale = &boundaryScannerLocale
  97. return hl
  98. }
  99. func (hl *Highlight) HighlighterType(highlighterType string) *Highlight {
  100. hl.highlighterType = &highlighterType
  101. return hl
  102. }
  103. func (hl *Highlight) Fragmenter(fragmenter string) *Highlight {
  104. hl.fragmenter = &fragmenter
  105. return hl
  106. }
  107. func (hl *Highlight) HighlightQuery(highlightQuery Query) *Highlight {
  108. hl.highlightQuery = highlightQuery
  109. return hl
  110. }
  111. func (hl *Highlight) NoMatchSize(noMatchSize int) *Highlight {
  112. hl.noMatchSize = &noMatchSize
  113. return hl
  114. }
  115. func (hl *Highlight) Options(options map[string]interface{}) *Highlight {
  116. hl.options = options
  117. return hl
  118. }
  119. func (hl *Highlight) ForceSource(forceSource bool) *Highlight {
  120. hl.forceSource = &forceSource
  121. return hl
  122. }
  123. func (hl *Highlight) UseExplicitFieldOrder(useExplicitFieldOrder bool) *Highlight {
  124. hl.useExplicitFieldOrder = useExplicitFieldOrder
  125. return hl
  126. }
  127. // Creates the query source for the bool query.
  128. func (hl *Highlight) Source() (interface{}, error) {
  129. // Returns the map inside of "highlight":
  130. // "highlight":{
  131. // ... this ...
  132. // }
  133. source := make(map[string]interface{})
  134. if hl.tagsSchema != nil {
  135. source["tags_schema"] = *hl.tagsSchema
  136. }
  137. if hl.preTags != nil && len(hl.preTags) > 0 {
  138. source["pre_tags"] = hl.preTags
  139. }
  140. if hl.postTags != nil && len(hl.postTags) > 0 {
  141. source["post_tags"] = hl.postTags
  142. }
  143. if hl.order != nil {
  144. source["order"] = *hl.order
  145. }
  146. if hl.highlightFilter != nil {
  147. source["highlight_filter"] = *hl.highlightFilter
  148. }
  149. if hl.fragmentSize != nil {
  150. source["fragment_size"] = *hl.fragmentSize
  151. }
  152. if hl.numOfFragments != nil {
  153. source["number_of_fragments"] = *hl.numOfFragments
  154. }
  155. if hl.encoder != nil {
  156. source["encoder"] = *hl.encoder
  157. }
  158. if hl.requireFieldMatch != nil {
  159. source["require_field_match"] = *hl.requireFieldMatch
  160. }
  161. if hl.boundaryMaxScan != nil {
  162. source["boundary_max_scan"] = *hl.boundaryMaxScan
  163. }
  164. if hl.boundaryChars != nil {
  165. source["boundary_chars"] = *hl.boundaryChars
  166. }
  167. if hl.boundaryScannerType != nil {
  168. source["boundary_scanner"] = *hl.boundaryScannerType
  169. }
  170. if hl.boundaryScannerLocale != nil {
  171. source["boundary_scanner_locale"] = *hl.boundaryScannerLocale
  172. }
  173. if hl.highlighterType != nil {
  174. source["type"] = *hl.highlighterType
  175. }
  176. if hl.fragmenter != nil {
  177. source["fragmenter"] = *hl.fragmenter
  178. }
  179. if hl.highlightQuery != nil {
  180. src, err := hl.highlightQuery.Source()
  181. if err != nil {
  182. return nil, err
  183. }
  184. source["highlight_query"] = src
  185. }
  186. if hl.noMatchSize != nil {
  187. source["no_match_size"] = *hl.noMatchSize
  188. }
  189. if hl.phraseLimit != nil {
  190. source["phrase_limit"] = *hl.phraseLimit
  191. }
  192. if hl.options != nil && len(hl.options) > 0 {
  193. source["options"] = hl.options
  194. }
  195. if hl.forceSource != nil {
  196. source["force_source"] = *hl.forceSource
  197. }
  198. if hl.fields != nil && len(hl.fields) > 0 {
  199. if hl.useExplicitFieldOrder {
  200. // Use a slice for the fields
  201. var fields []map[string]interface{}
  202. for _, field := range hl.fields {
  203. src, err := field.Source()
  204. if err != nil {
  205. return nil, err
  206. }
  207. fmap := make(map[string]interface{})
  208. fmap[field.Name] = src
  209. fields = append(fields, fmap)
  210. }
  211. source["fields"] = fields
  212. } else {
  213. // Use a map for the fields
  214. fields := make(map[string]interface{}, 0)
  215. for _, field := range hl.fields {
  216. src, err := field.Source()
  217. if err != nil {
  218. return nil, err
  219. }
  220. fields[field.Name] = src
  221. }
  222. source["fields"] = fields
  223. }
  224. }
  225. return source, nil
  226. }
  227. // HighlighterField specifies a highlighted field.
  228. type HighlighterField struct {
  229. Name string
  230. preTags []string
  231. postTags []string
  232. fragmentSize int
  233. fragmentOffset int
  234. numOfFragments int
  235. highlightFilter *bool
  236. order *string
  237. requireFieldMatch *bool
  238. boundaryMaxScan int
  239. boundaryChars []rune
  240. highlighterType *string
  241. fragmenter *string
  242. highlightQuery Query
  243. noMatchSize *int
  244. matchedFields []string
  245. phraseLimit *int
  246. options map[string]interface{}
  247. forceSource *bool
  248. /*
  249. Name string
  250. preTags []string
  251. postTags []string
  252. fragmentSize int
  253. numOfFragments int
  254. fragmentOffset int
  255. highlightFilter *bool
  256. order string
  257. requireFieldMatch *bool
  258. boundaryMaxScan int
  259. boundaryChars []rune
  260. highlighterType string
  261. fragmenter string
  262. highlightQuery Query
  263. noMatchSize *int
  264. matchedFields []string
  265. options map[string]interface{}
  266. forceSource *bool
  267. */
  268. }
  269. func NewHighlighterField(name string) *HighlighterField {
  270. return &HighlighterField{
  271. Name: name,
  272. preTags: make([]string, 0),
  273. postTags: make([]string, 0),
  274. fragmentSize: -1,
  275. fragmentOffset: -1,
  276. numOfFragments: -1,
  277. boundaryMaxScan: -1,
  278. boundaryChars: make([]rune, 0),
  279. matchedFields: make([]string, 0),
  280. options: make(map[string]interface{}),
  281. }
  282. }
  283. func (f *HighlighterField) PreTags(preTags ...string) *HighlighterField {
  284. f.preTags = append(f.preTags, preTags...)
  285. return f
  286. }
  287. func (f *HighlighterField) PostTags(postTags ...string) *HighlighterField {
  288. f.postTags = append(f.postTags, postTags...)
  289. return f
  290. }
  291. func (f *HighlighterField) FragmentSize(fragmentSize int) *HighlighterField {
  292. f.fragmentSize = fragmentSize
  293. return f
  294. }
  295. func (f *HighlighterField) FragmentOffset(fragmentOffset int) *HighlighterField {
  296. f.fragmentOffset = fragmentOffset
  297. return f
  298. }
  299. func (f *HighlighterField) NumOfFragments(numOfFragments int) *HighlighterField {
  300. f.numOfFragments = numOfFragments
  301. return f
  302. }
  303. func (f *HighlighterField) HighlightFilter(highlightFilter bool) *HighlighterField {
  304. f.highlightFilter = &highlightFilter
  305. return f
  306. }
  307. func (f *HighlighterField) Order(order string) *HighlighterField {
  308. f.order = &order
  309. return f
  310. }
  311. func (f *HighlighterField) RequireFieldMatch(requireFieldMatch bool) *HighlighterField {
  312. f.requireFieldMatch = &requireFieldMatch
  313. return f
  314. }
  315. func (f *HighlighterField) BoundaryMaxScan(boundaryMaxScan int) *HighlighterField {
  316. f.boundaryMaxScan = boundaryMaxScan
  317. return f
  318. }
  319. func (f *HighlighterField) BoundaryChars(boundaryChars ...rune) *HighlighterField {
  320. f.boundaryChars = append(f.boundaryChars, boundaryChars...)
  321. return f
  322. }
  323. func (f *HighlighterField) HighlighterType(highlighterType string) *HighlighterField {
  324. f.highlighterType = &highlighterType
  325. return f
  326. }
  327. func (f *HighlighterField) Fragmenter(fragmenter string) *HighlighterField {
  328. f.fragmenter = &fragmenter
  329. return f
  330. }
  331. func (f *HighlighterField) HighlightQuery(highlightQuery Query) *HighlighterField {
  332. f.highlightQuery = highlightQuery
  333. return f
  334. }
  335. func (f *HighlighterField) NoMatchSize(noMatchSize int) *HighlighterField {
  336. f.noMatchSize = &noMatchSize
  337. return f
  338. }
  339. func (f *HighlighterField) Options(options map[string]interface{}) *HighlighterField {
  340. f.options = options
  341. return f
  342. }
  343. func (f *HighlighterField) MatchedFields(matchedFields ...string) *HighlighterField {
  344. f.matchedFields = append(f.matchedFields, matchedFields...)
  345. return f
  346. }
  347. func (f *HighlighterField) PhraseLimit(phraseLimit int) *HighlighterField {
  348. f.phraseLimit = &phraseLimit
  349. return f
  350. }
  351. func (f *HighlighterField) ForceSource(forceSource bool) *HighlighterField {
  352. f.forceSource = &forceSource
  353. return f
  354. }
  355. func (f *HighlighterField) Source() (interface{}, error) {
  356. source := make(map[string]interface{})
  357. if f.preTags != nil && len(f.preTags) > 0 {
  358. source["pre_tags"] = f.preTags
  359. }
  360. if f.postTags != nil && len(f.postTags) > 0 {
  361. source["post_tags"] = f.postTags
  362. }
  363. if f.fragmentSize != -1 {
  364. source["fragment_size"] = f.fragmentSize
  365. }
  366. if f.numOfFragments != -1 {
  367. source["number_of_fragments"] = f.numOfFragments
  368. }
  369. if f.fragmentOffset != -1 {
  370. source["fragment_offset"] = f.fragmentOffset
  371. }
  372. if f.highlightFilter != nil {
  373. source["highlight_filter"] = *f.highlightFilter
  374. }
  375. if f.order != nil {
  376. source["order"] = *f.order
  377. }
  378. if f.requireFieldMatch != nil {
  379. source["require_field_match"] = *f.requireFieldMatch
  380. }
  381. if f.boundaryMaxScan != -1 {
  382. source["boundary_max_scan"] = f.boundaryMaxScan
  383. }
  384. if f.boundaryChars != nil && len(f.boundaryChars) > 0 {
  385. source["boundary_chars"] = f.boundaryChars
  386. }
  387. if f.highlighterType != nil {
  388. source["type"] = *f.highlighterType
  389. }
  390. if f.fragmenter != nil {
  391. source["fragmenter"] = *f.fragmenter
  392. }
  393. if f.highlightQuery != nil {
  394. src, err := f.highlightQuery.Source()
  395. if err != nil {
  396. return nil, err
  397. }
  398. source["highlight_query"] = src
  399. }
  400. if f.noMatchSize != nil {
  401. source["no_match_size"] = *f.noMatchSize
  402. }
  403. if f.matchedFields != nil && len(f.matchedFields) > 0 {
  404. source["matched_fields"] = f.matchedFields
  405. }
  406. if f.phraseLimit != nil {
  407. source["phrase_limit"] = *f.phraseLimit
  408. }
  409. if f.options != nil && len(f.options) > 0 {
  410. source["options"] = f.options
  411. }
  412. if f.forceSource != nil {
  413. source["force_source"] = *f.forceSource
  414. }
  415. return source, nil
  416. }