search_test.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  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. import (
  6. "context"
  7. "encoding/json"
  8. "reflect"
  9. "testing"
  10. "time"
  11. )
  12. func TestSearchMatchAll(t *testing.T) {
  13. //client := setupTestClientAndCreateIndexAndAddDocs(t, SetTraceLog(log.New(os.Stdout, "", log.LstdFlags)))
  14. client := setupTestClientAndCreateIndexAndAddDocs(t)
  15. // Match all should return all documents
  16. searchResult, err := client.Search().
  17. Index(testIndexName).
  18. Query(NewMatchAllQuery()).
  19. Size(100).
  20. Pretty(true).
  21. Do(context.TODO())
  22. if err != nil {
  23. t.Fatal(err)
  24. }
  25. if searchResult.Hits == nil {
  26. t.Errorf("expected SearchResult.Hits != nil; got nil")
  27. }
  28. if got, want := searchResult.Hits.TotalHits, int64(12); got != want {
  29. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, got)
  30. }
  31. if got, want := len(searchResult.Hits.Hits), 12; got != want {
  32. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, got)
  33. }
  34. for _, hit := range searchResult.Hits.Hits {
  35. if hit.Index != testIndexName {
  36. t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  37. }
  38. item := make(map[string]interface{})
  39. err := json.Unmarshal(*hit.Source, &item)
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. }
  44. }
  45. func TestSearchMatchAllWithRequestCacheDisabled(t *testing.T) {
  46. //client := setupTestClientAndCreateIndexAndAddDocs(t, SetTraceLog(log.New(os.Stdout, "", log.LstdFlags)))
  47. client := setupTestClientAndCreateIndexAndAddDocs(t)
  48. // Match all should return all documents, with request cache disabled
  49. searchResult, err := client.Search().
  50. Index(testIndexName).
  51. Query(NewMatchAllQuery()).
  52. Size(100).
  53. Pretty(true).
  54. RequestCache(false).
  55. Do(context.TODO())
  56. if err != nil {
  57. t.Fatal(err)
  58. }
  59. if searchResult.Hits == nil {
  60. t.Errorf("expected SearchResult.Hits != nil; got nil")
  61. }
  62. if got, want := searchResult.Hits.TotalHits, int64(12); got != want {
  63. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, got)
  64. }
  65. if got, want := len(searchResult.Hits.Hits), 12; got != want {
  66. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, got)
  67. }
  68. }
  69. func BenchmarkSearchMatchAll(b *testing.B) {
  70. client := setupTestClientAndCreateIndexAndAddDocs(b)
  71. for n := 0; n < b.N; n++ {
  72. // Match all should return all documents
  73. all := NewMatchAllQuery()
  74. searchResult, err := client.Search().Index(testIndexName).Query(all).Do(context.TODO())
  75. if err != nil {
  76. b.Fatal(err)
  77. }
  78. if searchResult.Hits == nil {
  79. b.Errorf("expected SearchResult.Hits != nil; got nil")
  80. }
  81. if searchResult.Hits.TotalHits == 0 {
  82. b.Errorf("expected SearchResult.Hits.TotalHits > %d; got %d", 0, searchResult.Hits.TotalHits)
  83. }
  84. }
  85. }
  86. func TestSearchResultTotalHits(t *testing.T) {
  87. client := setupTestClientAndCreateIndexAndAddDocs(t)
  88. count, err := client.Count(testIndexName).Do(context.TODO())
  89. if err != nil {
  90. t.Fatal(err)
  91. }
  92. all := NewMatchAllQuery()
  93. searchResult, err := client.Search().Index(testIndexName).Query(all).Do(context.TODO())
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. got := searchResult.TotalHits()
  98. if got != count {
  99. t.Fatalf("expected %d hits; got: %d", count, got)
  100. }
  101. // No hits
  102. searchResult = &SearchResult{}
  103. got = searchResult.TotalHits()
  104. if got != 0 {
  105. t.Errorf("expected %d hits; got: %d", 0, got)
  106. }
  107. }
  108. func TestSearchResultWithProfiling(t *testing.T) {
  109. client := setupTestClientAndCreateIndexAndAddDocs(t)
  110. all := NewMatchAllQuery()
  111. searchResult, err := client.Search().Index(testIndexName).Query(all).Profile(true).Do(context.TODO())
  112. if err != nil {
  113. t.Fatal(err)
  114. }
  115. if searchResult.Profile == nil {
  116. t.Fatal("Profiled MatchAll query did not return profiling data with results")
  117. }
  118. }
  119. func TestSearchResultEach(t *testing.T) {
  120. client := setupTestClientAndCreateIndexAndAddDocs(t)
  121. all := NewMatchAllQuery()
  122. searchResult, err := client.Search().Index(testIndexName).Query(all).Do(context.TODO())
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. // Iterate over non-ptr type
  127. var aTweet tweet
  128. count := 0
  129. for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
  130. count++
  131. _, ok := item.(tweet)
  132. if !ok {
  133. t.Fatalf("expected hit to be serialized as tweet; got: %v", reflect.ValueOf(item))
  134. }
  135. }
  136. if count == 0 {
  137. t.Errorf("expected to find some hits; got: %d", count)
  138. }
  139. // Iterate over ptr-type
  140. count = 0
  141. var aTweetPtr *tweet
  142. for _, item := range searchResult.Each(reflect.TypeOf(aTweetPtr)) {
  143. count++
  144. tw, ok := item.(*tweet)
  145. if !ok {
  146. t.Fatalf("expected hit to be serialized as tweet; got: %v", reflect.ValueOf(item))
  147. }
  148. if tw == nil {
  149. t.Fatal("expected hit to not be nil")
  150. }
  151. }
  152. if count == 0 {
  153. t.Errorf("expected to find some hits; got: %d", count)
  154. }
  155. // Does not iterate when no hits are found
  156. searchResult = &SearchResult{Hits: nil}
  157. count = 0
  158. for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
  159. count++
  160. _ = item
  161. }
  162. if count != 0 {
  163. t.Errorf("expected to not find any hits; got: %d", count)
  164. }
  165. searchResult = &SearchResult{Hits: &SearchHits{Hits: make([]*SearchHit, 0)}}
  166. count = 0
  167. for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
  168. count++
  169. _ = item
  170. }
  171. if count != 0 {
  172. t.Errorf("expected to not find any hits; got: %d", count)
  173. }
  174. }
  175. func TestSearchSorting(t *testing.T) {
  176. client := setupTestClientAndCreateIndex(t)
  177. tweet1 := tweet{
  178. User: "olivere", Retweets: 108,
  179. Message: "Welcome to Golang and Elasticsearch.",
  180. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  181. }
  182. tweet2 := tweet{
  183. User: "olivere", Retweets: 0,
  184. Message: "Another unrelated topic.",
  185. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  186. }
  187. tweet3 := tweet{
  188. User: "sandrae", Retweets: 12,
  189. Message: "Cycling is fun.",
  190. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  191. }
  192. // Add all documents
  193. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  194. if err != nil {
  195. t.Fatal(err)
  196. }
  197. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  198. if err != nil {
  199. t.Fatal(err)
  200. }
  201. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  202. if err != nil {
  203. t.Fatal(err)
  204. }
  205. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. // Match all should return all documents
  210. all := NewMatchAllQuery()
  211. searchResult, err := client.Search().
  212. Index(testIndexName).
  213. Query(all).
  214. Sort("created", false).
  215. Timeout("1s").
  216. Do(context.TODO())
  217. if err != nil {
  218. t.Fatal(err)
  219. }
  220. if searchResult.Hits == nil {
  221. t.Errorf("expected SearchResult.Hits != nil; got nil")
  222. }
  223. if searchResult.Hits.TotalHits != 3 {
  224. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  225. }
  226. if len(searchResult.Hits.Hits) != 3 {
  227. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
  228. }
  229. for _, hit := range searchResult.Hits.Hits {
  230. if hit.Index != testIndexName {
  231. t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  232. }
  233. item := make(map[string]interface{})
  234. err := json.Unmarshal(*hit.Source, &item)
  235. if err != nil {
  236. t.Fatal(err)
  237. }
  238. }
  239. }
  240. func TestSearchSortingBySorters(t *testing.T) {
  241. client := setupTestClientAndCreateIndex(t)
  242. tweet1 := tweet{
  243. User: "olivere", Retweets: 108,
  244. Message: "Welcome to Golang and Elasticsearch.",
  245. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  246. }
  247. tweet2 := tweet{
  248. User: "olivere", Retweets: 0,
  249. Message: "Another unrelated topic.",
  250. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  251. }
  252. tweet3 := tweet{
  253. User: "sandrae", Retweets: 12,
  254. Message: "Cycling is fun.",
  255. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  256. }
  257. // Add all documents
  258. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  259. if err != nil {
  260. t.Fatal(err)
  261. }
  262. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  263. if err != nil {
  264. t.Fatal(err)
  265. }
  266. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  267. if err != nil {
  268. t.Fatal(err)
  269. }
  270. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  271. if err != nil {
  272. t.Fatal(err)
  273. }
  274. // Match all should return all documents
  275. all := NewMatchAllQuery()
  276. searchResult, err := client.Search().
  277. Index(testIndexName).
  278. Query(all).
  279. SortBy(NewFieldSort("created").Desc(), NewScoreSort()).
  280. Timeout("1s").
  281. Do(context.TODO())
  282. if err != nil {
  283. t.Fatal(err)
  284. }
  285. if searchResult.Hits == nil {
  286. t.Errorf("expected SearchResult.Hits != nil; got nil")
  287. }
  288. if searchResult.Hits.TotalHits != 3 {
  289. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  290. }
  291. if len(searchResult.Hits.Hits) != 3 {
  292. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
  293. }
  294. for _, hit := range searchResult.Hits.Hits {
  295. if hit.Index != testIndexName {
  296. t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  297. }
  298. item := make(map[string]interface{})
  299. err := json.Unmarshal(*hit.Source, &item)
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. }
  304. }
  305. func TestSearchSpecificFields(t *testing.T) {
  306. // client := setupTestClientAndCreateIndexAndLog(t, SetTraceLog(log.New(os.Stdout, "", 0)))
  307. client := setupTestClientAndCreateIndex(t)
  308. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  309. tweet2 := tweet{User: "olivere", Message: "Another unrelated topic."}
  310. tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."}
  311. // Add all documents
  312. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  313. if err != nil {
  314. t.Fatal(err)
  315. }
  316. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  317. if err != nil {
  318. t.Fatal(err)
  319. }
  320. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  321. if err != nil {
  322. t.Fatal(err)
  323. }
  324. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  325. if err != nil {
  326. t.Fatal(err)
  327. }
  328. // Match all should return all documents
  329. all := NewMatchAllQuery()
  330. searchResult, err := client.Search().
  331. Index(testIndexName).
  332. Query(all).
  333. StoredFields("message").
  334. Do(context.TODO())
  335. if err != nil {
  336. t.Fatal(err)
  337. }
  338. if searchResult.Hits == nil {
  339. t.Errorf("expected SearchResult.Hits != nil; got nil")
  340. }
  341. if searchResult.Hits.TotalHits != 3 {
  342. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  343. }
  344. if len(searchResult.Hits.Hits) != 3 {
  345. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
  346. }
  347. for _, hit := range searchResult.Hits.Hits {
  348. if hit.Index != testIndexName {
  349. t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  350. }
  351. if hit.Source != nil {
  352. t.Fatalf("expected SearchResult.Hits.Hit.Source to be nil; got: %q", hit.Source)
  353. }
  354. if hit.Fields == nil {
  355. t.Fatal("expected SearchResult.Hits.Hit.Fields to be != nil")
  356. }
  357. field, found := hit.Fields["message"]
  358. if !found {
  359. t.Errorf("expected SearchResult.Hits.Hit.Fields[%s] to be found", "message")
  360. }
  361. fields, ok := field.([]interface{})
  362. if !ok {
  363. t.Errorf("expected []interface{}; got: %v", reflect.TypeOf(fields))
  364. }
  365. if len(fields) != 1 {
  366. t.Errorf("expected a field with 1 entry; got: %d", len(fields))
  367. }
  368. message, ok := fields[0].(string)
  369. if !ok {
  370. t.Errorf("expected a string; got: %v", reflect.TypeOf(fields[0]))
  371. }
  372. if message == "" {
  373. t.Errorf("expected a message; got: %q", message)
  374. }
  375. }
  376. }
  377. func TestSearchExplain(t *testing.T) {
  378. client := setupTestClientAndCreateIndex(t)
  379. // client := setupTestClientAndCreateIndex(t, SetTraceLog(log.New(os.Stdout, "", 0)))
  380. tweet1 := tweet{
  381. User: "olivere", Retweets: 108,
  382. Message: "Welcome to Golang and Elasticsearch.",
  383. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  384. }
  385. tweet2 := tweet{
  386. User: "olivere", Retweets: 0,
  387. Message: "Another unrelated topic.",
  388. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  389. }
  390. tweet3 := tweet{
  391. User: "sandrae", Retweets: 12,
  392. Message: "Cycling is fun.",
  393. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  394. }
  395. // Add all documents
  396. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  397. if err != nil {
  398. t.Fatal(err)
  399. }
  400. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  401. if err != nil {
  402. t.Fatal(err)
  403. }
  404. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  405. if err != nil {
  406. t.Fatal(err)
  407. }
  408. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  409. if err != nil {
  410. t.Fatal(err)
  411. }
  412. // Match all should return all documents
  413. all := NewMatchAllQuery()
  414. searchResult, err := client.Search().
  415. Index(testIndexName).
  416. Query(all).
  417. Explain(true).
  418. Timeout("1s").
  419. // Pretty(true).
  420. Do(context.TODO())
  421. if err != nil {
  422. t.Fatal(err)
  423. }
  424. if searchResult.Hits == nil {
  425. t.Errorf("expected SearchResult.Hits != nil; got nil")
  426. }
  427. if searchResult.Hits.TotalHits != 3 {
  428. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  429. }
  430. if len(searchResult.Hits.Hits) != 3 {
  431. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
  432. }
  433. for _, hit := range searchResult.Hits.Hits {
  434. if hit.Index != testIndexName {
  435. t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  436. }
  437. if hit.Explanation == nil {
  438. t.Fatal("expected search explanation")
  439. }
  440. if hit.Explanation.Value <= 0.0 {
  441. t.Errorf("expected explanation value to be > 0.0; got: %v", hit.Explanation.Value)
  442. }
  443. if hit.Explanation.Description == "" {
  444. t.Errorf("expected explanation description != %q; got: %q", "", hit.Explanation.Description)
  445. }
  446. }
  447. }
  448. func TestSearchSource(t *testing.T) {
  449. client := setupTestClientAndCreateIndex(t)
  450. tweet1 := tweet{
  451. User: "olivere", Retweets: 108,
  452. Message: "Welcome to Golang and Elasticsearch.",
  453. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  454. }
  455. tweet2 := tweet{
  456. User: "olivere", Retweets: 0,
  457. Message: "Another unrelated topic.",
  458. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  459. }
  460. tweet3 := tweet{
  461. User: "sandrae", Retweets: 12,
  462. Message: "Cycling is fun.",
  463. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  464. }
  465. // Add all documents
  466. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  467. if err != nil {
  468. t.Fatal(err)
  469. }
  470. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  471. if err != nil {
  472. t.Fatal(err)
  473. }
  474. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  475. if err != nil {
  476. t.Fatal(err)
  477. }
  478. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  479. if err != nil {
  480. t.Fatal(err)
  481. }
  482. // Set up the request JSON manually to pass to the search service via Source()
  483. source := map[string]interface{}{
  484. "query": map[string]interface{}{
  485. "match_all": map[string]interface{}{},
  486. },
  487. }
  488. searchResult, err := client.Search().
  489. Index(testIndexName).
  490. Source(source). // sets the JSON request
  491. Do(context.TODO())
  492. if err != nil {
  493. t.Fatal(err)
  494. }
  495. if searchResult.Hits == nil {
  496. t.Errorf("expected SearchResult.Hits != nil; got nil")
  497. }
  498. if searchResult.Hits.TotalHits != 3 {
  499. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  500. }
  501. }
  502. func TestSearchRawString(t *testing.T) {
  503. // client := setupTestClientAndCreateIndexAndLog(t, SetTraceLog(log.New(os.Stdout, "", 0)))
  504. client := setupTestClientAndCreateIndex(t)
  505. tweet1 := tweet{
  506. User: "olivere", Retweets: 108,
  507. Message: "Welcome to Golang and Elasticsearch.",
  508. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  509. }
  510. tweet2 := tweet{
  511. User: "olivere", Retweets: 0,
  512. Message: "Another unrelated topic.",
  513. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  514. }
  515. tweet3 := tweet{
  516. User: "sandrae", Retweets: 12,
  517. Message: "Cycling is fun.",
  518. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  519. }
  520. // Add all documents
  521. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  522. if err != nil {
  523. t.Fatal(err)
  524. }
  525. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  526. if err != nil {
  527. t.Fatal(err)
  528. }
  529. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  530. if err != nil {
  531. t.Fatal(err)
  532. }
  533. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  534. if err != nil {
  535. t.Fatal(err)
  536. }
  537. query := RawStringQuery(`{"match_all":{}}`)
  538. searchResult, err := client.Search().
  539. Index(testIndexName).
  540. Query(query).
  541. Do(context.TODO())
  542. if err != nil {
  543. t.Fatal(err)
  544. }
  545. if searchResult.Hits == nil {
  546. t.Errorf("expected SearchResult.Hits != nil; got nil")
  547. }
  548. if searchResult.Hits.TotalHits != 3 {
  549. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  550. }
  551. }
  552. func TestSearchSearchSource(t *testing.T) {
  553. client := setupTestClientAndCreateIndex(t)
  554. tweet1 := tweet{
  555. User: "olivere", Retweets: 108,
  556. Message: "Welcome to Golang and Elasticsearch.",
  557. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  558. }
  559. tweet2 := tweet{
  560. User: "olivere", Retweets: 0,
  561. Message: "Another unrelated topic.",
  562. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  563. }
  564. tweet3 := tweet{
  565. User: "sandrae", Retweets: 12,
  566. Message: "Cycling is fun.",
  567. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  568. }
  569. // Add all documents
  570. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  571. if err != nil {
  572. t.Fatal(err)
  573. }
  574. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  575. if err != nil {
  576. t.Fatal(err)
  577. }
  578. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  579. if err != nil {
  580. t.Fatal(err)
  581. }
  582. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  583. if err != nil {
  584. t.Fatal(err)
  585. }
  586. // Set up the search source manually and pass it to the search service via SearchSource()
  587. ss := NewSearchSource().Query(NewMatchAllQuery()).From(0).Size(2)
  588. // One can use ss.Source() to get to the raw interface{} that will be used
  589. // as the search request JSON by the SearchService.
  590. searchResult, err := client.Search().
  591. Index(testIndexName).
  592. SearchSource(ss). // sets the SearchSource
  593. Do(context.TODO())
  594. if err != nil {
  595. t.Fatal(err)
  596. }
  597. if searchResult.Hits == nil {
  598. t.Errorf("expected SearchResult.Hits != nil; got nil")
  599. }
  600. if searchResult.Hits.TotalHits != 3 {
  601. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  602. }
  603. if len(searchResult.Hits.Hits) != 2 {
  604. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 2, len(searchResult.Hits.Hits))
  605. }
  606. }
  607. func TestSearchInnerHitsOnHasChild(t *testing.T) {
  608. client := setupTestClientAndCreateIndex(t)
  609. // Check for valid ES version
  610. esversion, err := client.ElasticsearchVersion(DefaultURL)
  611. if err != nil {
  612. t.Fatal(err)
  613. }
  614. if esversion < "1.5.0" {
  615. t.Skip("InnerHits feature is only available for Elasticsearch 1.5+")
  616. return
  617. }
  618. tweet1 := tweet{
  619. User: "olivere", Retweets: 108,
  620. Message: "Welcome to Golang and Elasticsearch.",
  621. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  622. }
  623. tweet2 := tweet{
  624. User: "olivere", Retweets: 0,
  625. Message: "Another unrelated topic.",
  626. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  627. }
  628. comment2a := comment{User: "sandrae", Comment: "What does that even mean?"}
  629. tweet3 := tweet{
  630. User: "sandrae", Retweets: 12,
  631. Message: "Cycling is fun.",
  632. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  633. }
  634. comment3a := comment{User: "nico", Comment: "You bet."}
  635. comment3b := comment{User: "olivere", Comment: "It sure is."}
  636. // Add all documents
  637. _, err = client.Index().Index(testIndexName).Type("tweet").Id("t1").BodyJson(&tweet1).Do(context.TODO())
  638. if err != nil {
  639. t.Fatal(err)
  640. }
  641. _, err = client.Index().Index(testIndexName).Type("tweet").Id("t2").BodyJson(&tweet2).Do(context.TODO())
  642. if err != nil {
  643. t.Fatal(err)
  644. }
  645. _, err = client.Index().Index(testIndexName).Type("comment").Id("c2a").Parent("t2").BodyJson(&comment2a).Do(context.TODO())
  646. if err != nil {
  647. t.Fatal(err)
  648. }
  649. _, err = client.Index().Index(testIndexName).Type("tweet").Id("t3").BodyJson(&tweet3).Do(context.TODO())
  650. if err != nil {
  651. t.Fatal(err)
  652. }
  653. _, err = client.Index().Index(testIndexName).Type("comment").Id("c3a").Parent("t3").BodyJson(&comment3a).Do(context.TODO())
  654. if err != nil {
  655. t.Fatal(err)
  656. }
  657. _, err = client.Index().Index(testIndexName).Type("comment").Id("c3b").Parent("t3").BodyJson(&comment3b).Do(context.TODO())
  658. if err != nil {
  659. t.Fatal(err)
  660. }
  661. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  662. if err != nil {
  663. t.Fatal(err)
  664. }
  665. bq := NewBoolQuery()
  666. bq = bq.Must(NewMatchAllQuery())
  667. bq = bq.Filter(NewHasChildQuery("comment", NewMatchAllQuery()).
  668. InnerHit(NewInnerHit().Name("comments")))
  669. searchResult, err := client.Search().
  670. Index(testIndexName).
  671. Query(bq).
  672. Pretty(true).
  673. Do(context.TODO())
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. if searchResult.Hits == nil {
  678. t.Errorf("expected SearchResult.Hits != nil; got nil")
  679. }
  680. if searchResult.Hits.TotalHits != 2 {
  681. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 2, searchResult.Hits.TotalHits)
  682. }
  683. if len(searchResult.Hits.Hits) != 2 {
  684. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 2, len(searchResult.Hits.Hits))
  685. }
  686. hit := searchResult.Hits.Hits[0]
  687. if hit.Id != "t2" {
  688. t.Fatalf("expected tweet %q; got: %q", "t2", hit.Id)
  689. }
  690. if hit.InnerHits == nil {
  691. t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
  692. }
  693. if len(hit.InnerHits) != 1 {
  694. t.Fatalf("expected %d inner hits; got: %d", 1, len(hit.InnerHits))
  695. }
  696. innerHits, found := hit.InnerHits["comments"]
  697. if !found {
  698. t.Fatalf("expected inner hits for name %q", "comments")
  699. }
  700. if innerHits == nil || innerHits.Hits == nil {
  701. t.Fatal("expected inner hits != nil")
  702. }
  703. if len(innerHits.Hits.Hits) != 1 {
  704. t.Fatalf("expected %d inner hits; got: %d", 1, len(innerHits.Hits.Hits))
  705. }
  706. if innerHits.Hits.Hits[0].Id != "c2a" {
  707. t.Fatalf("expected inner hit with id %q; got: %q", "c2a", innerHits.Hits.Hits[0].Id)
  708. }
  709. hit = searchResult.Hits.Hits[1]
  710. if hit.Id != "t3" {
  711. t.Fatalf("expected tweet %q; got: %q", "t3", hit.Id)
  712. }
  713. if hit.InnerHits == nil {
  714. t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
  715. }
  716. if len(hit.InnerHits) != 1 {
  717. t.Fatalf("expected %d inner hits; got: %d", 1, len(hit.InnerHits))
  718. }
  719. innerHits, found = hit.InnerHits["comments"]
  720. if !found {
  721. t.Fatalf("expected inner hits for name %q", "comments")
  722. }
  723. if innerHits == nil || innerHits.Hits == nil {
  724. t.Fatal("expected inner hits != nil")
  725. }
  726. if len(innerHits.Hits.Hits) != 2 {
  727. t.Fatalf("expected %d inner hits; got: %d", 2, len(innerHits.Hits.Hits))
  728. }
  729. if innerHits.Hits.Hits[0].Id != "c3a" {
  730. t.Fatalf("expected inner hit with id %q; got: %q", "c3a", innerHits.Hits.Hits[0].Id)
  731. }
  732. if innerHits.Hits.Hits[1].Id != "c3b" {
  733. t.Fatalf("expected inner hit with id %q; got: %q", "c3b", innerHits.Hits.Hits[1].Id)
  734. }
  735. }
  736. func TestSearchInnerHitsOnHasParent(t *testing.T) {
  737. client := setupTestClientAndCreateIndex(t)
  738. // Check for valid ES version
  739. esversion, err := client.ElasticsearchVersion(DefaultURL)
  740. if err != nil {
  741. t.Fatal(err)
  742. }
  743. if esversion < "1.5.0" {
  744. t.Skip("InnerHits feature is only available for Elasticsearch 1.5+")
  745. return
  746. }
  747. tweet1 := tweet{
  748. User: "olivere", Retweets: 108,
  749. Message: "Welcome to Golang and Elasticsearch.",
  750. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  751. }
  752. tweet2 := tweet{
  753. User: "olivere", Retweets: 0,
  754. Message: "Another unrelated topic.",
  755. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  756. }
  757. comment2a := comment{User: "sandrae", Comment: "What does that even mean?"}
  758. tweet3 := tweet{
  759. User: "sandrae", Retweets: 12,
  760. Message: "Cycling is fun.",
  761. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  762. }
  763. comment3a := comment{User: "nico", Comment: "You bet."}
  764. comment3b := comment{User: "olivere", Comment: "It sure is."}
  765. // Add all documents
  766. _, err = client.Index().Index(testIndexName).Type("tweet").Id("t1").BodyJson(&tweet1).Do(context.TODO())
  767. if err != nil {
  768. t.Fatal(err)
  769. }
  770. _, err = client.Index().Index(testIndexName).Type("tweet").Id("t2").BodyJson(&tweet2).Do(context.TODO())
  771. if err != nil {
  772. t.Fatal(err)
  773. }
  774. _, err = client.Index().Index(testIndexName).Type("comment").Id("c2a").Parent("t2").BodyJson(&comment2a).Do(context.TODO())
  775. if err != nil {
  776. t.Fatal(err)
  777. }
  778. _, err = client.Index().Index(testIndexName).Type("tweet").Id("t3").BodyJson(&tweet3).Do(context.TODO())
  779. if err != nil {
  780. t.Fatal(err)
  781. }
  782. _, err = client.Index().Index(testIndexName).Type("comment").Id("c3a").Parent("t3").BodyJson(&comment3a).Do(context.TODO())
  783. if err != nil {
  784. t.Fatal(err)
  785. }
  786. _, err = client.Index().Index(testIndexName).Type("comment").Id("c3b").Parent("t3").BodyJson(&comment3b).Do(context.TODO())
  787. if err != nil {
  788. t.Fatal(err)
  789. }
  790. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  791. if err != nil {
  792. t.Fatal(err)
  793. }
  794. bq := NewBoolQuery()
  795. bq = bq.Must(NewMatchAllQuery())
  796. bq = bq.Filter(NewHasParentQuery("tweet", NewMatchAllQuery()).
  797. InnerHit(NewInnerHit().Name("tweets")))
  798. searchResult, err := client.Search().
  799. Index(testIndexName).
  800. Query(bq).
  801. Pretty(true).
  802. Do(context.TODO())
  803. if err != nil {
  804. t.Fatal(err)
  805. }
  806. if searchResult.Hits == nil {
  807. t.Errorf("expected SearchResult.Hits != nil; got nil")
  808. }
  809. if searchResult.Hits.TotalHits != 3 {
  810. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  811. }
  812. if len(searchResult.Hits.Hits) != 3 {
  813. t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
  814. }
  815. hit := searchResult.Hits.Hits[0]
  816. if hit.Id != "c2a" {
  817. t.Fatalf("expected tweet %q; got: %q", "c2a", hit.Id)
  818. }
  819. if hit.InnerHits == nil {
  820. t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
  821. }
  822. if len(hit.InnerHits) != 1 {
  823. t.Fatalf("expected %d inner hits; got: %d", 1, len(hit.InnerHits))
  824. }
  825. innerHits, found := hit.InnerHits["tweets"]
  826. if !found {
  827. t.Fatalf("expected inner hits for name %q", "tweets")
  828. }
  829. if innerHits == nil || innerHits.Hits == nil {
  830. t.Fatal("expected inner hits != nil")
  831. }
  832. if len(innerHits.Hits.Hits) != 1 {
  833. t.Fatalf("expected %d inner hits; got: %d", 1, len(innerHits.Hits.Hits))
  834. }
  835. if innerHits.Hits.Hits[0].Id != "t2" {
  836. t.Fatalf("expected inner hit with id %q; got: %q", "t2", innerHits.Hits.Hits[0].Id)
  837. }
  838. hit = searchResult.Hits.Hits[1]
  839. if hit.Id != "c3a" {
  840. t.Fatalf("expected tweet %q; got: %q", "c3a", hit.Id)
  841. }
  842. if hit.InnerHits == nil {
  843. t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
  844. }
  845. if len(hit.InnerHits) != 1 {
  846. t.Fatalf("expected %d inner hits; got: %d", 1, len(hit.InnerHits))
  847. }
  848. innerHits, found = hit.InnerHits["tweets"]
  849. if !found {
  850. t.Fatalf("expected inner hits for name %q", "tweets")
  851. }
  852. if innerHits == nil || innerHits.Hits == nil {
  853. t.Fatal("expected inner hits != nil")
  854. }
  855. if len(innerHits.Hits.Hits) != 1 {
  856. t.Fatalf("expected %d inner hits; got: %d", 1, len(innerHits.Hits.Hits))
  857. }
  858. if innerHits.Hits.Hits[0].Id != "t3" {
  859. t.Fatalf("expected inner hit with id %q; got: %q", "t3", innerHits.Hits.Hits[0].Id)
  860. }
  861. hit = searchResult.Hits.Hits[2]
  862. if hit.Id != "c3b" {
  863. t.Fatalf("expected tweet %q; got: %q", "c3b", hit.Id)
  864. }
  865. if hit.InnerHits == nil {
  866. t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
  867. }
  868. if len(hit.InnerHits) != 1 {
  869. t.Fatalf("expected %d inner hits; got: %d", 1, len(hit.InnerHits))
  870. }
  871. innerHits, found = hit.InnerHits["tweets"]
  872. if !found {
  873. t.Fatalf("expected inner hits for name %q", "tweets")
  874. }
  875. if innerHits == nil || innerHits.Hits == nil {
  876. t.Fatal("expected inner hits != nil")
  877. }
  878. if len(innerHits.Hits.Hits) != 1 {
  879. t.Fatalf("expected %d inner hits; got: %d", 1, len(innerHits.Hits.Hits))
  880. }
  881. if innerHits.Hits.Hits[0].Id != "t3" {
  882. t.Fatalf("expected inner hit with id %q; got: %q", "t3", innerHits.Hits.Hits[0].Id)
  883. }
  884. }
  885. func TestSearchBuildURL(t *testing.T) {
  886. client := setupTestClient(t)
  887. tests := []struct {
  888. Indices []string
  889. Types []string
  890. Expected string
  891. }{
  892. {
  893. []string{},
  894. []string{},
  895. "/_search",
  896. },
  897. {
  898. []string{"index1"},
  899. []string{},
  900. "/index1/_search",
  901. },
  902. {
  903. []string{"index1", "index2"},
  904. []string{},
  905. "/index1%2Cindex2/_search",
  906. },
  907. {
  908. []string{},
  909. []string{"type1"},
  910. "/_all/type1/_search",
  911. },
  912. {
  913. []string{"index1"},
  914. []string{"type1"},
  915. "/index1/type1/_search",
  916. },
  917. {
  918. []string{"index1", "index2"},
  919. []string{"type1", "type2"},
  920. "/index1%2Cindex2/type1%2Ctype2/_search",
  921. },
  922. {
  923. []string{},
  924. []string{"type1", "type2"},
  925. "/_all/type1%2Ctype2/_search",
  926. },
  927. }
  928. for i, test := range tests {
  929. path, _, err := client.Search().Index(test.Indices...).Type(test.Types...).buildURL()
  930. if err != nil {
  931. t.Errorf("case #%d: %v", i+1, err)
  932. continue
  933. }
  934. if path != test.Expected {
  935. t.Errorf("case #%d: expected %q; got: %q", i+1, test.Expected, path)
  936. }
  937. }
  938. }
  939. func TestSearchFilterPath(t *testing.T) {
  940. // client := setupTestClientAndCreateIndexAndAddDocs(t, SetTraceLog(log.New(os.Stdout, "", log.LstdFlags)))
  941. client := setupTestClientAndCreateIndexAndAddDocs(t)
  942. // Match all should return all documents
  943. all := NewMatchAllQuery()
  944. searchResult, err := client.Search().
  945. Index(testIndexName).
  946. Type("tweet").
  947. Query(all).
  948. FilterPath(
  949. "took",
  950. "hits.hits._id",
  951. "hits.hits._source.user",
  952. "hits.hits._source.message",
  953. ).
  954. Timeout("1s").
  955. Pretty(true).
  956. Do(context.TODO())
  957. if err != nil {
  958. t.Fatal(err)
  959. }
  960. if searchResult.Hits == nil {
  961. t.Fatalf("expected SearchResult.Hits != nil; got nil")
  962. }
  963. // 0 because it was filtered out
  964. if want, got := int64(0), searchResult.Hits.TotalHits; want != got {
  965. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, got)
  966. }
  967. if want, got := 3, len(searchResult.Hits.Hits); want != got {
  968. t.Fatalf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, got)
  969. }
  970. for _, hit := range searchResult.Hits.Hits {
  971. if want, got := "", hit.Index; want != got {
  972. t.Fatalf("expected index %q, got %q", want, got)
  973. }
  974. item := make(map[string]interface{})
  975. err := json.Unmarshal(*hit.Source, &item)
  976. if err != nil {
  977. t.Fatal(err)
  978. }
  979. // user field
  980. v, found := item["user"]
  981. if !found {
  982. t.Fatalf("expected SearchResult.Hits.Hit[%q] to be found", "user")
  983. }
  984. if v == "" {
  985. t.Fatalf("expected user field, got %v (%T)", v, v)
  986. }
  987. // No retweets field
  988. v, found = item["retweets"]
  989. if found {
  990. t.Fatalf("expected SearchResult.Hits.Hit[%q] to not be found, got %v", "retweets", v)
  991. }
  992. if v == "" {
  993. t.Fatalf("expected user field, got %v (%T)", v, v)
  994. }
  995. }
  996. }
  997. func TestSearchAfter(t *testing.T) {
  998. // client := setupTestClientAndCreateIndexAndLog(t, SetTraceLog(log.New(os.Stdout, "", 0)))
  999. client := setupTestClientAndCreateIndex(t)
  1000. tweet1 := tweet{
  1001. User: "olivere", Retweets: 108,
  1002. Message: "Welcome to Golang and Elasticsearch.",
  1003. Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
  1004. }
  1005. tweet2 := tweet{
  1006. User: "olivere", Retweets: 0,
  1007. Message: "Another unrelated topic.",
  1008. Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
  1009. }
  1010. tweet3 := tweet{
  1011. User: "sandrae", Retweets: 12,
  1012. Message: "Cycling is fun.",
  1013. Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
  1014. }
  1015. // Add all documents
  1016. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO())
  1017. if err != nil {
  1018. t.Fatal(err)
  1019. }
  1020. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO())
  1021. if err != nil {
  1022. t.Fatal(err)
  1023. }
  1024. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO())
  1025. if err != nil {
  1026. t.Fatal(err)
  1027. }
  1028. _, err = client.Flush().Index(testIndexName).Do(context.TODO())
  1029. if err != nil {
  1030. t.Fatal(err)
  1031. }
  1032. searchResult, err := client.Search().
  1033. Index(testIndexName).
  1034. Query(NewMatchAllQuery()).
  1035. SearchAfter("olivere").
  1036. Sort("user", true).
  1037. Do(context.TODO())
  1038. if err != nil {
  1039. t.Fatal(err)
  1040. }
  1041. if searchResult.Hits == nil {
  1042. t.Errorf("expected SearchResult.Hits != nil; got nil")
  1043. }
  1044. if searchResult.Hits.TotalHits != 3 {
  1045. t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
  1046. }
  1047. if want, got := 1, len(searchResult.Hits.Hits); want != got {
  1048. t.Fatalf("expected len(SearchResult.Hits.Hits) = %d; got: %d", want, got)
  1049. }
  1050. hit := searchResult.Hits.Hits[0]
  1051. if want, got := "3", hit.Id; want != got {
  1052. t.Fatalf("expected tweet %q; got: %q", want, got)
  1053. }
  1054. }
  1055. func TestSearchResultWithFieldCollapsing(t *testing.T) {
  1056. client := setupTestClientAndCreateIndexAndAddDocs(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))
  1057. searchResult, err := client.Search().
  1058. Index(testIndexName).
  1059. Type("tweet").
  1060. Query(NewMatchAllQuery()).
  1061. Collapse(NewCollapseBuilder("user")).
  1062. Pretty(true).
  1063. Do(context.TODO())
  1064. if err != nil {
  1065. t.Fatal(err)
  1066. }
  1067. if searchResult.Hits == nil {
  1068. t.Fatalf("expected SearchResult.Hits != nil; got nil")
  1069. }
  1070. if got := searchResult.Hits.TotalHits; got == 0 {
  1071. t.Fatalf("expected SearchResult.Hits.TotalHits > 0; got %d", got)
  1072. }
  1073. for _, hit := range searchResult.Hits.Hits {
  1074. if hit.Index != testIndexName {
  1075. t.Fatalf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  1076. }
  1077. item := make(map[string]interface{})
  1078. err := json.Unmarshal(*hit.Source, &item)
  1079. if err != nil {
  1080. t.Fatal(err)
  1081. }
  1082. if len(hit.Fields) == 0 {
  1083. t.Fatal("expected fields in SearchResult")
  1084. }
  1085. usersVal, ok := hit.Fields["user"]
  1086. if !ok {
  1087. t.Fatalf("expected %q field in fields of SearchResult", "user")
  1088. }
  1089. users, ok := usersVal.([]interface{})
  1090. if !ok {
  1091. t.Fatalf("expected slice of strings in field of SearchResult, got %T", usersVal)
  1092. }
  1093. if len(users) != 1 {
  1094. t.Fatalf("expected 1 entry in users slice, got %d", len(users))
  1095. }
  1096. }
  1097. }
  1098. func TestSearchResultWithFieldCollapsingAndInnerHits(t *testing.T) {
  1099. client := setupTestClientAndCreateIndexAndAddDocs(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))
  1100. searchResult, err := client.Search().
  1101. Index(testIndexName).
  1102. Type("tweet").
  1103. Query(NewMatchAllQuery()).
  1104. Collapse(
  1105. NewCollapseBuilder("user").
  1106. InnerHit(
  1107. NewInnerHit().Name("last_tweets").Size(5).Sort("created", true),
  1108. ).
  1109. MaxConcurrentGroupRequests(4)).
  1110. Pretty(true).
  1111. Do(context.TODO())
  1112. if err != nil {
  1113. t.Fatal(err)
  1114. }
  1115. if searchResult.Hits == nil {
  1116. t.Fatalf("expected SearchResult.Hits != nil; got nil")
  1117. }
  1118. if got := searchResult.Hits.TotalHits; got == 0 {
  1119. t.Fatalf("expected SearchResult.Hits.TotalHits > 0; got %d", got)
  1120. }
  1121. for _, hit := range searchResult.Hits.Hits {
  1122. if hit.Index != testIndexName {
  1123. t.Fatalf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
  1124. }
  1125. item := make(map[string]interface{})
  1126. err := json.Unmarshal(*hit.Source, &item)
  1127. if err != nil {
  1128. t.Fatal(err)
  1129. }
  1130. if len(hit.Fields) == 0 {
  1131. t.Fatal("expected fields in SearchResult")
  1132. }
  1133. usersVal, ok := hit.Fields["user"]
  1134. if !ok {
  1135. t.Fatalf("expected %q field in fields of SearchResult", "user")
  1136. }
  1137. users, ok := usersVal.([]interface{})
  1138. if !ok {
  1139. t.Fatalf("expected slice of strings in field of SearchResult, got %T", usersVal)
  1140. }
  1141. if len(users) != 1 {
  1142. t.Fatalf("expected 1 entry in users slice, got %d", len(users))
  1143. }
  1144. lastTweets, ok := hit.InnerHits["last_tweets"]
  1145. if !ok {
  1146. t.Fatalf("expected inner_hits named %q in SearchResult", "last_tweets")
  1147. }
  1148. if lastTweets == nil {
  1149. t.Fatal("expected inner_hits in SearchResult")
  1150. }
  1151. }
  1152. }