summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/olivere/elastic/search_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/olivere/elastic/search_test.go')
-rw-r--r--vendor/github.com/olivere/elastic/search_test.go1265
1 files changed, 1265 insertions, 0 deletions
diff --git a/vendor/github.com/olivere/elastic/search_test.go b/vendor/github.com/olivere/elastic/search_test.go
new file mode 100644
index 000000000..097c26525
--- /dev/null
+++ b/vendor/github.com/olivere/elastic/search_test.go
@@ -0,0 +1,1265 @@
+// Copyright 2012-present Oliver Eilhard. All rights reserved.
+// Use of this source code is governed by a MIT-license.
+// See http://olivere.mit-license.org/license.txt for details.
+
+package elastic
+
+import (
+ "context"
+ "encoding/json"
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestSearchMatchAll(t *testing.T) {
+ //client := setupTestClientAndCreateIndexAndAddDocs(t, SetTraceLog(log.New(os.Stdout, "", log.LstdFlags)))
+ client := setupTestClientAndCreateIndexAndAddDocs(t)
+
+ // Match all should return all documents
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(NewMatchAllQuery()).
+ Size(100).
+ Pretty(true).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if got, want := searchResult.Hits.TotalHits, int64(3); got != want {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, got)
+ }
+ if got, want := len(searchResult.Hits.Hits), 3; got != want {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, got)
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ item := make(map[string]interface{})
+ err := json.Unmarshal(*hit.Source, &item)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+}
+
+func TestSearchMatchAllWithRequestCacheDisabled(t *testing.T) {
+ //client := setupTestClientAndCreateIndexAndAddDocs(t, SetTraceLog(log.New(os.Stdout, "", log.LstdFlags)))
+ client := setupTestClientAndCreateIndexAndAddDocs(t)
+
+ // Match all should return all documents, with request cache disabled
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(NewMatchAllQuery()).
+ Size(100).
+ Pretty(true).
+ RequestCache(false).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if got, want := searchResult.Hits.TotalHits, int64(3); got != want {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, got)
+ }
+ if got, want := len(searchResult.Hits.Hits), 3; got != want {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, got)
+ }
+}
+
+func BenchmarkSearchMatchAll(b *testing.B) {
+ client := setupTestClientAndCreateIndexAndAddDocs(b)
+
+ for n := 0; n < b.N; n++ {
+ // Match all should return all documents
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().Index(testIndexName).Query(all).Do(context.TODO())
+ if err != nil {
+ b.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ b.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits == 0 {
+ b.Errorf("expected SearchResult.Hits.TotalHits > %d; got %d", 0, searchResult.Hits.TotalHits)
+ }
+ }
+}
+
+func TestSearchResultTotalHits(t *testing.T) {
+ client := setupTestClientAndCreateIndexAndAddDocs(t)
+
+ count, err := client.Count(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().Index(testIndexName).Query(all).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got := searchResult.TotalHits()
+ if got != count {
+ t.Fatalf("expected %d hits; got: %d", count, got)
+ }
+
+ // No hits
+ searchResult = &SearchResult{}
+ got = searchResult.TotalHits()
+ if got != 0 {
+ t.Errorf("expected %d hits; got: %d", 0, got)
+ }
+}
+
+func TestSearchResultWithProfiling(t *testing.T) {
+ client := setupTestClientAndCreateIndexAndAddDocs(t)
+
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().Index(testIndexName).Query(all).Profile(true).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if searchResult.Profile == nil {
+ t.Fatal("Profiled MatchAll query did not return profiling data with results")
+ }
+}
+
+func TestSearchResultEach(t *testing.T) {
+ client := setupTestClientAndCreateIndexAndAddDocs(t)
+
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().Index(testIndexName).Query(all).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Iterate over non-ptr type
+ var aTweet tweet
+ count := 0
+ for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
+ count++
+ _, ok := item.(tweet)
+ if !ok {
+ t.Fatalf("expected hit to be serialized as tweet; got: %v", reflect.ValueOf(item))
+ }
+ }
+ if count == 0 {
+ t.Errorf("expected to find some hits; got: %d", count)
+ }
+
+ // Iterate over ptr-type
+ count = 0
+ var aTweetPtr *tweet
+ for _, item := range searchResult.Each(reflect.TypeOf(aTweetPtr)) {
+ count++
+ tw, ok := item.(*tweet)
+ if !ok {
+ t.Fatalf("expected hit to be serialized as tweet; got: %v", reflect.ValueOf(item))
+ }
+ if tw == nil {
+ t.Fatal("expected hit to not be nil")
+ }
+ }
+ if count == 0 {
+ t.Errorf("expected to find some hits; got: %d", count)
+ }
+
+ // Does not iterate when no hits are found
+ searchResult = &SearchResult{Hits: nil}
+ count = 0
+ for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
+ count++
+ _ = item
+ }
+ if count != 0 {
+ t.Errorf("expected to not find any hits; got: %d", count)
+ }
+ searchResult = &SearchResult{Hits: &SearchHits{Hits: make([]*SearchHit, 0)}}
+ count = 0
+ for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
+ count++
+ _ = item
+ }
+ if count != 0 {
+ t.Errorf("expected to not find any hits; got: %d", count)
+ }
+}
+
+func TestSearchResultEachNoSource(t *testing.T) {
+ client := setupTestClientAndCreateIndexAndAddDocsNoSource(t)
+
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().Index(testNoSourceIndexName).Query(all).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Iterate over non-ptr type
+ var aTweet tweet
+ count := 0
+ for _, item := range searchResult.Each(reflect.TypeOf(aTweet)) {
+ count++
+ tw, ok := item.(tweet)
+ if !ok {
+ t.Fatalf("expected hit to be serialized as tweet; got: %v", reflect.ValueOf(item))
+ }
+
+ if tw.User != "" {
+ t.Fatalf("expected no _source hit to be empty tweet; got: %v", reflect.ValueOf(item))
+ }
+ }
+ if count != 2 {
+ t.Errorf("expected to find 2 hits; got: %d", count)
+ }
+
+ // Iterate over ptr-type
+ count = 0
+ var aTweetPtr *tweet
+ for _, item := range searchResult.Each(reflect.TypeOf(aTweetPtr)) {
+ count++
+ tw, ok := item.(*tweet)
+ if !ok {
+ t.Fatalf("expected hit to be serialized as tweet; got: %v", reflect.ValueOf(item))
+ }
+ if tw != nil {
+ t.Fatal("expected hit to be nil")
+ }
+ }
+ if count != 2 {
+ t.Errorf("expected to find 2 hits; got: %d", count)
+ }
+}
+
+func TestSearchSorting(t *testing.T) {
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Match all should return all documents
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(all).
+ Sort("created", false).
+ Timeout("1s").
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+ if len(searchResult.Hits.Hits) != 3 {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ item := make(map[string]interface{})
+ err := json.Unmarshal(*hit.Source, &item)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+}
+
+func TestSearchSortingBySorters(t *testing.T) {
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Match all should return all documents
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(all).
+ SortBy(NewFieldSort("created").Desc(), NewScoreSort()).
+ Timeout("1s").
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+ if len(searchResult.Hits.Hits) != 3 {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ item := make(map[string]interface{})
+ err := json.Unmarshal(*hit.Source, &item)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+}
+
+func TestSearchSpecificFields(t *testing.T) {
+ // client := setupTestClientAndCreateIndexAndLog(t, SetTraceLog(log.New(os.Stdout, "", 0)))
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
+ tweet2 := tweet{User: "olivere", Message: "Another unrelated topic."}
+ tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."}
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Match all should return all documents
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(all).
+ StoredFields("message").
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+ if len(searchResult.Hits.Hits) != 3 {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ if hit.Source != nil {
+ t.Fatalf("expected SearchResult.Hits.Hit.Source to be nil; got: %q", hit.Source)
+ }
+ if hit.Fields == nil {
+ t.Fatal("expected SearchResult.Hits.Hit.Fields to be != nil")
+ }
+ field, found := hit.Fields["message"]
+ if !found {
+ t.Errorf("expected SearchResult.Hits.Hit.Fields[%s] to be found", "message")
+ }
+ fields, ok := field.([]interface{})
+ if !ok {
+ t.Errorf("expected []interface{}; got: %v", reflect.TypeOf(fields))
+ }
+ if len(fields) != 1 {
+ t.Errorf("expected a field with 1 entry; got: %d", len(fields))
+ }
+ message, ok := fields[0].(string)
+ if !ok {
+ t.Errorf("expected a string; got: %v", reflect.TypeOf(fields[0]))
+ }
+ if message == "" {
+ t.Errorf("expected a message; got: %q", message)
+ }
+ }
+}
+
+func TestSearchExplain(t *testing.T) {
+ client := setupTestClientAndCreateIndex(t)
+ // client := setupTestClientAndCreateIndex(t, SetTraceLog(log.New(os.Stdout, "", 0)))
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Match all should return all documents
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(all).
+ Explain(true).
+ Timeout("1s").
+ // Pretty(true).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+ if len(searchResult.Hits.Hits) != 3 {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 3, len(searchResult.Hits.Hits))
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Errorf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ if hit.Explanation == nil {
+ t.Fatal("expected search explanation")
+ }
+ if hit.Explanation.Value <= 0.0 {
+ t.Errorf("expected explanation value to be > 0.0; got: %v", hit.Explanation.Value)
+ }
+ if hit.Explanation.Description == "" {
+ t.Errorf("expected explanation description != %q; got: %q", "", hit.Explanation.Description)
+ }
+ }
+}
+
+func TestSearchSource(t *testing.T) {
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Set up the request JSON manually to pass to the search service via Source()
+ source := map[string]interface{}{
+ "query": map[string]interface{}{
+ "match_all": map[string]interface{}{},
+ },
+ }
+
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Source(source). // sets the JSON request
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+}
+
+func TestSearchRawString(t *testing.T) {
+ // client := setupTestClientAndCreateIndexAndLog(t, SetTraceLog(log.New(os.Stdout, "", 0)))
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ query := RawStringQuery(`{"match_all":{}}`)
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(query).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+}
+
+func TestSearchSearchSource(t *testing.T) {
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Set up the search source manually and pass it to the search service via SearchSource()
+ ss := NewSearchSource().Query(NewMatchAllQuery()).From(0).Size(2)
+
+ // One can use ss.Source() to get to the raw interface{} that will be used
+ // as the search request JSON by the SearchService.
+
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ SearchSource(ss). // sets the SearchSource
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+ if len(searchResult.Hits.Hits) != 2 {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 2, len(searchResult.Hits.Hits))
+ }
+}
+
+func TestSearchInnerHitsOnHasChild(t *testing.T) {
+ // client := setupTestClientAndCreateIndex(t, SetTraceLog(log.New(os.Stdout, "", 0)))
+ client := setupTestClientAndCreateIndex(t)
+
+ ctx := context.Background()
+
+ // Create join index
+ createIndex, err := client.CreateIndex(testJoinIndex).Body(testJoinMapping).Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if createIndex == nil {
+ t.Errorf("expected result to be != nil; got: %v", createIndex)
+ }
+
+ // Add documents
+ // See https://www.elastic.co/guide/en/elasticsearch/reference/6.0/parent-join.html for example code.
+ doc1 := joinDoc{
+ Message: "This is a question",
+ JoinField: &joinField{Name: "question"},
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("1").BodyJson(&doc1).Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ doc2 := joinDoc{
+ Message: "This is another question",
+ JoinField: "question",
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("2").BodyJson(&doc2).Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ doc3 := joinDoc{
+ Message: "This is an answer",
+ JoinField: &joinField{
+ Name: "answer",
+ Parent: "1",
+ },
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("3").BodyJson(&doc3).Routing("1").Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ doc4 := joinDoc{
+ Message: "This is another answer",
+ JoinField: &joinField{
+ Name: "answer",
+ Parent: "1",
+ },
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("4").BodyJson(&doc4).Routing("1").Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testJoinIndex).Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Search for all documents that have an answer, and return those answers as inner hits
+ bq := NewBoolQuery()
+ bq = bq.Must(NewMatchAllQuery())
+ bq = bq.Filter(NewHasChildQuery("answer", NewMatchAllQuery()).
+ InnerHit(NewInnerHit().Name("answers")))
+
+ searchResult, err := client.Search().
+ Index(testJoinIndex).
+ Query(bq).
+ Pretty(true).
+ Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 1 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 2, searchResult.Hits.TotalHits)
+ }
+ if len(searchResult.Hits.Hits) != 1 {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", 2, len(searchResult.Hits.Hits))
+ }
+
+ hit := searchResult.Hits.Hits[0]
+ if want, have := "1", hit.Id; want != have {
+ t.Fatalf("expected tweet %q; got: %q", want, have)
+ }
+ if hit.InnerHits == nil {
+ t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
+ }
+ if want, have := 1, len(hit.InnerHits); want != have {
+ t.Fatalf("expected %d inner hits; got: %d", want, have)
+ }
+ innerHits, found := hit.InnerHits["answers"]
+ if !found {
+ t.Fatalf("expected inner hits for name %q", "answers")
+ }
+ if innerHits == nil || innerHits.Hits == nil {
+ t.Fatal("expected inner hits != nil")
+ }
+ if want, have := 2, len(innerHits.Hits.Hits); want != have {
+ t.Fatalf("expected %d inner hits; got: %d", want, have)
+ }
+ if want, have := "3", innerHits.Hits.Hits[0].Id; want != have {
+ t.Fatalf("expected inner hit with id %q; got: %q", want, have)
+ }
+ if want, have := "4", innerHits.Hits.Hits[1].Id; want != have {
+ t.Fatalf("expected inner hit with id %q; got: %q", want, have)
+ }
+}
+
+func TestSearchInnerHitsOnHasParent(t *testing.T) {
+ // client := setupTestClientAndCreateIndex(t, SetTraceLog(log.New(os.Stdout, "", 0)))
+ client := setupTestClientAndCreateIndex(t)
+
+ ctx := context.Background()
+
+ // Create join index
+ createIndex, err := client.CreateIndex(testJoinIndex).Body(testJoinMapping).Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if createIndex == nil {
+ t.Errorf("expected result to be != nil; got: %v", createIndex)
+ }
+
+ // Add documents
+ // See https://www.elastic.co/guide/en/elasticsearch/reference/6.0/parent-join.html for example code.
+ doc1 := joinDoc{
+ Message: "This is a question",
+ JoinField: &joinField{Name: "question"},
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("1").BodyJson(&doc1).Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ doc2 := joinDoc{
+ Message: "This is another question",
+ JoinField: "question",
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("2").BodyJson(&doc2).Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ doc3 := joinDoc{
+ Message: "This is an answer",
+ JoinField: &joinField{
+ Name: "answer",
+ Parent: "1",
+ },
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("3").BodyJson(&doc3).Routing("1").Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ doc4 := joinDoc{
+ Message: "This is another answer",
+ JoinField: &joinField{
+ Name: "answer",
+ Parent: "1",
+ },
+ }
+ _, err = client.Index().Index(testJoinIndex).Type("doc").Id("4").BodyJson(&doc4).Routing("1").Refresh("true").Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testJoinIndex).Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Search for all documents that have an answer, and return those answers as inner hits
+ bq := NewBoolQuery()
+ bq = bq.Must(NewMatchAllQuery())
+ bq = bq.Filter(NewHasParentQuery("question", NewMatchAllQuery()).
+ InnerHit(NewInnerHit().Name("answers")))
+
+ searchResult, err := client.Search().
+ Index(testJoinIndex).
+ Query(bq).
+ Pretty(true).
+ Do(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if want, have := int64(2), searchResult.Hits.TotalHits; want != have {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, have)
+ }
+ if want, have := 2, len(searchResult.Hits.Hits); want != have {
+ t.Errorf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, have)
+ }
+
+ hit := searchResult.Hits.Hits[0]
+ if want, have := "3", hit.Id; want != have {
+ t.Fatalf("expected tweet %q; got: %q", want, have)
+ }
+ if hit.InnerHits == nil {
+ t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
+ }
+ if want, have := 1, len(hit.InnerHits); want != have {
+ t.Fatalf("expected %d inner hits; got: %d", want, have)
+ }
+ innerHits, found := hit.InnerHits["answers"]
+ if !found {
+ t.Fatalf("expected inner hits for name %q", "tweets")
+ }
+ if innerHits == nil || innerHits.Hits == nil {
+ t.Fatal("expected inner hits != nil")
+ }
+ if want, have := 1, len(innerHits.Hits.Hits); want != have {
+ t.Fatalf("expected %d inner hits; got: %d", want, have)
+ }
+ if want, have := "1", innerHits.Hits.Hits[0].Id; want != have {
+ t.Fatalf("expected inner hit with id %q; got: %q", want, have)
+ }
+
+ hit = searchResult.Hits.Hits[1]
+ if want, have := "4", hit.Id; want != have {
+ t.Fatalf("expected tweet %q; got: %q", want, have)
+ }
+ if hit.InnerHits == nil {
+ t.Fatalf("expected inner hits; got: %v", hit.InnerHits)
+ }
+ if want, have := 1, len(hit.InnerHits); want != have {
+ t.Fatalf("expected %d inner hits; got: %d", want, have)
+ }
+ innerHits, found = hit.InnerHits["answers"]
+ if !found {
+ t.Fatalf("expected inner hits for name %q", "tweets")
+ }
+ if innerHits == nil || innerHits.Hits == nil {
+ t.Fatal("expected inner hits != nil")
+ }
+ if want, have := 1, len(innerHits.Hits.Hits); want != have {
+ t.Fatalf("expected %d inner hits; got: %d", want, have)
+ }
+ if want, have := "1", innerHits.Hits.Hits[0].Id; want != have {
+ t.Fatalf("expected inner hit with id %q; got: %q", want, have)
+ }
+}
+
+func TestSearchBuildURL(t *testing.T) {
+ client := setupTestClient(t)
+
+ tests := []struct {
+ Indices []string
+ Types []string
+ Expected string
+ }{
+ {
+ []string{},
+ []string{},
+ "/_search",
+ },
+ {
+ []string{"index1"},
+ []string{},
+ "/index1/_search",
+ },
+ {
+ []string{"index1", "index2"},
+ []string{},
+ "/index1%2Cindex2/_search",
+ },
+ {
+ []string{},
+ []string{"type1"},
+ "/_all/type1/_search",
+ },
+ {
+ []string{"index1"},
+ []string{"type1"},
+ "/index1/type1/_search",
+ },
+ {
+ []string{"index1", "index2"},
+ []string{"type1", "type2"},
+ "/index1%2Cindex2/type1%2Ctype2/_search",
+ },
+ {
+ []string{},
+ []string{"type1", "type2"},
+ "/_all/type1%2Ctype2/_search",
+ },
+ }
+
+ for i, test := range tests {
+ path, _, err := client.Search().Index(test.Indices...).Type(test.Types...).buildURL()
+ if err != nil {
+ t.Errorf("case #%d: %v", i+1, err)
+ continue
+ }
+ if path != test.Expected {
+ t.Errorf("case #%d: expected %q; got: %q", i+1, test.Expected, path)
+ }
+ }
+}
+
+func TestSearchFilterPath(t *testing.T) {
+ // client := setupTestClientAndCreateIndexAndAddDocs(t, SetTraceLog(log.New(os.Stdout, "", log.LstdFlags)))
+ client := setupTestClientAndCreateIndexAndAddDocs(t)
+
+ // Match all should return all documents
+ all := NewMatchAllQuery()
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Type("doc").
+ Query(all).
+ FilterPath(
+ "took",
+ "hits.hits._id",
+ "hits.hits._source.user",
+ "hits.hits._source.message",
+ ).
+ Timeout("1s").
+ Pretty(true).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Fatalf("expected SearchResult.Hits != nil; got nil")
+ }
+ // 0 because it was filtered out
+ if want, got := int64(0), searchResult.Hits.TotalHits; want != got {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", want, got)
+ }
+ if want, got := 3, len(searchResult.Hits.Hits); want != got {
+ t.Fatalf("expected len(SearchResult.Hits.Hits) = %d; got %d", want, got)
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if want, got := "", hit.Index; want != got {
+ t.Fatalf("expected index %q, got %q", want, got)
+ }
+ item := make(map[string]interface{})
+ err := json.Unmarshal(*hit.Source, &item)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // user field
+ v, found := item["user"]
+ if !found {
+ t.Fatalf("expected SearchResult.Hits.Hit[%q] to be found", "user")
+ }
+ if v == "" {
+ t.Fatalf("expected user field, got %v (%T)", v, v)
+ }
+ // No retweets field
+ v, found = item["retweets"]
+ if found {
+ t.Fatalf("expected SearchResult.Hits.Hit[%q] to not be found, got %v", "retweets", v)
+ }
+ if v == "" {
+ t.Fatalf("expected user field, got %v (%T)", v, v)
+ }
+ }
+}
+
+func TestSearchAfter(t *testing.T) {
+ // client := setupTestClientAndCreateIndexAndLog(t, SetTraceLog(log.New(os.Stdout, "", 0)))
+ client := setupTestClientAndCreateIndex(t)
+
+ tweet1 := tweet{
+ User: "olivere", Retweets: 108,
+ Message: "Welcome to Golang and Elasticsearch.",
+ Created: time.Date(2012, 12, 12, 17, 38, 34, 0, time.UTC),
+ }
+ tweet2 := tweet{
+ User: "olivere", Retweets: 0,
+ Message: "Another unrelated topic.",
+ Created: time.Date(2012, 10, 10, 8, 12, 03, 0, time.UTC),
+ }
+ tweet3 := tweet{
+ User: "sandrae", Retweets: 12,
+ Message: "Cycling is fun.",
+ Created: time.Date(2011, 11, 11, 10, 58, 12, 0, time.UTC),
+ }
+
+ // Add all documents
+ _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = client.Flush().Index(testIndexName).Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Query(NewMatchAllQuery()).
+ SearchAfter("olivere").
+ Sort("user", true).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if searchResult.Hits == nil {
+ t.Errorf("expected SearchResult.Hits != nil; got nil")
+ }
+ if searchResult.Hits.TotalHits != 3 {
+ t.Errorf("expected SearchResult.Hits.TotalHits = %d; got %d", 3, searchResult.Hits.TotalHits)
+ }
+ if want, got := 1, len(searchResult.Hits.Hits); want != got {
+ t.Fatalf("expected len(SearchResult.Hits.Hits) = %d; got: %d", want, got)
+ }
+ hit := searchResult.Hits.Hits[0]
+ if want, got := "3", hit.Id; want != got {
+ t.Fatalf("expected tweet %q; got: %q", want, got)
+ }
+}
+
+func TestSearchResultWithFieldCollapsing(t *testing.T) {
+ client := setupTestClientAndCreateIndexAndAddDocs(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))
+
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Type("doc").
+ Query(NewMatchAllQuery()).
+ Collapse(NewCollapseBuilder("user")).
+ Pretty(true).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if searchResult.Hits == nil {
+ t.Fatalf("expected SearchResult.Hits != nil; got nil")
+ }
+ if got := searchResult.Hits.TotalHits; got == 0 {
+ t.Fatalf("expected SearchResult.Hits.TotalHits > 0; got %d", got)
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Fatalf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ item := make(map[string]interface{})
+ err := json.Unmarshal(*hit.Source, &item)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(hit.Fields) == 0 {
+ t.Fatal("expected fields in SearchResult")
+ }
+ usersVal, ok := hit.Fields["user"]
+ if !ok {
+ t.Fatalf("expected %q field in fields of SearchResult", "user")
+ }
+ users, ok := usersVal.([]interface{})
+ if !ok {
+ t.Fatalf("expected slice of strings in field of SearchResult, got %T", usersVal)
+ }
+ if len(users) != 1 {
+ t.Fatalf("expected 1 entry in users slice, got %d", len(users))
+ }
+ }
+}
+
+func TestSearchResultWithFieldCollapsingAndInnerHits(t *testing.T) {
+ client := setupTestClientAndCreateIndexAndAddDocs(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))
+
+ searchResult, err := client.Search().
+ Index(testIndexName).
+ Type("doc").
+ Query(NewMatchAllQuery()).
+ Collapse(
+ NewCollapseBuilder("user").
+ InnerHit(
+ NewInnerHit().Name("last_tweets").Size(5).Sort("created", true),
+ ).
+ MaxConcurrentGroupRequests(4)).
+ Pretty(true).
+ Do(context.TODO())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if searchResult.Hits == nil {
+ t.Fatalf("expected SearchResult.Hits != nil; got nil")
+ }
+ if got := searchResult.Hits.TotalHits; got == 0 {
+ t.Fatalf("expected SearchResult.Hits.TotalHits > 0; got %d", got)
+ }
+
+ for _, hit := range searchResult.Hits.Hits {
+ if hit.Index != testIndexName {
+ t.Fatalf("expected SearchResult.Hits.Hit.Index = %q; got %q", testIndexName, hit.Index)
+ }
+ item := make(map[string]interface{})
+ err := json.Unmarshal(*hit.Source, &item)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(hit.Fields) == 0 {
+ t.Fatal("expected fields in SearchResult")
+ }
+ usersVal, ok := hit.Fields["user"]
+ if !ok {
+ t.Fatalf("expected %q field in fields of SearchResult", "user")
+ }
+ users, ok := usersVal.([]interface{})
+ if !ok {
+ t.Fatalf("expected slice of strings in field of SearchResult, got %T", usersVal)
+ }
+ if len(users) != 1 {
+ t.Fatalf("expected 1 entry in users slice, got %d", len(users))
+ }
+ lastTweets, ok := hit.InnerHits["last_tweets"]
+ if !ok {
+ t.Fatalf("expected inner_hits named %q in SearchResult", "last_tweets")
+ }
+ if lastTweets == nil {
+ t.Fatal("expected inner_hits in SearchResult")
+ }
+ }
+}