diff --git a/.travis.yml.off b/.travis.yml.off index a944e7020..4f5446f95 100644 --- a/.travis.yml.off +++ b/.travis.yml.off @@ -12,5 +12,5 @@ services: - docker before_install: - sudo sysctl -w vm.max_map_count=262144 - - docker run --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:6.0.0-beta2 elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_ + - docker run --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:6.0.0-rc1 elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_ - sleep 30 diff --git a/CHANGELOG-6.0.md b/CHANGELOG-6.0.md index fd7637b60..277925929 100644 --- a/CHANGELOG-6.0.md +++ b/CHANGELOG-6.0.md @@ -12,35 +12,7 @@ Only use `true` or `false` for boolean values, not `0` or `1` or `on` or `off`. ## Single Type Indices -Notice that 6.0 will default to single type indices, i.e. you may not use multiple -types when e.g. adding an index with a mapping. - -To enable multiple indices, specify index.mapping.single_type : false. Example: - -``` -{ - "settings":{ - "number_of_shards":1, - "number_of_replicas":0, - "index.mapping.single_type" : false - }, - "mappings":{ - "tweet":{ - "properties":{ - ... - } - }, - "comment":{ - "_parent": { - "type": "tweet" - } - }, - "order":{ - "properties":{ - ... - } - } - } -} -``` +Notice that 6.0 and future versions will default to single type indices, i.e. you may not use multiple types when e.g. adding an index with a mapping. + +See [here for details](https://www.elastic.co/guide/en/elasticsearch/reference/6.x/removal-of-types.html#_what_are_mapping_types). diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e3f7a6432..fcdf38fbf 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -20,6 +20,7 @@ Andrew Dunham [@andrew-d](https://github.com/andrew-d) Andrew Gaul [@andrewgaul](https://github.com/andrewgaul) Andy Walker [@alaska](https://github.com/alaska) Arquivei [@arquivei](https://github.com/arquivei) +arthurgustin [@arthurgustin](https://github.com/arthurgustin) Benjamin Fernandes [@LotharSee](https://github.com/LotharSee) Benjamin Zarzycki [@kf6nux](https://github.com/kf6nux) Braden Bassingthwaite [@bbassingthwaite-va](https://github.com/bbassingthwaite-va) @@ -109,4 +110,5 @@ Wyndham Blanton [@wyndhblb](https://github.com/wyndhblb) Yarden Bar [@ayashjorden](https://github.com/ayashjorden) zakthomas [@zakthomas](https://github.com/zakthomas) singham [@zhaochenxiao90](https://github.com/zhaochenxiao90) +@林 [@zplzpl](https://github.com/zplzpl) Roman Colohanin [@zuzmic](https://github.com/zuzmic) diff --git a/README.md b/README.md index 462628f92..a8a8a1ebb 100644 --- a/README.md +++ b/README.md @@ -121,101 +121,9 @@ The client connects to Elasticsearch on `http://127.0.0.1:9200` by default. You typically create one client for your app. Here's a complete example of creating a client, creating an index, adding a document, executing a search etc. -```go -// Create a context -ctx := context.Background() - -// Create a client -client, err := elastic.NewClient() -if err != nil { - // Handle error - panic(err) -} - -// Create an index -_, err = client.CreateIndex("twitter").Do(ctx) -if err != nil { - // Handle error - panic(err) -} - -// Add a document to the index -tweet := Tweet{User: "olivere", Message: "Take Five"} -_, err = client.Index(). - Index("twitter"). - Type("tweet"). - Id("1"). - BodyJson(tweet). - Refresh("true"). - Do(ctx) -if err != nil { - // Handle error - panic(err) -} - -// Search with a term query -termQuery := elastic.NewTermQuery("user", "olivere") -searchResult, err := client.Search(). - Index("twitter"). // search in index "twitter" - Query(termQuery). // specify the query - Sort("user", true). // sort by "user" field, ascending - From(0).Size(10). // take documents 0-9 - Pretty(true). // pretty print request and response JSON - Do(ctx) // execute -if err != nil { - // Handle error - panic(err) -} - -// searchResult is of type SearchResult and returns hits, suggestions, -// and all kinds of other information from Elasticsearch. -fmt.Printf("Query took %d milliseconds\n", searchResult.TookInMillis) - -// Each is a convenience function that iterates over hits in a search result. -// It makes sure you don't need to check for nil values in the response. -// However, it ignores errors in serialization. If you want full control -// over iterating the hits, see below. -var ttyp Tweet -for _, item := range searchResult.Each(reflect.TypeOf(ttyp)) { - if t, ok := item.(Tweet); ok { - fmt.Printf("Tweet by %s: %s\n", t.User, t.Message) - } -} -// TotalHits is another convenience function that works even when something goes wrong. -fmt.Printf("Found a total of %d tweets\n", searchResult.TotalHits()) - -// Here's how you iterate through results with full control over each step. -if searchResult.Hits.TotalHits > 0 { - fmt.Printf("Found a total of %d tweets\n", searchResult.Hits.TotalHits) - - // Iterate through results - for _, hit := range searchResult.Hits.Hits { - // hit.Index contains the name of the index - - // Deserialize hit.Source into a Tweet (could also be just a map[string]interface{}). - var t Tweet - err := json.Unmarshal(*hit.Source, &t) - if err != nil { - // Deserialization failed - } - - // Work with tweet - fmt.Printf("Tweet by %s: %s\n", t.User, t.Message) - } -} else { - // No hits - fmt.Print("Found no tweets\n") -} - -// Delete the index again -_, err = client.DeleteIndex("twitter").Do(ctx) -if err != nil { - // Handle error - panic(err) -} -``` +An example is available [here](https://olivere.github.io/elastic/). -Here's a [link to a complete working example](https://gist.github.com/olivere/114347ff9d9cfdca7bdc0ecea8b82263). +Here's a [link to a complete working example for v3](https://gist.github.com/olivere/114347ff9d9cfdca7bdc0ecea8b82263). See the [wiki](https://github.com/olivere/elastic/wiki) for more details. diff --git a/bulk.go b/bulk.go index 5dfd55c2a..9772c85c7 100644 --- a/bulk.go +++ b/bulk.go @@ -234,7 +234,13 @@ func (s *BulkService) Do(ctx context.Context) (*BulkResponse, error) { } // Get response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + ContentType: "application/x-ndjson", + }) if err != nil { return nil, err } @@ -304,10 +310,12 @@ type BulkResponseItem struct { Type string `json:"_type,omitempty"` Id string `json:"_id,omitempty"` Version int64 `json:"_version,omitempty"` - Status int `json:"status,omitempty"` Result string `json:"result,omitempty"` + Shards *shardsInfo `json:"_shards,omitempty"` + SeqNo int64 `json:"_seq_no,omitempty"` + PrimaryTerm int64 `json:"_primary_term,omitempty"` + Status int `json:"status,omitempty"` ForcedRefresh bool `json:"forced_refresh,omitempty"` - Found bool `json:"found,omitempty"` Error *ErrorDetails `json:"error,omitempty"` } diff --git a/bulk_delete_request_test.go b/bulk_delete_request_test.go index 6ac429d8b..656992c01 100644 --- a/bulk_delete_request_test.go +++ b/bulk_delete_request_test.go @@ -15,23 +15,23 @@ func TestBulkDeleteRequestSerialization(t *testing.T) { }{ // #0 { - Request: NewBulkDeleteRequest().Index("index1").Type("tweet").Id("1"), + Request: NewBulkDeleteRequest().Index("index1").Type("doc").Id("1"), Expected: []string{ - `{"delete":{"_id":"1","_index":"index1","_type":"tweet"}}`, + `{"delete":{"_id":"1","_index":"index1","_type":"doc"}}`, }, }, // #1 { - Request: NewBulkDeleteRequest().Index("index1").Type("tweet").Id("1").Parent("2"), + Request: NewBulkDeleteRequest().Index("index1").Type("doc").Id("1").Parent("2"), Expected: []string{ - `{"delete":{"_id":"1","_index":"index1","_parent":"2","_type":"tweet"}}`, + `{"delete":{"_id":"1","_index":"index1","_parent":"2","_type":"doc"}}`, }, }, // #2 { - Request: NewBulkDeleteRequest().Index("index1").Type("tweet").Id("1").Routing("3"), + Request: NewBulkDeleteRequest().Index("index1").Type("doc").Id("1").Routing("3"), Expected: []string{ - `{"delete":{"_id":"1","_index":"index1","_routing":"3","_type":"tweet"}}`, + `{"delete":{"_id":"1","_index":"index1","_routing":"3","_type":"doc"}}`, }, }, } @@ -58,7 +58,7 @@ func TestBulkDeleteRequestSerialization(t *testing.T) { var bulkDeleteRequestSerializationResult string func BenchmarkBulkDeleteRequestSerialization(b *testing.B) { - r := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1") + r := NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1") var s string for n := 0; n < b.N; n++ { s = r.String() diff --git a/bulk_index_request_test.go b/bulk_index_request_test.go index fe95bd65c..ef4e8e8b0 100644 --- a/bulk_index_request_test.go +++ b/bulk_index_request_test.go @@ -16,55 +16,55 @@ func TestBulkIndexRequestSerialization(t *testing.T) { }{ // #0 { - Request: NewBulkIndexRequest().Index("index1").Type("tweet").Id("1"). + Request: NewBulkIndexRequest().Index("index1").Type("doc").Id("1"). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}), Expected: []string{ - `{"index":{"_id":"1","_index":"index1","_type":"tweet"}}`, + `{"index":{"_id":"1","_index":"index1","_type":"doc"}}`, `{"user":"olivere","message":"","retweets":0,"created":"2014-01-18T23:59:58Z"}`, }, }, // #1 { - Request: NewBulkIndexRequest().OpType("create").Index("index1").Type("tweet").Id("1"). + Request: NewBulkIndexRequest().OpType("create").Index("index1").Type("doc").Id("1"). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}), Expected: []string{ - `{"create":{"_id":"1","_index":"index1","_type":"tweet"}}`, + `{"create":{"_id":"1","_index":"index1","_type":"doc"}}`, `{"user":"olivere","message":"","retweets":0,"created":"2014-01-18T23:59:58Z"}`, }, }, // #2 { - Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("tweet").Id("1"). + Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("doc").Id("1"). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}), Expected: []string{ - `{"index":{"_id":"1","_index":"index1","_type":"tweet"}}`, + `{"index":{"_id":"1","_index":"index1","_type":"doc"}}`, `{"user":"olivere","message":"","retweets":0,"created":"2014-01-18T23:59:58Z"}`, }, }, // #3 { - Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("tweet").Id("1").RetryOnConflict(42). + Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("doc").Id("1").RetryOnConflict(42). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}), Expected: []string{ - `{"index":{"_id":"1","_index":"index1","_retry_on_conflict":42,"_type":"tweet"}}`, + `{"index":{"_id":"1","_index":"index1","_retry_on_conflict":42,"_type":"doc"}}`, `{"user":"olivere","message":"","retweets":0,"created":"2014-01-18T23:59:58Z"}`, }, }, // #4 { - Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("tweet").Id("1").Pipeline("my_pipeline"). + Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("doc").Id("1").Pipeline("my_pipeline"). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}), Expected: []string{ - `{"index":{"_id":"1","_index":"index1","_type":"tweet","pipeline":"my_pipeline"}}`, + `{"index":{"_id":"1","_index":"index1","_type":"doc","pipeline":"my_pipeline"}}`, `{"user":"olivere","message":"","retweets":0,"created":"2014-01-18T23:59:58Z"}`, }, }, // #5 { - Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("tweet").Id("1").TTL("1m"). + Request: NewBulkIndexRequest().OpType("index").Index("index1").Type("doc").Id("1").TTL("1m"). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}), Expected: []string{ - `{"index":{"_id":"1","_index":"index1","_ttl":"1m","_type":"tweet"}}`, + `{"index":{"_id":"1","_index":"index1","_ttl":"1m","_type":"doc"}}`, `{"user":"olivere","message":"","retweets":0,"created":"2014-01-18T23:59:58Z"}`, }, }, @@ -92,7 +92,7 @@ func TestBulkIndexRequestSerialization(t *testing.T) { var bulkIndexRequestSerializationResult string func BenchmarkBulkIndexRequestSerialization(b *testing.B) { - r := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1"). + r := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1"). Doc(tweet{User: "olivere", Created: time.Date(2014, 1, 18, 23, 59, 58, 0, time.UTC)}) var s string for n := 0; n < b.N; n++ { diff --git a/bulk_processor_test.go b/bulk_processor_test.go index a47e99652..13dc277d0 100644 --- a/bulk_processor_test.go +++ b/bulk_processor_test.go @@ -126,7 +126,7 @@ func TestBulkProcessorBasedOnFlushInterval(t *testing.T) { for i := 1; i <= numDocs; i++ { tweet := tweet{User: "olivere", Message: fmt.Sprintf("%d. %s", i, randomString(rand.Intn(64)))} - request := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id(fmt.Sprintf("%d", i)).Doc(tweet) + request := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id(fmt.Sprintf("%d", i)).Doc(tweet) p.Add(request) } @@ -209,7 +209,7 @@ func TestBulkProcessorClose(t *testing.T) { for i := 1; i <= numDocs; i++ { tweet := tweet{User: "olivere", Message: fmt.Sprintf("%d. %s", i, randomString(rand.Intn(64)))} - request := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id(fmt.Sprintf("%d", i)).Doc(tweet) + request := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id(fmt.Sprintf("%d", i)).Doc(tweet) p.Add(request) } @@ -275,7 +275,7 @@ func TestBulkProcessorFlush(t *testing.T) { for i := 1; i <= numDocs; i++ { tweet := tweet{User: "olivere", Message: fmt.Sprintf("%d. %s", i, randomString(rand.Intn(64)))} - request := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id(fmt.Sprintf("%d", i)).Doc(tweet) + request := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id(fmt.Sprintf("%d", i)).Doc(tweet) p.Add(request) } @@ -356,7 +356,7 @@ func testBulkProcessor(t *testing.T, numDocs int, svc *BulkProcessorService) { for i := 1; i <= numDocs; i++ { tweet := tweet{User: "olivere", Message: fmt.Sprintf("%07d. %s", i, randomString(1+rand.Intn(63)))} - request := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id(fmt.Sprintf("%d", i)).Doc(tweet) + request := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id(fmt.Sprintf("%d", i)).Doc(tweet) p.Add(request) } diff --git a/bulk_test.go b/bulk_test.go index fba52be73..b2c29f482 100644 --- a/bulk_test.go +++ b/bulk_test.go @@ -7,6 +7,9 @@ package elastic import ( "context" "encoding/json" + "fmt" + "net/http" + "net/http/httptest" "testing" ) @@ -16,9 +19,9 @@ func TestBulk(t *testing.T) { tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."} - index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1) - index2Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("2").Doc(tweet2) - delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1") + index1Req := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(tweet1) + index2Req := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("2").Doc(tweet2) + delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1") bulkRequest := client.Bulk() bulkRequest = bulkRequest.Add(index1Req) @@ -42,7 +45,7 @@ func TestBulk(t *testing.T) { } // Document with Id="1" should not exist - exists, err := client.Exists().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + exists, err := client.Exists().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -51,7 +54,7 @@ func TestBulk(t *testing.T) { } // Document with Id="2" should exist - exists, err = client.Exists().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO()) + exists, err = client.Exists().Index(testIndexName).Type("doc").Id("2").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -65,7 +68,7 @@ func TestBulk(t *testing.T) { }{ 42, } - update1Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2").Doc(&updateDoc) + update1Req := NewBulkUpdateRequest().Index(testIndexName).Type("doc").Id("2").Doc(&updateDoc) bulkRequest = client.Bulk() bulkRequest = bulkRequest.Add(update1Req) @@ -86,7 +89,7 @@ func TestBulk(t *testing.T) { } // Document with Id="1" should have a retweets count of 42 - doc, err := client.Get().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO()) + doc, err := client.Get().Index(testIndexName).Type("doc").Id("2").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -109,7 +112,7 @@ func TestBulk(t *testing.T) { } // Update with script - update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2"). + update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("doc").Id("2"). RetryOnConflict(3). Script(NewScript("ctx._source.retweets += params.v").Param("v", 1)) bulkRequest = client.Bulk() @@ -130,7 +133,7 @@ func TestBulk(t *testing.T) { } // Document with Id="1" should have a retweets count of 43 - doc, err = client.Get().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO()) + doc, err = client.Get().Index(testIndexName).Type("doc").Id("2").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -158,11 +161,11 @@ func TestBulkWithIndexSetOnClient(t *testing.T) { tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."} - index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1) - index2Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("2").Doc(tweet2) - delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1") + index1Req := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(tweet1) + index2Req := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("2").Doc(tweet2) + delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1") - bulkRequest := client.Bulk().Index(testIndexName).Type("tweet") + bulkRequest := client.Bulk().Index(testIndexName).Type("doc") bulkRequest = bulkRequest.Add(index1Req) bulkRequest = bulkRequest.Add(index2Req) bulkRequest = bulkRequest.Add(delete1Req) @@ -180,7 +183,7 @@ func TestBulkWithIndexSetOnClient(t *testing.T) { } // Document with Id="1" should not exist - exists, err := client.Exists().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + exists, err := client.Exists().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -189,7 +192,7 @@ func TestBulkWithIndexSetOnClient(t *testing.T) { } // Document with Id="2" should exist - exists, err = client.Exists().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO()) + exists, err = client.Exists().Index(testIndexName).Type("doc").Id("2").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -204,10 +207,10 @@ func TestBulkRequestsSerialization(t *testing.T) { tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."} - index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1) - index2Req := NewBulkIndexRequest().OpType("create").Index(testIndexName).Type("tweet").Id("2").Doc(tweet2) - delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1") - update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2"). + index1Req := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(tweet1) + index2Req := NewBulkIndexRequest().OpType("create").Index(testIndexName).Type("doc").Id("2").Doc(tweet2) + delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1") + update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("doc").Id("2"). Doc(struct { Retweets int `json:"retweets"` }{ @@ -224,12 +227,12 @@ func TestBulkRequestsSerialization(t *testing.T) { t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 4, bulkRequest.NumberOfActions()) } - expected := `{"index":{"_id":"1","_index":"` + testIndexName + `","_type":"tweet"}} + expected := `{"index":{"_id":"1","_index":"` + testIndexName + `","_type":"doc"}} {"user":"olivere","message":"Welcome to Golang and Elasticsearch.","retweets":0,"created":"0001-01-01T00:00:00Z"} -{"create":{"_id":"2","_index":"` + testIndexName + `","_type":"tweet"}} +{"create":{"_id":"2","_index":"` + testIndexName + `","_type":"doc"}} {"user":"sandrae","message":"Dancing all night long. Yeah.","retweets":0,"created":"0001-01-01T00:00:00Z"} -{"delete":{"_id":"1","_index":"` + testIndexName + `","_type":"tweet"}} -{"update":{"_id":"2","_index":"` + testIndexName + `","_type":"tweet"}} +{"delete":{"_id":"1","_index":"` + testIndexName + `","_type":"doc"}} +{"update":{"_id":"2","_index":"` + testIndexName + `","_type":"doc"}} {"doc":{"retweets":42}} ` got, err := bulkRequest.bodyAsString() @@ -241,7 +244,7 @@ func TestBulkRequestsSerialization(t *testing.T) { } // Run the bulk request - bulkResponse, err := bulkRequest.Do(context.TODO()) + bulkResponse, err := bulkRequest.Pretty(true).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -287,6 +290,9 @@ func TestBulkRequestsSerialization(t *testing.T) { if created[0].Status != 201 { t.Errorf("expected created[0].Status == %d; got %d", 201, created[0].Status) } + if want, have := "created", created[0].Result; want != have { + t.Errorf("expected created[0].Result == %q; got %q", want, have) + } // Deleted actions deleted := bulkResponse.Deleted() @@ -302,8 +308,8 @@ func TestBulkRequestsSerialization(t *testing.T) { if deleted[0].Status != 200 { t.Errorf("expected deleted[0].Status == %d; got %d", 200, deleted[0].Status) } - if !deleted[0].Found { - t.Errorf("expected deleted[0].Found == %v; got %v", true, deleted[0].Found) + if want, have := "deleted", deleted[0].Result; want != have { + t.Errorf("expected deleted[0].Result == %q; got %q", want, have) } // Updated actions @@ -323,6 +329,9 @@ func TestBulkRequestsSerialization(t *testing.T) { if updated[0].Version != 2 { t.Errorf("expected updated[0].Version == %d; got %d", 2, updated[0].Version) } + if want, have := "updated", updated[0].Result; want != have { + t.Errorf("expected updated[0].Result == %q; got %q", want, have) + } // Succeeded actions succeeded := bulkResponse.Succeeded() @@ -368,7 +377,7 @@ func TestFailedBulkRequests(t *testing.T) { "items" : [ { "index" : { "_index" : "elastic-test", - "_type" : "tweet", + "_type" : "doc", "_id" : "1", "_version" : 1, "status" : 201 @@ -376,7 +385,7 @@ func TestFailedBulkRequests(t *testing.T) { }, { "create" : { "_index" : "elastic-test", - "_type" : "tweet", + "_type" : "doc", "_id" : "2", "_version" : 1, "status" : 423, @@ -388,7 +397,7 @@ func TestFailedBulkRequests(t *testing.T) { }, { "delete" : { "_index" : "elastic-test", - "_type" : "tweet", + "_type" : "doc", "_id" : "1", "_version" : 2, "status" : 404, @@ -397,7 +406,7 @@ func TestFailedBulkRequests(t *testing.T) { }, { "update" : { "_index" : "elastic-test", - "_type" : "tweet", + "_type" : "doc", "_id" : "2", "_version" : 2, "status" : 200 @@ -422,10 +431,10 @@ func TestBulkEstimatedSizeInBytes(t *testing.T) { tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."} - index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1) - index2Req := NewBulkIndexRequest().OpType("create").Index(testIndexName).Type("tweet").Id("2").Doc(tweet2) - delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1") - update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2"). + index1Req := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(tweet1) + index2Req := NewBulkIndexRequest().OpType("create").Index(testIndexName).Type("doc").Id("2").Doc(tweet2) + delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1") + update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("doc").Id("2"). Doc(struct { Retweets int `json:"retweets"` }{ @@ -465,7 +474,7 @@ func TestBulkEstimatedSizeInBytes(t *testing.T) { func TestBulkEstimateSizeInBytesLength(t *testing.T) { client := setupTestClientAndCreateIndex(t) s := client.Bulk() - r := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1") + r := NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1") s = s.Add(r) if got, want := s.estimateSizeInBytes(r), int64(1+len(r.String())); got != want { t.Fatalf("expected %d; got: %d", want, got) @@ -479,9 +488,9 @@ func BenchmarkBulkEstimatedSizeInBytesWith1Request(b *testing.B) { s := client.Bulk() var result int64 for n := 0; n < b.N; n++ { - s = s.Add(NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"1"})) - s = s.Add(NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"2"})) - s = s.Add(NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")) + s = s.Add(NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(struct{ A string }{"1"})) + s = s.Add(NewBulkUpdateRequest().Index(testIndexName).Type("doc").Id("1").Doc(struct{ A string }{"2"})) + s = s.Add(NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1")) result = s.EstimatedSizeInBytes() s.reset() } @@ -495,9 +504,9 @@ func BenchmarkBulkEstimatedSizeInBytesWith100Requests(b *testing.B) { var result int64 for n := 0; n < b.N; n++ { for i := 0; i < 100; i++ { - s = s.Add(NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"1"})) - s = s.Add(NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"2"})) - s = s.Add(NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")) + s = s.Add(NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(struct{ A string }{"1"})) + s = s.Add(NewBulkUpdateRequest().Index(testIndexName).Type("doc").Id("1").Doc(struct{ A string }{"2"})) + s = s.Add(NewBulkDeleteRequest().Index(testIndexName).Type("doc").Id("1")) } result = s.EstimatedSizeInBytes() s.reset() @@ -505,3 +514,27 @@ func BenchmarkBulkEstimatedSizeInBytesWith100Requests(b *testing.B) { b.ReportAllocs() benchmarkBulkEstimatedSizeInBytes = result // ensure the compiler doesn't optimize } + +func TestBulkContentType(t *testing.T) { + var header http.Header + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + header = r.Header + fmt.Fprintln(w, `{}`) + })) + defer ts.Close() + + client, err := NewSimpleClient(SetURL(ts.URL)) + if err != nil { + t.Fatal(err) + } + indexReq := NewBulkIndexRequest().Index(testIndexName).Type("doc").Id("1").Doc(tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}) + if _, err := client.Bulk().Add(indexReq).Do(context.Background()); err != nil { + t.Fatal(err) + } + if header == nil { + t.Fatalf("expected header, got %v", header) + } + if want, have := "application/x-ndjson", header.Get("Content-Type"); want != have { + t.Fatalf("Content-Type: want %q, have %q", want, have) + } +} diff --git a/bulk_update_request_test.go b/bulk_update_request_test.go index afe873890..aca31cbfb 100644 --- a/bulk_update_request_test.go +++ b/bulk_update_request_test.go @@ -15,19 +15,19 @@ func TestBulkUpdateRequestSerialization(t *testing.T) { }{ // #0 { - Request: NewBulkUpdateRequest().Index("index1").Type("tweet").Id("1").Doc(struct { + Request: NewBulkUpdateRequest().Index("index1").Type("doc").Id("1").Doc(struct { Counter int64 `json:"counter"` }{ Counter: 42, }), Expected: []string{ - `{"update":{"_id":"1","_index":"index1","_type":"tweet"}}`, + `{"update":{"_id":"1","_index":"index1","_type":"doc"}}`, `{"doc":{"counter":42}}`, }, }, // #1 { - Request: NewBulkUpdateRequest().Index("index1").Type("tweet").Id("1"). + Request: NewBulkUpdateRequest().Index("index1").Type("doc").Id("1"). RetryOnConflict(3). DocAsUpsert(true). Doc(struct { @@ -36,13 +36,13 @@ func TestBulkUpdateRequestSerialization(t *testing.T) { Counter: 42, }), Expected: []string{ - `{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"tweet"}}`, + `{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"doc"}}`, `{"doc":{"counter":42},"doc_as_upsert":true}`, }, }, // #2 { - Request: NewBulkUpdateRequest().Index("index1").Type("tweet").Id("1"). + Request: NewBulkUpdateRequest().Index("index1").Type("doc").Id("1"). RetryOnConflict(3). Script(NewScript(`ctx._source.retweets += param1`).Lang("javascript").Param("param1", 42)). Upsert(struct { @@ -51,25 +51,25 @@ func TestBulkUpdateRequestSerialization(t *testing.T) { Counter: 42, }), Expected: []string{ - `{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"tweet"}}`, + `{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"doc"}}`, `{"script":{"inline":"ctx._source.retweets += param1","lang":"javascript","params":{"param1":42}},"upsert":{"counter":42}}`, }, }, // #3 { - Request: NewBulkUpdateRequest().Index("index1").Type("tweet").Id("1").DetectNoop(true).Doc(struct { + Request: NewBulkUpdateRequest().Index("index1").Type("doc").Id("1").DetectNoop(true).Doc(struct { Counter int64 `json:"counter"` }{ Counter: 42, }), Expected: []string{ - `{"update":{"_id":"1","_index":"index1","_type":"tweet"}}`, + `{"update":{"_id":"1","_index":"index1","_type":"doc"}}`, `{"detect_noop":true,"doc":{"counter":42}}`, }, }, // #4 { - Request: NewBulkUpdateRequest().Index("index1").Type("tweet").Id("1"). + Request: NewBulkUpdateRequest().Index("index1").Type("doc").Id("1"). RetryOnConflict(3). ScriptedUpsert(true). Script(NewScript(`ctx._source.retweets += param1`).Lang("javascript").Param("param1", 42)). @@ -79,7 +79,7 @@ func TestBulkUpdateRequestSerialization(t *testing.T) { Counter: 42, }), Expected: []string{ - `{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"tweet"}}`, + `{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"doc"}}`, `{"script":{"inline":"ctx._source.retweets += param1","lang":"javascript","params":{"param1":42}},"scripted_upsert":true,"upsert":{"counter":42}}`, }, }, @@ -107,7 +107,7 @@ func TestBulkUpdateRequestSerialization(t *testing.T) { var bulkUpdateRequestSerializationResult string func BenchmarkBulkUpdateRequestSerialization(b *testing.B) { - r := NewBulkUpdateRequest().Index("index1").Type("tweet").Id("1").Doc(struct { + r := NewBulkUpdateRequest().Index("index1").Type("doc").Id("1").Doc(struct { Counter int64 `json:"counter"` }{ Counter: 42, diff --git a/clear_scroll.go b/clear_scroll.go index 1062647d6..32d9479ef 100644 --- a/clear_scroll.go +++ b/clear_scroll.go @@ -85,7 +85,12 @@ func (s *ClearScrollService) Do(ctx context.Context) (*ClearScrollResponse, erro } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/clear_scroll_test.go b/clear_scroll_test.go index 56a9d936c..4037d3cd6 100644 --- a/clear_scroll_test.go +++ b/clear_scroll_test.go @@ -19,17 +19,17 @@ func TestClearScroll(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/client.go b/client.go index d376811e2..31f79f28c 100644 --- a/client.go +++ b/client.go @@ -26,7 +26,7 @@ import ( const ( // Version is the current version of Elastic. - Version = "6.0.0-beta2" + Version = "6.0.0-rc1" // DefaultURL is the default endpoint of Elasticsearch on the local machine. // It is used e.g. when initializing a new Client without a specific URL. @@ -1167,13 +1167,25 @@ func (c *Client) mustActiveConn() error { return errors.Wrap(ErrNoClient, "no active connection found") } +// -- PerformRequest -- + +// PerformRequestOptions must be passed into PerformRequest. +type PerformRequestOptions struct { + Method string + Path string + Params url.Values + Body interface{} + ContentType string + IgnoreErrors []int +} + // PerformRequest does a HTTP request to Elasticsearch. // It returns a response (which might be nil) and an error on failure. // // Optionally, a list of HTTP error codes to ignore can be passed. // This is necessary for services that expect e.g. HTTP status 404 as a // valid outcome (Exists, IndicesExists, IndicesTypeExists). -func (c *Client) PerformRequest(ctx context.Context, method, path string, params url.Values, body interface{}, ignoreErrors ...int) (*Response, error) { +func (c *Client) PerformRequest(ctx context.Context, opt PerformRequestOptions) (*Response, error) { start := time.Now().UTC() c.mu.RLock() @@ -1193,14 +1205,14 @@ func (c *Client) PerformRequest(ctx context.Context, method, path string, params var n int // Change method if sendGetBodyAs is specified. - if method == "GET" && body != nil && sendGetBodyAs != "GET" { - method = sendGetBodyAs + if opt.Method == "GET" && opt.Body != nil && sendGetBodyAs != "GET" { + opt.Method = sendGetBodyAs } for { - pathWithParams := path - if len(params) > 0 { - pathWithParams += "?" + params.Encode() + pathWithParams := opt.Path + if len(opt.Params) > 0 { + pathWithParams += "?" + opt.Params.Encode() } // Get a connection @@ -1227,21 +1239,24 @@ func (c *Client) PerformRequest(ctx context.Context, method, path string, params return nil, err } - req, err = NewRequest(method, conn.URL()+pathWithParams) + req, err = NewRequest(opt.Method, conn.URL()+pathWithParams) if err != nil { - c.errorf("elastic: cannot create request for %s %s: %v", strings.ToUpper(method), conn.URL()+pathWithParams, err) + c.errorf("elastic: cannot create request for %s %s: %v", strings.ToUpper(opt.Method), conn.URL()+pathWithParams, err) return nil, err } if basicAuth { req.SetBasicAuth(basicAuthUsername, basicAuthPassword) } + if opt.ContentType != "" { + req.Header.Set("Content-Type", opt.ContentType) + } // Set body - if body != nil { - err = req.SetBody(body, gzipEnabled) + if opt.Body != nil { + err = req.SetBody(opt.Body, gzipEnabled) if err != nil { - c.errorf("elastic: couldn't set body %+v for request: %v", body, err) + c.errorf("elastic: couldn't set body %+v for request: %v", opt.Body, err) return nil, err } } @@ -1287,7 +1302,7 @@ func (c *Client) PerformRequest(ctx context.Context, method, path string, params c.dumpResponse(res) // Check for errors - if err := checkResponse((*http.Request)(req), res, ignoreErrors...); err != nil { + if err := checkResponse((*http.Request)(req), res, opt.IgnoreErrors...); err != nil { // No retry if request succeeded // We still try to return a response. resp, _ = c.newResponse(res) @@ -1307,7 +1322,7 @@ func (c *Client) PerformRequest(ctx context.Context, method, path string, params duration := time.Now().UTC().Sub(start) c.infof("%s %s [status:%d, request:%.3fs]", - strings.ToUpper(method), + strings.ToUpper(opt.Method), req.URL, resp.StatusCode, float64(int64(duration/time.Millisecond))/1000) diff --git a/client_test.go b/client_test.go index 6caf7b797..3eb73a4e8 100644 --- a/client_test.go +++ b/client_test.go @@ -873,7 +873,10 @@ func TestPerformRequest(t *testing.T) { if err != nil { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + }) if err != nil { t.Fatal(err) } @@ -895,7 +898,10 @@ func TestPerformRequestWithSimpleClient(t *testing.T) { if err != nil { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + }) if err != nil { t.Fatal(err) } @@ -921,7 +927,10 @@ func TestPerformRequestWithLogger(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + }) if err != nil { t.Fatal(err) } @@ -960,7 +969,10 @@ func TestPerformRequestWithLoggerAndTracer(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + }) if err != nil { t.Fatal(err) } @@ -995,7 +1007,10 @@ func TestPerformRequestWithTracerOnError(t *testing.T) { t.Fatal(err) } - client.PerformRequest(context.TODO(), "GET", "/no-such-index", nil, nil) + client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/no-such-index", + }) tgot := tw.String() if tgot == "" { @@ -1019,7 +1034,10 @@ func TestPerformRequestWithCustomLogger(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + }) if err != nil { t.Fatal(err) } @@ -1082,7 +1100,10 @@ func TestPerformRequestRetryOnHttpError(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/fail", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/fail", + }) if err == nil { t.Fatal("expected error") } @@ -1112,7 +1133,10 @@ func TestPerformRequestNoRetryOnValidButUnsuccessfulHttpStatus(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/fail", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/fail", + }) if err == nil { t.Fatal("expected error") } @@ -1141,7 +1165,11 @@ func TestPerformRequestWithSetBodyError(t *testing.T) { if err != nil { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, failingBody{}) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + Body: failingBody{}, + }) if err == nil { t.Fatal("expected error") } @@ -1178,7 +1206,10 @@ func TestPerformRequestWithCancel(t *testing.T) { resc := make(chan result, 1) go func() { - res, err := client.PerformRequest(ctx, "GET", "/", nil, nil) + res, err := client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: "/", + }) resc <- result{res: res, err: err} }() select { @@ -1213,7 +1244,10 @@ func TestPerformRequestWithTimeout(t *testing.T) { resc := make(chan result, 1) go func() { - res, err := client.PerformRequest(ctx, "GET", "/", nil, nil) + res, err := client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: "/", + }) resc <- result{res: res, err: err} }() select { @@ -1261,7 +1295,10 @@ func testPerformRequestWithCompression(t *testing.T, hc *http.Client) { if err != nil { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/", + }) if err != nil { t.Fatal(err) } diff --git a/cluster_health.go b/cluster_health.go index 4a031479b..2484605e2 100644 --- a/cluster_health.go +++ b/cluster_health.go @@ -179,7 +179,11 @@ func (s *ClusterHealthService) Do(ctx context.Context) (*ClusterHealthResponse, } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/cluster_state.go b/cluster_state.go index 180bd6d73..f1552044d 100644 --- a/cluster_state.go +++ b/cluster_state.go @@ -165,7 +165,11 @@ func (s *ClusterStateService) Do(ctx context.Context) (*ClusterStateResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/cluster_stats.go b/cluster_stats.go index bba766bdd..6d89c4eae 100644 --- a/cluster_stats.go +++ b/cluster_stats.go @@ -108,7 +108,11 @@ func (s *ClusterStatsService) Do(ctx context.Context) (*ClusterStatsResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/count.go b/count.go index b9a22ade2..dfcafed4a 100644 --- a/count.go +++ b/count.go @@ -286,7 +286,12 @@ func (s *CountService) Do(ctx context.Context) (int64, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return 0, err } diff --git a/count_test.go b/count_test.go index dd2b7556f..a0ee52112 100644 --- a/count_test.go +++ b/count_test.go @@ -58,17 +58,17 @@ func TestCount(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -88,7 +88,7 @@ func TestCount(t *testing.T) { } // Count documents - count, err = client.Count(testIndexName).Type("tweet").Do(context.TODO()) + count, err = client.Count(testIndexName).Type("doc").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -117,7 +117,7 @@ func TestCount(t *testing.T) { // Count with query and type query = NewTermQuery("user", "olivere") - count, err = client.Count(testIndexName).Type("tweet").Query(query).Do(context.TODO()) + count, err = client.Count(testIndexName).Type("doc").Query(query).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/decoder_test.go b/decoder_test.go index 15263fb8d..2c3dde8ca 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -34,7 +34,7 @@ func TestDecoder(t *testing.T) { // Add a document indexResult, err := client.Index(). Index(testIndexName). - Type("tweet"). + Type("doc"). Id("1"). BodyJson(&tweet). Do(context.TODO()) diff --git a/delete.go b/delete.go index 119e16a8c..74cdfb7c6 100644 --- a/delete.go +++ b/delete.go @@ -185,7 +185,12 @@ func (s *DeleteService) Do(ctx context.Context) (*DeleteResponse, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, nil, http.StatusNotFound) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + IgnoreErrors: []int{http.StatusNotFound}, + }) if err != nil { return nil, err } @@ -208,12 +213,14 @@ func (s *DeleteService) Do(ctx context.Context) (*DeleteResponse, error) { // DeleteResponse is the outcome of running DeleteService.Do. type DeleteResponse struct { - Index string `json:"_index"` - Type string `json:"_type"` - Id string `json:"_id"` - Version int64 `json:"_version"` - Shards *shardsInfo `json:"_shards"` + Index string `json:"_index,omitempty"` + Type string `json:"_type,omitempty"` + Id string `json:"_id,omitempty"` + Version int64 `json:"_version,omitempty"` Result string `json:"result,omitempty"` + Shards *shardsInfo `json:"_shards,omitempty"` + SeqNo int64 `json:"_seq_no,omitempty"` + PrimaryTerm int64 `json:"_primary_term,omitempty"` + Status int `json:"status,omitempty"` ForcedRefresh bool `json:"forced_refresh,omitempty"` - Found bool `json:"found"` } diff --git a/delete_by_query.go b/delete_by_query.go index ba9cb0b51..e7903190d 100644 --- a/delete_by_query.go +++ b/delete_by_query.go @@ -598,7 +598,12 @@ func (s *DeleteByQueryService) Do(ctx context.Context) (*BulkIndexByScrollRespon } // Get response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/delete_by_query_test.go b/delete_by_query_test.go index 9208ebce3..40e45b871 100644 --- a/delete_by_query_test.go +++ b/delete_by_query_test.go @@ -87,17 +87,17 @@ func TestDeleteByQuery(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -120,7 +120,7 @@ func TestDeleteByQuery(t *testing.T) { q := NewTermQuery("user", "sandrae") res, err := client.DeleteByQuery(). Index(testIndexName). - Type("tweet"). + Type("doc"). Query(q). Pretty(true). Do(context.TODO()) diff --git a/delete_template.go b/delete_template.go index 8cd578d9c..a312fc238 100644 --- a/delete_template.go +++ b/delete_template.go @@ -95,7 +95,11 @@ func (s *DeleteTemplateService) Do(ctx context.Context) (*AcknowledgedResponse, } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/delete_test.go b/delete_test.go index 1daf5499d..571fcf589 100644 --- a/delete_test.go +++ b/delete_test.go @@ -17,17 +17,17 @@ func TestDelete(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -47,12 +47,12 @@ func TestDelete(t *testing.T) { } // Delete document 1 - res, err := client.Delete().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + res, err := client.Delete().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } - if res.Found != true { - t.Errorf("expected Found = true; got %v", res.Found) + if want, have := "deleted", res.Result; want != have { + t.Errorf("expected Result = %q; got %q", want, have) } _, err = client.Flush().Index(testIndexName).Do(context.TODO()) if err != nil { @@ -67,7 +67,7 @@ func TestDelete(t *testing.T) { } // Delete non existent document 99 - res, err = client.Delete().Index(testIndexName).Type("tweet").Id("99").Refresh("true").Do(context.TODO()) + res, err = client.Delete().Index(testIndexName).Type("doc").Id("99").Refresh("true").Do(context.TODO()) if err == nil { t.Fatal("expected error") } @@ -80,20 +80,17 @@ func TestDelete(t *testing.T) { if res == nil { t.Fatal("expected response") } - if res.Found { - t.Errorf("expected Found = false; got %v", res.Found) - } if have, want := res.Id, "99"; have != want { t.Errorf("expected _id = %q, got %q", have, want) } if have, want := res.Index, testIndexName; have != want { t.Errorf("expected _index = %q, got %q", have, want) } - if have, want := res.Type, "tweet"; have != want { + if have, want := res.Type, "doc"; have != want { t.Errorf("expected _type = %q, got %q", have, want) } if have, want := res.Result, "not_found"; have != want { - t.Errorf("expected result = %q, got %q", have, want) + t.Errorf("expected Result = %q, got %q", have, want) } count, err = client.Count(testIndexName).Do(context.TODO()) @@ -109,7 +106,7 @@ func TestDeleteValidate(t *testing.T) { client := setupTestClientAndCreateIndexAndAddDocs(t) // No index name -> fail with error - res, err := NewDeleteService(client).Type("tweet").Id("1").Do(context.TODO()) + res, err := NewDeleteService(client).Type("doc").Id("1").Do(context.TODO()) if err == nil { t.Fatalf("expected Delete to fail without index name") } @@ -127,7 +124,7 @@ func TestDeleteValidate(t *testing.T) { } // No id -> fail with error - res, err = NewDeleteService(client).Index(testIndexName).Type("tweet").Do(context.TODO()) + res, err = NewDeleteService(client).Index(testIndexName).Type("doc").Do(context.TODO()) if err == nil { t.Fatalf("expected Delete to fail without id") } diff --git a/docker-compose.yml b/docker-compose.yml index 046096db2..63167e10f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3' services: elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:5.6.0 + image: docker.elastic.co/elasticsearch/elasticsearch:6.0.0-rc1 # container_name: elasticsearch hostname: elasticsearch environment: diff --git a/example_test.go b/example_test.go index 7bcbddc4d..9c2b0f626 100644 --- a/example_test.go +++ b/example_test.go @@ -71,7 +71,7 @@ func Example() { "number_of_replicas":0 }, "mappings":{ - "tweet":{ + "doc":{ "properties":{ "user":{ "type":"keyword" @@ -112,7 +112,7 @@ func Example() { tweet1 := Tweet{User: "olivere", Message: "Take Five", Retweets: 0} put1, err := client.Index(). Index("twitter"). - Type("tweet"). + Type("doc"). Id("1"). BodyJson(tweet1). Do(context.Background()) @@ -126,7 +126,7 @@ func Example() { tweet2 := `{"user" : "olivere", "message" : "It's a Raggy Waltz"}` put2, err := client.Index(). Index("twitter"). - Type("tweet"). + Type("doc"). Id("2"). BodyString(tweet2). Do(context.Background()) @@ -139,7 +139,7 @@ func Example() { // Get tweet with specified ID get1, err := client.Get(). Index("twitter"). - Type("tweet"). + Type("doc"). Id("1"). Do(context.Background()) if err != nil { @@ -212,7 +212,7 @@ func Example() { // Update a tweet by the update API of Elasticsearch. // We just increment the number of retweets. script := elastic.NewScript("ctx._source.retweets += params.num").Param("num", 1) - update, err := client.Update().Index("twitter").Type("tweet").Id("1"). + update, err := client.Update().Index("twitter").Type("doc").Id("1"). Script(script). Upsert(map[string]interface{}{"retweets": 0}). Do(context.Background()) diff --git a/exists.go b/exists.go index c08f71eef..e3e348159 100644 --- a/exists.go +++ b/exists.go @@ -159,7 +159,12 @@ func (s *ExistsService) Do(ctx context.Context) (bool, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "HEAD", path, params, nil, 404) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "HEAD", + Path: path, + Params: params, + IgnoreErrors: []int{404}, + }) if err != nil { return false, err } diff --git a/exists_test.go b/exists_test.go index af6a04e80..9ef71d7b1 100644 --- a/exists_test.go +++ b/exists_test.go @@ -12,7 +12,7 @@ import ( func TestExists(t *testing.T) { client := setupTestClientAndCreateIndexAndAddDocs(t) //, SetTraceLog(log.New(os.Stdout, "", 0))) - exists, err := client.Exists().Index(testIndexName).Type("comment").Id("1").Parent("tweet").Do(context.TODO()) + exists, err := client.Exists().Index(testIndexName).Type("comment").Id("1").Parent("doc").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -25,7 +25,7 @@ func TestExistsValidate(t *testing.T) { client := setupTestClient(t) // No index -> fail with error - res, err := NewExistsService(client).Type("tweet").Id("1").Do(context.TODO()) + res, err := NewExistsService(client).Type("doc").Id("1").Do(context.TODO()) if err == nil { t.Fatalf("expected Delete to fail without index name") } @@ -43,7 +43,7 @@ func TestExistsValidate(t *testing.T) { } // No id -> fail with error - res, err = NewExistsService(client).Index(testIndexName).Type("tweet").Do(context.TODO()) + res, err = NewExistsService(client).Index(testIndexName).Type("doc").Do(context.TODO()) if err == nil { t.Fatalf("expected Delete to fail without index name") } diff --git a/explain.go b/explain.go index 2c1a82aac..2243d8fbd 100644 --- a/explain.go +++ b/explain.go @@ -298,7 +298,12 @@ func (s *ExplainService) Do(ctx context.Context) (*ExplainResponse, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/explain_test.go b/explain_test.go index e71bf6675..22cb9668a 100644 --- a/explain_test.go +++ b/explain_test.go @@ -17,7 +17,7 @@ func TestExplain(t *testing.T) { // Add a document indexResult, err := client.Index(). Index(testIndexName). - Type("tweet"). + Type("doc"). Id("1"). BodyJson(&tweet1). Refresh("true"). @@ -31,7 +31,7 @@ func TestExplain(t *testing.T) { // Explain query := NewTermQuery("user", "olivere") - expl, err := client.Explain(testIndexName, "tweet", "1").Query(query).Do(context.TODO()) + expl, err := client.Explain(testIndexName, "doc", "1").Query(query).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/field_stats.go b/field_stats.go index e5ab83cbe..6ef05df6f 100644 --- a/field_stats.go +++ b/field_stats.go @@ -188,7 +188,13 @@ func (s *FieldStatsService) Do(ctx context.Context) (*FieldStatsResponse, error) } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body, http.StatusNotFound) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + IgnoreErrors: []int{http.StatusNotFound}, + }) if err != nil { return nil, err } diff --git a/get.go b/get.go index bc8b87e14..1232f4fab 100644 --- a/get.go +++ b/get.go @@ -223,7 +223,11 @@ func (s *GetService) Do(ctx context.Context) (*GetResult, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/get_template.go b/get_template.go index 3621f2239..fdf6b4fcb 100644 --- a/get_template.go +++ b/get_template.go @@ -95,7 +95,11 @@ func (s *GetTemplateService) Do(ctx context.Context) (*GetTemplateResponse, erro } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/get_template_test.go b/get_template_test.go index 16d063fcc..d6ba70fe0 100644 --- a/get_template_test.go +++ b/get_template_test.go @@ -10,7 +10,7 @@ import ( ) func TestGetPutDeleteTemplate(t *testing.T) { - client := setupTestClientAndCreateIndex(t) + client := setupTestClientAndCreateIndexAndLog(t) // This is a search template, not an index template! tmpl := `{ @@ -24,7 +24,7 @@ func TestGetPutDeleteTemplate(t *testing.T) { "my_size" : 5 } }` - putres, err := client.PutTemplate().Id("elastic-template").BodyString(tmpl).Do(context.TODO()) + putres, err := client.PutTemplate().Id("elastic-template").BodyString(tmpl).Pretty(true).Do(context.TODO()) if err != nil { t.Fatalf("expected no error; got: %v", err) } diff --git a/get_test.go b/get_test.go index 8ad5a43d8..f9504bdbf 100644 --- a/get_test.go +++ b/get_test.go @@ -14,13 +14,13 @@ func TestGet(t *testing.T) { client := setupTestClientAndCreateIndex(t) tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO()) if err != nil { t.Fatal(err) } // Get document 1 - res, err := client.Get().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + res, err := client.Get().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -32,7 +32,7 @@ func TestGet(t *testing.T) { } // Get non existent document 99 - res, err = client.Get().Index(testIndexName).Type("tweet").Id("99").Do(context.TODO()) + res, err = client.Get().Index(testIndexName).Type("doc").Id("99").Do(context.TODO()) if err == nil { t.Fatalf("expected error; got: %v", err) } @@ -48,13 +48,13 @@ func TestGetWithSourceFiltering(t *testing.T) { client := setupTestClientAndCreateIndex(t) // , SetTraceLog(log.New(os.Stdout, "", 0))) tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO()) if err != nil { t.Fatal(err) } // Get document 1, without source - res, err := client.Get().Index(testIndexName).Type("tweet").Id("1").FetchSource(false).Do(context.TODO()) + res, err := client.Get().Index(testIndexName).Type("doc").Id("1").FetchSource(false).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -67,7 +67,7 @@ func TestGetWithSourceFiltering(t *testing.T) { // Get document 1, exclude Message field fsc := NewFetchSourceContext(true).Exclude("message") - res, err = client.Get().Index(testIndexName).Type("tweet").Id("1").FetchSourceContext(fsc).Do(context.TODO()) + res, err = client.Get().Index(testIndexName).Type("doc").Id("1").FetchSourceContext(fsc).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -94,13 +94,13 @@ func TestGetWithFields(t *testing.T) { client := setupTestClientAndCreateIndex(t) //, SetTraceLog(log.New(os.Stdout, "", 0))) tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO()) if err != nil { t.Fatal(err) } // Get document 1, specifying fields - res, err := client.Get().Index(testIndexName).Type("tweet").Id("1").StoredFields("message").Do(context.TODO()) + res, err := client.Get().Index(testIndexName).Type("doc").Id("1").StoredFields("message").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -151,16 +151,16 @@ func TestGetValidate(t *testing.T) { if _, err := client.Get().Index(testIndexName).Do(context.TODO()); err == nil { t.Fatal("expected Get to fail") } - if _, err := client.Get().Type("tweet").Do(context.TODO()); err == nil { + if _, err := client.Get().Type("doc").Do(context.TODO()); err == nil { t.Fatal("expected Get to fail") } if _, err := client.Get().Id("1").Do(context.TODO()); err == nil { t.Fatal("expected Get to fail") } - if _, err := client.Get().Index(testIndexName).Type("tweet").Do(context.TODO()); err == nil { + if _, err := client.Get().Index(testIndexName).Type("doc").Do(context.TODO()); err == nil { t.Fatal("expected Get to fail") } - if _, err := client.Get().Type("tweet").Id("1").Do(context.TODO()); err == nil { + if _, err := client.Get().Type("doc").Id("1").Do(context.TODO()); err == nil { t.Fatal("expected Get to fail") } } diff --git a/highlight_test.go b/highlight_test.go index 9687cfb79..839bbf197 100644 --- a/highlight_test.go +++ b/highlight_test.go @@ -142,17 +142,17 @@ func TestHighlightWithTermQuery(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun to do."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/index.go b/index.go index 086b09aea..5800ac783 100644 --- a/index.go +++ b/index.go @@ -264,7 +264,12 @@ func (s *IndexService) Do(ctx context.Context) (*IndexResponse, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, method, path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: method, + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } @@ -279,10 +284,14 @@ func (s *IndexService) Do(ctx context.Context) (*IndexResponse, error) { // IndexResponse is the result of indexing a document in Elasticsearch. type IndexResponse struct { - // TODO _shards { total, failed, successful } - Index string `json:"_index"` - Type string `json:"_type"` - Id string `json:"_id"` - Version int `json:"_version"` - Created bool `json:"created"` + Index string `json:"_index,omitempty"` + Type string `json:"_type,omitempty"` + Id string `json:"_id,omitempty"` + Version int64 `json:"_version,omitempty"` + Result string `json:"result,omitempty"` + Shards *shardsInfo `json:"_shards,omitempty"` + SeqNo int64 `json:"_seq_no,omitempty"` + PrimaryTerm int64 `json:"_primary_term,omitempty"` + Status int `json:"status,omitempty"` + ForcedRefresh bool `json:"forced_refresh,omitempty"` } diff --git a/index_test.go b/index_test.go index 5e997f3b8..1a0c38576 100644 --- a/index_test.go +++ b/index_test.go @@ -18,7 +18,7 @@ func TestIndexLifecycle(t *testing.T) { // Add a document indexResult, err := client.Index(). Index(testIndexName). - Type("tweet"). + Type("doc"). Id("1"). BodyJson(&tweet1). Do(context.TODO()) @@ -30,7 +30,7 @@ func TestIndexLifecycle(t *testing.T) { } // Exists - exists, err := client.Exists().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + exists, err := client.Exists().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -41,7 +41,7 @@ func TestIndexLifecycle(t *testing.T) { // Get document getResult, err := client.Get(). Index(testIndexName). - Type("tweet"). + Type("doc"). Id("1"). Do(context.TODO()) if err != nil { @@ -50,8 +50,8 @@ func TestIndexLifecycle(t *testing.T) { if getResult.Index != testIndexName { t.Errorf("expected GetResult.Index %q; got %q", testIndexName, getResult.Index) } - if getResult.Type != "tweet" { - t.Errorf("expected GetResult.Type %q; got %q", "tweet", getResult.Type) + if getResult.Type != "doc" { + t.Errorf("expected GetResult.Type %q; got %q", "doc", getResult.Type) } if getResult.Id != "1" { t.Errorf("expected GetResult.Id %q; got %q", "1", getResult.Id) @@ -74,7 +74,7 @@ func TestIndexLifecycle(t *testing.T) { } // Delete document again - deleteResult, err := client.Delete().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + deleteResult, err := client.Delete().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -83,7 +83,7 @@ func TestIndexLifecycle(t *testing.T) { } // Exists - exists, err = client.Exists().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO()) + exists, err = client.Exists().Index(testIndexName).Type("doc").Id("1").Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -100,7 +100,7 @@ func TestIndexLifecycleWithAutomaticIDGeneration(t *testing.T) { // Add a document indexResult, err := client.Index(). Index(testIndexName). - Type("tweet"). + Type("doc"). BodyJson(&tweet1). Do(context.TODO()) if err != nil { @@ -115,7 +115,7 @@ func TestIndexLifecycleWithAutomaticIDGeneration(t *testing.T) { id := indexResult.Id // Exists - exists, err := client.Exists().Index(testIndexName).Type("tweet").Id(id).Do(context.TODO()) + exists, err := client.Exists().Index(testIndexName).Type("doc").Id(id).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -126,7 +126,7 @@ func TestIndexLifecycleWithAutomaticIDGeneration(t *testing.T) { // Get document getResult, err := client.Get(). Index(testIndexName). - Type("tweet"). + Type("doc"). Id(id). Do(context.TODO()) if err != nil { @@ -135,8 +135,8 @@ func TestIndexLifecycleWithAutomaticIDGeneration(t *testing.T) { if getResult.Index != testIndexName { t.Errorf("expected GetResult.Index %q; got %q", testIndexName, getResult.Index) } - if getResult.Type != "tweet" { - t.Errorf("expected GetResult.Type %q; got %q", "tweet", getResult.Type) + if getResult.Type != "doc" { + t.Errorf("expected GetResult.Type %q; got %q", "doc", getResult.Type) } if getResult.Id != id { t.Errorf("expected GetResult.Id %q; got %q", id, getResult.Id) @@ -159,7 +159,7 @@ func TestIndexLifecycleWithAutomaticIDGeneration(t *testing.T) { } // Delete document again - deleteResult, err := client.Delete().Index(testIndexName).Type("tweet").Id(id).Do(context.TODO()) + deleteResult, err := client.Delete().Index(testIndexName).Type("doc").Id(id).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -168,7 +168,7 @@ func TestIndexLifecycleWithAutomaticIDGeneration(t *testing.T) { } // Exists - exists, err = client.Exists().Index(testIndexName).Type("tweet").Id(id).Do(context.TODO()) + exists, err = client.Exists().Index(testIndexName).Type("doc").Id(id).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -183,7 +183,7 @@ func TestIndexValidate(t *testing.T) { tweet := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."} // No index name -> fail with error - res, err := NewIndexService(client).Type("tweet").Id("1").BodyJson(&tweet).Do(context.TODO()) + res, err := NewIndexService(client).Type("doc").Id("1").BodyJson(&tweet).Do(context.TODO()) if err == nil { t.Fatalf("expected Index to fail without index name") } diff --git a/indices_analyze.go b/indices_analyze.go index 0368886a4..9d07fa2e0 100644 --- a/indices_analyze.go +++ b/indices_analyze.go @@ -189,7 +189,12 @@ func (s *IndicesAnalyzeService) Do(ctx context.Context) (*IndicesAnalyzeResponse body = s.request } - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_close.go b/indices_close.go index 20c4c2069..1ebb6bbde 100644 --- a/indices_close.go +++ b/indices_close.go @@ -134,7 +134,11 @@ func (s *IndicesCloseService) Do(ctx context.Context) (*IndicesCloseResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_create.go b/indices_create.go index b11935c14..c98719290 100644 --- a/indices_create.go +++ b/indices_create.go @@ -109,7 +109,12 @@ func (b *IndicesCreateService) Do(ctx context.Context) (*IndicesCreateResult, er } // Get response - res, err := b.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := b.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_delete.go b/indices_delete.go index 4d576dbcd..765289c3a 100644 --- a/indices_delete.go +++ b/indices_delete.go @@ -108,7 +108,11 @@ func (s *IndicesDeleteService) Do(ctx context.Context) (*IndicesDeleteResponse, } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_delete_template.go b/indices_delete_template.go index a4b563e4b..e8cf00b05 100644 --- a/indices_delete_template.go +++ b/indices_delete_template.go @@ -103,7 +103,11 @@ func (s *IndicesDeleteTemplateService) Do(ctx context.Context) (*IndicesDeleteTe } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_exists.go b/indices_exists.go index aa259da33..cceb638fe 100644 --- a/indices_exists.go +++ b/indices_exists.go @@ -133,7 +133,12 @@ func (s *IndicesExistsService) Do(ctx context.Context) (bool, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "HEAD", path, params, nil, 404) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "HEAD", + Path: path, + Params: params, + IgnoreErrors: []int{404}, + }) if err != nil { return false, err } diff --git a/indices_exists_template.go b/indices_exists_template.go index ef341faaa..e130f98ef 100644 --- a/indices_exists_template.go +++ b/indices_exists_template.go @@ -96,7 +96,12 @@ func (s *IndicesExistsTemplateService) Do(ctx context.Context) (bool, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "HEAD", path, params, nil, 404) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "HEAD", + Path: path, + Params: params, + IgnoreErrors: []int{404}, + }) if err != nil { return false, err } diff --git a/indices_exists_template_test.go b/indices_exists_template_test.go index cddf69f21..f35620ada 100644 --- a/indices_exists_template_test.go +++ b/indices_exists_template_test.go @@ -19,7 +19,7 @@ func TestIndexExistsTemplate(t *testing.T) { "number_of_replicas":0 }, "mappings":{ - "tweet":{ + "doc":{ "properties":{ "tags":{ "type":"keyword" diff --git a/indices_exists_type.go b/indices_exists_type.go index 17224a8ea..8f9715155 100644 --- a/indices_exists_type.go +++ b/indices_exists_type.go @@ -143,7 +143,12 @@ func (s *IndicesExistsTypeService) Do(ctx context.Context) (bool, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "HEAD", path, params, nil, 404) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "HEAD", + Path: path, + Params: params, + IgnoreErrors: []int{404}, + }) if err != nil { return false, err } diff --git a/indices_exists_type_test.go b/indices_exists_type_test.go index 2af3c2c5d..3795bd042 100644 --- a/indices_exists_type_test.go +++ b/indices_exists_type_test.go @@ -94,12 +94,12 @@ func TestIndicesExistsType(t *testing.T) { } // Check if type exists - exists, err := client.TypeExists().Index(testIndexName).Type("tweet").Do(context.TODO()) + exists, err := client.TypeExists().Index(testIndexName).Type("doc").Do(context.TODO()) if err != nil { t.Fatal(err) } if !exists { - t.Fatalf("type %s should exist in index %s, but doesn't\n", "tweet", testIndexName) + t.Fatalf("type %s should exist in index %s, but doesn't\n", "doc", testIndexName) } // Delete index @@ -112,12 +112,12 @@ func TestIndicesExistsType(t *testing.T) { } // Check if type exists - exists, err = client.TypeExists().Index(testIndexName).Type("tweet").Do(context.TODO()) + exists, err = client.TypeExists().Index(testIndexName).Type("doc").Do(context.TODO()) if err != nil { t.Fatal(err) } if exists { - t.Fatalf("type %s should not exist in index %s, but it does\n", "tweet", testIndexName) + t.Fatalf("type %s should not exist in index %s, but it does\n", "doc", testIndexName) } } diff --git a/indices_flush.go b/indices_flush.go index 927845214..413181f99 100644 --- a/indices_flush.go +++ b/indices_flush.go @@ -149,7 +149,11 @@ func (s *IndicesFlushService) Do(ctx context.Context) (*IndicesFlushResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_forcemerge.go b/indices_forcemerge.go index 3e1c52872..f90ce1590 100644 --- a/indices_forcemerge.go +++ b/indices_forcemerge.go @@ -170,7 +170,11 @@ func (s *IndicesForcemergeService) Do(ctx context.Context) (*IndicesForcemergeRe } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_get.go b/indices_get.go index 17084d535..6f94ed561 100644 --- a/indices_get.go +++ b/indices_get.go @@ -180,7 +180,11 @@ func (s *IndicesGetService) Do(ctx context.Context) (map[string]*IndicesGetRespo } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_get_aliases.go b/indices_get_aliases.go index 53e630c55..88ccceba2 100644 --- a/indices_get_aliases.go +++ b/indices_get_aliases.go @@ -72,7 +72,11 @@ func (s *AliasesService) Do(ctx context.Context) (*AliasesResult, error) { } // Get response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_get_aliases_test.go b/indices_get_aliases_test.go index 75abac835..b51d6bacf 100644 --- a/indices_get_aliases_test.go +++ b/indices_get_aliases_test.go @@ -53,16 +53,16 @@ func TestAliases(t *testing.T) { tweet3 := tweet{User: "olivere", Message: "Another unrelated topic."} // Add tweets to first index - _, err = client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO()) if err != nil { t.Fatal(err) } // Add tweets to second index - _, err = client.Index().Index(testIndexName2).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName2).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/indices_get_field_mapping.go b/indices_get_field_mapping.go index 64e476ba3..dfbf90085 100644 --- a/indices_get_field_mapping.go +++ b/indices_get_field_mapping.go @@ -170,7 +170,11 @@ func (s *IndicesGetFieldMappingService) Do(ctx context.Context) (map[string]inte } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_get_mapping.go b/indices_get_mapping.go index 5e2ecb0ad..2fba14343 100644 --- a/indices_get_mapping.go +++ b/indices_get_mapping.go @@ -156,7 +156,11 @@ func (s *IndicesGetMappingService) Do(ctx context.Context) (map[string]interface } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_get_settings.go b/indices_get_settings.go index faa00c8e5..465483bfa 100644 --- a/indices_get_settings.go +++ b/indices_get_settings.go @@ -164,7 +164,11 @@ func (s *IndicesGetSettingsService) Do(ctx context.Context) (map[string]*Indices } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_get_template.go b/indices_get_template.go index e88fcbc80..9c0701b18 100644 --- a/indices_get_template.go +++ b/indices_get_template.go @@ -105,7 +105,11 @@ func (s *IndicesGetTemplateService) Do(ctx context.Context) (map[string]*Indices } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_open.go b/indices_open.go index d85b3373a..9fff4fb70 100644 --- a/indices_open.go +++ b/indices_open.go @@ -138,7 +138,11 @@ func (s *IndicesOpenService) Do(ctx context.Context) (*IndicesOpenResponse, erro } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_put_alias.go b/indices_put_alias.go index 5d965bd66..7740fe419 100644 --- a/indices_put_alias.go +++ b/indices_put_alias.go @@ -274,7 +274,12 @@ func (s *AliasService) Do(ctx context.Context) (*AliasResult, error) { body["actions"] = actions // Get response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_put_alias_test.go b/indices_put_alias_test.go index 82ab6a07b..ada1dfdef 100644 --- a/indices_put_alias_test.go +++ b/indices_put_alias_test.go @@ -25,18 +25,18 @@ func TestAliasLifecycle(t *testing.T) { tweet3 := tweet{User: "olivere", Message: "Another unrelated topic."} // Add tweets to first index - _, err = client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyJson(&tweet2).Do(context.TODO()) if err != nil { t.Fatal(err) } // Add tweets to second index - _, err = client.Index().Index(testIndexName2).Type("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName2).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/indices_put_mapping.go b/indices_put_mapping.go index d50137452..aea6cb569 100644 --- a/indices_put_mapping.go +++ b/indices_put_mapping.go @@ -202,7 +202,12 @@ func (s *IndicesPutMappingService) Do(ctx context.Context) (*PutMappingResponse, } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_put_mapping_test.go b/indices_put_mapping_test.go index ffac0d0f2..647c454bb 100644 --- a/indices_put_mapping_test.go +++ b/indices_put_mapping_test.go @@ -19,18 +19,18 @@ func TestPutMappingURL(t *testing.T) { }{ { []string{}, - "tweet", - "/_mapping/tweet", + "doc", + "/_mapping/doc", }, { []string{"*"}, - "tweet", - "/%2A/_mapping/tweet", + "doc", + "/%2A/_mapping/doc", }, { []string{"store-1", "store-2"}, - "tweet", - "/store-1%2Cstore-2/_mapping/tweet", + "doc", + "/store-1%2Cstore-2/_mapping/doc", }, } @@ -49,7 +49,7 @@ func TestMappingLifecycle(t *testing.T) { client := setupTestClientAndCreateIndex(t) mapping := `{ - "tweetdoc":{ + "doc":{ "properties":{ "field":{ "type":"keyword" @@ -58,7 +58,7 @@ func TestMappingLifecycle(t *testing.T) { } }` - putresp, err := client.PutMapping().Index(testIndexName2).Type("tweetdoc").BodyString(mapping).Do(context.TODO()) + putresp, err := client.PutMapping().Index(testIndexName3).Type("doc").BodyString(mapping).Do(context.TODO()) if err != nil { t.Fatalf("expected put mapping to succeed; got: %v", err) } @@ -69,14 +69,14 @@ func TestMappingLifecycle(t *testing.T) { t.Fatalf("expected put mapping ack; got: %v", putresp.Acknowledged) } - getresp, err := client.GetMapping().Index(testIndexName2).Type("tweetdoc").Do(context.TODO()) + getresp, err := client.GetMapping().Index(testIndexName3).Type("doc").Do(context.TODO()) if err != nil { t.Fatalf("expected get mapping to succeed; got: %v", err) } if getresp == nil { t.Fatalf("expected get mapping response; got: %v", getresp) } - props, ok := getresp[testIndexName2] + props, ok := getresp[testIndexName3] if !ok { t.Fatalf("expected JSON root to be of type map[string]interface{}; got: %#v", props) } diff --git a/indices_put_settings.go b/indices_put_settings.go index abfb3c73d..f3508f6a5 100644 --- a/indices_put_settings.go +++ b/indices_put_settings.go @@ -165,7 +165,12 @@ func (s *IndicesPutSettingsService) Do(ctx context.Context) (*IndicesPutSettings } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_put_template.go b/indices_put_template.go index eefa79984..7b331fe4d 100644 --- a/indices_put_template.go +++ b/indices_put_template.go @@ -181,7 +181,12 @@ func (s *IndicesPutTemplateService) Do(ctx context.Context) (*IndicesPutTemplate } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_refresh.go b/indices_refresh.go index eb1654354..46551a7dc 100644 --- a/indices_refresh.go +++ b/indices_refresh.go @@ -14,11 +14,10 @@ import ( ) // RefreshService explicitly refreshes one or more indices. -// See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/indices-refresh.html. +// See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-refresh.html. type RefreshService struct { client *Client index []string - force *bool pretty bool } @@ -36,12 +35,6 @@ func (s *RefreshService) Index(index ...string) *RefreshService { return s } -// Force forces a refresh. -func (s *RefreshService) Force(force bool) *RefreshService { - s.force = &force - return s -} - // Pretty asks Elasticsearch to return indented JSON. func (s *RefreshService) Pretty(pretty bool) *RefreshService { s.pretty = pretty @@ -66,9 +59,6 @@ func (s *RefreshService) buildURL() (string, url.Values, error) { // Add query string parameters params := url.Values{} - if s.force != nil { - params.Set("force", fmt.Sprintf("%v", *s.force)) - } if s.pretty { params.Set("pretty", fmt.Sprintf("%v", s.pretty)) } @@ -83,7 +73,11 @@ func (s *RefreshService) Do(ctx context.Context) (*RefreshResult, error) { } // Get response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/indices_refresh_test.go b/indices_refresh_test.go index a6aac44ea..8640fb602 100644 --- a/indices_refresh_test.go +++ b/indices_refresh_test.go @@ -50,17 +50,17 @@ func TestRefresh(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add some documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/indices_rollover.go b/indices_rollover.go index 726e08e14..18691c6e2 100644 --- a/indices_rollover.go +++ b/indices_rollover.go @@ -242,7 +242,12 @@ func (s *IndicesRolloverService) Do(ctx context.Context) (*IndicesRolloverRespon } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_rollover_test.go b/indices_rollover_test.go index 77ac1e851..81d7099e0 100644 --- a/indices_rollover_test.go +++ b/indices_rollover_test.go @@ -97,7 +97,7 @@ func TestIndicesRolloverBodyComplex(t *testing.T) { AddMaxIndexAgeCondition("2d"). AddMaxIndexDocsCondition(1000000). AddSetting("index.number_of_shards", 2). - AddMapping("tweet", map[string]interface{}{ + AddMapping("doc", map[string]interface{}{ "properties": map[string]interface{}{ "user": map[string]interface{}{ "type": "keyword", @@ -109,7 +109,7 @@ func TestIndicesRolloverBodyComplex(t *testing.T) { t.Fatalf("marshaling to JSON failed: %v", err) } got := string(data) - expected := `{"conditions":{"max_age":"2d","max_docs":1000000},"mappings":{"tweet":{"properties":{"user":{"type":"keyword"}}}},"settings":{"index.number_of_shards":2}}` + expected := `{"conditions":{"max_age":"2d","max_docs":1000000},"mappings":{"doc":{"properties":{"user":{"type":"keyword"}}}},"settings":{"index.number_of_shards":2}}` if got != expected { t.Errorf("expected\n%s\n,got:\n%s", expected, got) } diff --git a/indices_shrink.go b/indices_shrink.go index 55983eaac..a66ec68c9 100644 --- a/indices_shrink.go +++ b/indices_shrink.go @@ -153,7 +153,12 @@ func (s *IndicesShrinkService) Do(ctx context.Context) (*IndicesShrinkResponse, } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/indices_stats.go b/indices_stats.go index 61ec966fd..508b861b3 100644 --- a/indices_stats.go +++ b/indices_stats.go @@ -180,7 +180,11 @@ func (s *IndicesStatsService) Do(ctx context.Context) (*IndicesStatsResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/ingest_delete_pipeline.go b/ingest_delete_pipeline.go index 3d20d5edd..42fa4cb33 100644 --- a/ingest_delete_pipeline.go +++ b/ingest_delete_pipeline.go @@ -104,7 +104,11 @@ func (s *IngestDeletePipelineService) Do(ctx context.Context) (*IngestDeletePipe } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/ingest_get_pipeline.go b/ingest_get_pipeline.go index b721fd7a9..8f4633240 100644 --- a/ingest_get_pipeline.go +++ b/ingest_get_pipeline.go @@ -95,7 +95,11 @@ func (s *IngestGetPipelineService) Do(ctx context.Context) (IngestGetPipelineRes } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/ingest_put_pipeline.go b/ingest_put_pipeline.go index d934b863e..1682a5875 100644 --- a/ingest_put_pipeline.go +++ b/ingest_put_pipeline.go @@ -132,7 +132,12 @@ func (s *IngestPutPipelineService) Do(ctx context.Context) (*IngestPutPipelineRe } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/ingest_simulate_pipeline.go b/ingest_simulate_pipeline.go index 0b38019f6..193500d1c 100644 --- a/ingest_simulate_pipeline.go +++ b/ingest_simulate_pipeline.go @@ -127,7 +127,12 @@ func (s *IngestSimulatePipelineService) Do(ctx context.Context) (*IngestSimulate } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/mget.go b/mget.go index 0f2894854..1801d4be0 100644 --- a/mget.go +++ b/mget.go @@ -124,7 +124,12 @@ func (s *MgetService) Do(ctx context.Context) (*MgetResponse, error) { } // Get response - res, err := s.client.PerformRequest(ctx, "GET", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/mget_test.go b/mget_test.go index 4d6bfa0c5..6b3ecd9f6 100644 --- a/mget_test.go +++ b/mget_test.go @@ -18,17 +18,17 @@ func TestMultiGet(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add some documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -49,8 +49,8 @@ func TestMultiGet(t *testing.T) { // Get documents 1 and 3 res, err := client.MultiGet(). - Add(NewMultiGetItem().Index(testIndexName).Type("tweet").Id("1")). - Add(NewMultiGetItem().Index(testIndexName).Type("tweet").Id("3")). + Add(NewMultiGetItem().Index(testIndexName).Type("doc").Id("1")). + Add(NewMultiGetItem().Index(testIndexName).Type("doc").Id("3")). Do(context.TODO()) if err != nil { t.Fatal(err) diff --git a/msearch.go b/msearch.go index 52ca9ee74..ed54d3c2f 100644 --- a/msearch.go +++ b/msearch.go @@ -68,7 +68,7 @@ func (s *MultiSearchService) Do(ctx context.Context) (*MultiSearchResult, error) if err != nil { return nil, err } - body, err := json.Marshal(sr.body()) + body, err := json.Marshal(sr.Body()) if err != nil { return nil, err } @@ -78,7 +78,12 @@ func (s *MultiSearchService) Do(ctx context.Context) (*MultiSearchResult, error) body := strings.Join(lines, "\n") + "\n" // Don't forget trailing \n // Get response - res, err := s.client.PerformRequest(ctx, "GET", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/msearch_test.go b/msearch_test.go index 0d3670da6..79f2047e6 100644 --- a/msearch_test.go +++ b/msearch_test.go @@ -31,17 +31,17 @@ func TestMultiSearch(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -57,7 +57,7 @@ func TestMultiSearch(t *testing.T) { sreq1 := NewSearchRequest().Index(testIndexName, testIndexName2). Source(NewSearchSource().Query(q1).Size(10)) - sreq2 := NewSearchRequest().Index(testIndexName).Type("tweet"). + sreq2 := NewSearchRequest().Index(testIndexName).Type("doc"). Source(NewSearchSource().Query(q2)) searchResult, err := client.MultiSearch(). @@ -136,17 +136,17 @@ func TestMultiSearchWithOneRequest(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/mtermvectors.go b/mtermvectors.go index 34e558985..58b77a261 100644 --- a/mtermvectors.go +++ b/mtermvectors.go @@ -278,7 +278,12 @@ func (s *MultiTermvectorService) Do(ctx context.Context) (*MultiTermvectorRespon } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/mtermvectors_test.go b/mtermvectors_test.go index fe543cf29..5f90cd5e2 100644 --- a/mtermvectors_test.go +++ b/mtermvectors_test.go @@ -35,15 +35,15 @@ func TestMultiTermVectorsValidateAndBuildURL(t *testing.T) { // #2: Type without index { "", - "tweet", + "doc", "", true, }, // #3: Both index and type { "twitter", - "tweet", - "/twitter/tweet/_mtermvectors", + "doc", + "/twitter/doc/_mtermvectors", false, }, } @@ -82,17 +82,17 @@ func TestMultiTermVectorsWithIds(t *testing.T) { tweet2 := tweet{User: "olivere", Message: "Another unrelated topic."} tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -115,9 +115,9 @@ func TestMultiTermVectorsWithIds(t *testing.T) { field := "Message" res, err := client.MultiTermVectors(). Index(testIndexName). - Type("tweet"). - Add(NewMultiTermvectorItem().Index(testIndexName).Type("tweet").Id("1").Fields(field)). - Add(NewMultiTermvectorItem().Index(testIndexName).Type("tweet").Id("3").Fields(field)). + Type("doc"). + Add(NewMultiTermvectorItem().Index(testIndexName).Type("doc").Id("1").Fields(field)). + Add(NewMultiTermvectorItem().Index(testIndexName).Type("doc").Id("3").Fields(field)). Do(context.TODO()) if err != nil { t.Fatal(err) diff --git a/nodes_info.go b/nodes_info.go index 13fd284de..e6763e078 100644 --- a/nodes_info.go +++ b/nodes_info.go @@ -113,7 +113,11 @@ func (s *NodesInfoService) Do(ctx context.Context) (*NodesInfoResponse, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/nodes_stats.go b/nodes_stats.go index 3c7becf67..0f7c4343b 100644 --- a/nodes_stats.go +++ b/nodes_stats.go @@ -213,7 +213,11 @@ func (s *NodesStatsService) Do(ctx context.Context) (*NodesStatsResponse, error) } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/put_template.go b/put_template.go index 1a4a0903e..6af84ee6f 100644 --- a/put_template.go +++ b/put_template.go @@ -57,6 +57,12 @@ func (s *PutTemplateService) VersionType(versionType string) *PutTemplateService return s } +// Pretty indicates whether to indent the returned JSON. +func (s *PutTemplateService) Pretty(pretty bool) *PutTemplateService { + s.pretty = pretty + return s +} + // BodyJson is the document as a JSON serializable object. func (s *PutTemplateService) BodyJson(body interface{}) *PutTemplateService { s.bodyJson = body @@ -90,6 +96,9 @@ func (s *PutTemplateService) buildURL() (string, url.Values, error) { if s.opType != "" { params.Set("op_type", s.opType) } + if s.pretty { + params.Set("pretty", "true") + } return path, params, nil } @@ -131,7 +140,12 @@ func (s *PutTemplateService) Do(ctx context.Context) (*AcknowledgedResponse, err } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/reindex.go b/reindex.go index 1f92d7a99..01b60ed80 100644 --- a/reindex.go +++ b/reindex.go @@ -267,7 +267,12 @@ func (s *ReindexService) Do(ctx context.Context) (*BulkIndexByScrollResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } @@ -309,7 +314,12 @@ func (s *ReindexService) DoAsync(ctx context.Context) (*StartTaskResult, error) } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/reindex_test.go b/reindex_test.go index 2ab604089..0d8a4a330 100644 --- a/reindex_test.go +++ b/reindex_test.go @@ -166,7 +166,7 @@ func TestReindexSourceWithProceedOnVersionConflict(t *testing.T) { func TestReindexSourceWithQuery(t *testing.T) { client := setupTestClient(t) - src := NewReindexSource().Index("twitter").Type("tweet").Query(NewTermQuery("user", "olivere")) + src := NewReindexSource().Index("twitter").Type("doc").Query(NewTermQuery("user", "olivere")) dst := NewReindexDestination().Index("new_twitter") out, err := client.Reindex().Source(src).Destination(dst).getBody() if err != nil { @@ -177,7 +177,7 @@ func TestReindexSourceWithQuery(t *testing.T) { t.Fatal(err) } got := string(b) - want := `{"dest":{"index":"new_twitter"},"source":{"index":"twitter","query":{"term":{"user":"olivere"}},"type":"tweet"}}` + want := `{"dest":{"index":"new_twitter"},"source":{"index":"twitter","query":{"term":{"user":"olivere"}},"type":"doc"}}` if got != want { t.Fatalf("\ngot %s\nwant %s", got, want) } @@ -185,7 +185,7 @@ func TestReindexSourceWithQuery(t *testing.T) { func TestReindexSourceWithMultipleSourceIndicesAndTypes(t *testing.T) { client := setupTestClient(t) - src := NewReindexSource().Index("twitter", "blog").Type("tweet", "post") + src := NewReindexSource().Index("twitter", "blog").Type("doc", "post") dst := NewReindexDestination().Index("all_together") out, err := client.Reindex().Source(src).Destination(dst).getBody() if err != nil { @@ -196,7 +196,7 @@ func TestReindexSourceWithMultipleSourceIndicesAndTypes(t *testing.T) { t.Fatal(err) } got := string(b) - want := `{"dest":{"index":"all_together"},"source":{"index":["twitter","blog"],"type":["tweet","post"]}}` + want := `{"dest":{"index":"all_together"},"source":{"index":["twitter","blog"],"type":["doc","post"]}}` if got != want { t.Fatalf("\ngot %s\nwant %s", got, want) } diff --git a/request_test.go b/request_test.go index 2a2d229df..d5ae4f800 100644 --- a/request_test.go +++ b/request_test.go @@ -8,6 +8,20 @@ import "testing" var testReq *Request // used as a temporary variable to avoid compiler optimizations in tests/benchmarks +func TestRequestSetContentType(t *testing.T) { + req, err := NewRequest("GET", "/") + if err != nil { + t.Fatal(err) + } + if want, have := "application/json", req.Header.Get("Content-Type"); want != have { + t.Fatalf("want %q, have %q", want, have) + } + req.Header.Set("Content-Type", "application/x-ndjson") + if want, have := "application/x-ndjson", req.Header.Get("Content-Type"); want != have { + t.Fatalf("want %q, have %q", want, have) + } +} + func BenchmarkRequestSetBodyString(b *testing.B) { req, err := NewRequest("GET", "/") if err != nil { diff --git a/response.go b/response.go index e7380d98a..4fcdc32d6 100644 --- a/response.go +++ b/response.go @@ -34,9 +34,7 @@ func (c *Client) newResponse(res *http.Response) (*Response, error) { } // HEAD requests return a body but no content if len(slurp) > 0 { - if err := c.decoder.Decode(slurp, &r.Body); err != nil { - return nil, err - } + r.Body = json.RawMessage(slurp) } } return r, nil diff --git a/response_test.go b/response_test.go new file mode 100644 index 000000000..e62773403 --- /dev/null +++ b/response_test.go @@ -0,0 +1,48 @@ +// 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 ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "testing" +) + +func BenchmarkResponse(b *testing.B) { + c := &Client{ + decoder: &DefaultDecoder{}, + } + + var resp *Response + for n := 0; n < b.N; n++ { + iteration := fmt.Sprint(n) + body := fmt.Sprintf(`{"n":%d}`, n) + res := &http.Response{ + Header: http.Header{ + "X-Iteration": []string{iteration}, + }, + Body: ioutil.NopCloser(bytes.NewBufferString(body)), + StatusCode: http.StatusOK, + } + var err error + resp, err = c.newResponse(res) + if err != nil { + b.Fatal(err) + } + /* + if want, have := body, string(resp.Body); want != have { + b.Fatalf("want %q, have %q", want, have) + } + //*/ + /* + if want, have := iteration, resp.Header.Get("X-Iteration"); want != have { + b.Fatalf("want %q, have %q", want, have) + } + //*/ + } + _ = resp +} diff --git a/retrier_test.go b/retrier_test.go index 100a17838..8580ee10f 100644 --- a/retrier_test.go +++ b/retrier_test.go @@ -65,7 +65,10 @@ func TestRetrier(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/fail", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/fail", + }) if err == nil { t.Fatal("expected error") } @@ -107,7 +110,10 @@ func TestRetrierWithError(t *testing.T) { t.Fatal(err) } - res, err := client.PerformRequest(context.TODO(), "GET", "/fail", nil, nil) + res, err := client.PerformRequest(context.TODO(), PerformRequestOptions{ + Method: "GET", + Path: "/fail", + }) if err != kaboom { t.Fatalf("expected %v, got %v", kaboom, err) } diff --git a/run-es.sh b/run-es.sh index bf6f926c9..7a32eeb48 100755 --- a/run-es.sh +++ b/run-es.sh @@ -1 +1 @@ -docker run --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:6.0.0-beta2 elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_ +docker run --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:6.0.0-rc1 elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_ diff --git a/scroll.go b/scroll.go index 098c7b0d0..f0c720c33 100644 --- a/scroll.go +++ b/scroll.go @@ -258,7 +258,12 @@ func (s *ScrollService) Clear(ctx context.Context) error { ScrollId: []string{scrollId}, } - _, err := s.client.PerformRequest(ctx, "DELETE", path, params, body) + _, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + Body: body, + }) if err != nil { return err } @@ -283,7 +288,12 @@ func (s *ScrollService) first(ctx context.Context) (*SearchResult, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } @@ -397,7 +407,12 @@ func (s *ScrollService) next(ctx context.Context) (*SearchResult, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/scroll_test.go b/scroll_test.go index 9c9037beb..c94e5f92f 100644 --- a/scroll_test.go +++ b/scroll_test.go @@ -20,17 +20,17 @@ func TestScroll(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -113,17 +113,17 @@ func TestScrollWithQueryAndSort(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -200,17 +200,17 @@ func TestScrollWithBody(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun.", Retweets: 3} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/search.go b/search.go index b041511ac..819a854e6 100644 --- a/search.go +++ b/search.go @@ -385,7 +385,12 @@ func (s *SearchService) Do(ctx context.Context) (*SearchResult, error) { } body = src } - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } @@ -498,12 +503,15 @@ type SearchSuggestion struct { // SearchSuggestionOption is an option of a SearchSuggestion. // See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-suggesters.html. type SearchSuggestionOption struct { - Text string `json:"text"` - Index string `json:"_index"` - Type string `json:"_type"` - Id string `json:"_id"` - Score float64 `json:"_score"` - Source *json.RawMessage `json:"_source"` + Text string `json:"text"` + Index string `json:"_index"` + Type string `json:"_type"` + Id string `json:"_id"` + Score float64 `json:"score"` + Highlighted string `json:"highlighted"` + CollateMatch bool `json:"collate_match"` + Freq int `json:"freq"` // from TermSuggestion.Option in Java API + Source *json.RawMessage `json:"_source"` } // SearchProfile is a list of shard profiling data collected during diff --git a/search_aggs_test.go b/search_aggs_test.go index c730e3b43..208a21f9a 100644 --- a/search_aggs_test.go +++ b/search_aggs_test.go @@ -48,17 +48,17 @@ func TestAggs(t *testing.T) { } // Add all documents - _, err = client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -1000,7 +1000,7 @@ func TestAggsMarshal(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyJson(&tweet1).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/search_queries_common_terms_test.go b/search_queries_common_terms_test.go index be5a381c7..e841e7731 100644 --- a/search_queries_common_terms_test.go +++ b/search_queries_common_terms_test.go @@ -36,17 +36,17 @@ func TestSearchQueriesCommonTermsQuery(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/search_queries_match.go b/search_queries_match.go index 0c44c5d57..1f2f16f69 100644 --- a/search_queries_match.go +++ b/search_queries_match.go @@ -16,16 +16,13 @@ package elastic type MatchQuery struct { name string text interface{} - typ string // boolean, phrase, phrase_prefix operator string // or / and analyzer string boost *float64 - slop *int fuzziness string prefixLength *int maxExpansions *int minimumShouldMatch string - rewrite string fuzzyRewrite string lenient *bool fuzzyTranspositions *bool @@ -39,22 +36,6 @@ func NewMatchQuery(name string, text interface{}) *MatchQuery { return &MatchQuery{name: name, text: text} } -// NewMatchPhraseQuery creates and initializes a new MatchQuery of type phrase. -func NewMatchPhraseQuery(name string, text interface{}) *MatchQuery { - return &MatchQuery{name: name, text: text, typ: "phrase"} -} - -// NewMatchPhrasePrefixQuery creates and initializes a new MatchQuery of type phrase_prefix. -func NewMatchPhrasePrefixQuery(name string, text interface{}) *MatchQuery { - return &MatchQuery{name: name, text: text, typ: "phrase_prefix"} -} - -// Type can be "boolean", "phrase", or "phrase_prefix". Defaults to "boolean". -func (q *MatchQuery) Type(typ string) *MatchQuery { - q.typ = typ - return q -} - // Operator sets the operator to use when using a boolean query. // Can be "AND" or "OR" (default). func (q *MatchQuery) Operator(operator string) *MatchQuery { @@ -69,18 +50,6 @@ func (q *MatchQuery) Analyzer(analyzer string) *MatchQuery { return q } -// Boost sets the boost to apply to this query. -func (q *MatchQuery) Boost(boost float64) *MatchQuery { - q.boost = &boost - return q -} - -// Slop sets the phrase slop if evaluated to a phrase query type. -func (q *MatchQuery) Slop(slop int) *MatchQuery { - q.slop = &slop - return q -} - // Fuzziness sets the fuzziness when evaluated to a fuzzy query type. // Defaults to "AUTO". func (q *MatchQuery) Fuzziness(fuzziness string) *MatchQuery { @@ -88,6 +57,8 @@ func (q *MatchQuery) Fuzziness(fuzziness string) *MatchQuery { return q } +// PrefixLength sets the length of a length of common (non-fuzzy) +// prefix for fuzzy match queries. It must be non-negative. func (q *MatchQuery) PrefixLength(prefixLength int) *MatchQuery { q.prefixLength = &prefixLength return q @@ -109,21 +80,28 @@ func (q *MatchQuery) CutoffFrequency(cutoff float64) *MatchQuery { return q } +// MinimumShouldMatch sets the optional minimumShouldMatch value to +// apply to the query. func (q *MatchQuery) MinimumShouldMatch(minimumShouldMatch string) *MatchQuery { q.minimumShouldMatch = minimumShouldMatch return q } -func (q *MatchQuery) Rewrite(rewrite string) *MatchQuery { - q.rewrite = rewrite - return q -} - +// FuzzyRewrite sets the fuzzy_rewrite parameter controlling how the +// fuzzy query will get rewritten. func (q *MatchQuery) FuzzyRewrite(fuzzyRewrite string) *MatchQuery { q.fuzzyRewrite = fuzzyRewrite return q } +// FuzzyTranspositions sets whether transpositions are supported in +// fuzzy queries. +// +// The default metric used by fuzzy queries to determine a match is +// the Damerau-Levenshtein distance formula which supports transpositions. +// Setting transposition to false will +// * switch to classic Levenshtein distance. +// * If not set, Damerau-Levenshtein distance metric will be used. func (q *MatchQuery) FuzzyTranspositions(fuzzyTranspositions bool) *MatchQuery { q.fuzzyTranspositions = &fuzzyTranspositions return q @@ -141,6 +119,12 @@ func (q *MatchQuery) ZeroTermsQuery(zeroTermsQuery string) *MatchQuery { return q } +// Boost sets the boost to apply to this query. +func (q *MatchQuery) Boost(boost float64) *MatchQuery { + q.boost = &boost + return q +} + // QueryName sets the query name for the filter that can be used when // searching for matched filters per hit. func (q *MatchQuery) QueryName(queryName string) *MatchQuery { @@ -161,21 +145,12 @@ func (q *MatchQuery) Source() (interface{}, error) { query["query"] = q.text - if q.typ != "" { - query["type"] = q.typ - } if q.operator != "" { query["operator"] = q.operator } if q.analyzer != "" { query["analyzer"] = q.analyzer } - if q.boost != nil { - query["boost"] = *q.boost - } - if q.slop != nil { - query["slop"] = *q.slop - } if q.fuzziness != "" { query["fuzziness"] = q.fuzziness } @@ -188,9 +163,6 @@ func (q *MatchQuery) Source() (interface{}, error) { if q.minimumShouldMatch != "" { query["minimum_should_match"] = q.minimumShouldMatch } - if q.rewrite != "" { - query["rewrite"] = q.rewrite - } if q.fuzzyRewrite != "" { query["fuzzy_rewrite"] = q.fuzzyRewrite } @@ -206,6 +178,9 @@ func (q *MatchQuery) Source() (interface{}, error) { if q.cutoffFrequency != nil { query["cutoff_frequency"] = q.cutoffFrequency } + if q.boost != nil { + query["boost"] = *q.boost + } if q.queryName != "" { query["_name"] = q.queryName } diff --git a/search_queries_match_all.go b/search_queries_match_all.go index d681ba237..5551eea30 100644 --- a/search_queries_match_all.go +++ b/search_queries_match_all.go @@ -10,7 +10,8 @@ package elastic // For more details, see // https://www.elastic.co/guide/en/elasticsearch/reference/5.2/query-dsl-match-all-query.html type MatchAllQuery struct { - boost *float64 + boost *float64 + queryName string } // NewMatchAllQuery creates and initializes a new match all query. @@ -26,7 +27,13 @@ func (q *MatchAllQuery) Boost(boost float64) *MatchAllQuery { return q } -// Source returns JSON for the function score query. +// QueryName sets the query name. +func (q *MatchAllQuery) QueryName(name string) *MatchAllQuery { + q.queryName = name + return q +} + +// Source returns JSON for the match all query. func (q MatchAllQuery) Source() (interface{}, error) { // { // "match_all" : { ... } @@ -37,5 +44,8 @@ func (q MatchAllQuery) Source() (interface{}, error) { if q.boost != nil { params["boost"] = *q.boost } + if q.queryName != "" { + params["_name"] = q.queryName + } return source, nil } diff --git a/search_queries_match_all_test.go b/search_queries_match_all_test.go index 11cf5c5f7..5d8671025 100644 --- a/search_queries_match_all_test.go +++ b/search_queries_match_all_test.go @@ -42,3 +42,20 @@ func TestMatchAllQueryWithBoost(t *testing.T) { t.Errorf("expected\n%s\n,got:\n%s", expected, got) } } + +func TestMatchAllQueryWithQueryName(t *testing.T) { + q := NewMatchAllQuery().QueryName("qname") + src, err := q.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"match_all":{"_name":"qname"}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} diff --git a/search_queries_match_none.go b/search_queries_match_none.go new file mode 100644 index 000000000..06d036e71 --- /dev/null +++ b/search_queries_match_none.go @@ -0,0 +1,39 @@ +// 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 + +// MatchNoneQuery returns no documents. It is the inverse of +// MatchAllQuery. +// +// For more details, see +// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-match-all-query.html +type MatchNoneQuery struct { + queryName string +} + +// NewMatchNoneQuery creates and initializes a new match none query. +func NewMatchNoneQuery() *MatchNoneQuery { + return &MatchNoneQuery{} +} + +// QueryName sets the query name. +func (q *MatchNoneQuery) QueryName(name string) *MatchNoneQuery { + q.queryName = name + return q +} + +// Source returns JSON for the match none query. +func (q MatchNoneQuery) Source() (interface{}, error) { + // { + // "match_none" : { ... } + // } + source := make(map[string]interface{}) + params := make(map[string]interface{}) + source["match_none"] = params + if q.queryName != "" { + params["_name"] = q.queryName + } + return source, nil +} diff --git a/search_queries_match_none_test.go b/search_queries_match_none_test.go new file mode 100644 index 000000000..6463452da --- /dev/null +++ b/search_queries_match_none_test.go @@ -0,0 +1,44 @@ +// 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 ( + "encoding/json" + "testing" +) + +func TestMatchNoneQuery(t *testing.T) { + q := NewMatchNoneQuery() + src, err := q.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"match_none":{}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} + +func TestMatchNoneQueryWithQueryName(t *testing.T) { + q := NewMatchNoneQuery().QueryName("qname") + src, err := q.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"match_none":{"_name":"qname"}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} diff --git a/search_queries_match_phrase.go b/search_queries_match_phrase.go new file mode 100644 index 000000000..fdded2e76 --- /dev/null +++ b/search_queries_match_phrase.go @@ -0,0 +1,79 @@ +// 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 + +// MatchPhraseQuery analyzes the text and creates a phrase query out of +// the analyzed text. +// +// For more details, see +// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-match-query-phrase.html +type MatchPhraseQuery struct { + name string + value interface{} + analyzer string + slop *int + boost *float64 + queryName string +} + +// NewMatchPhraseQuery creates and initializes a new MatchPhraseQuery. +func NewMatchPhraseQuery(name string, value interface{}) *MatchPhraseQuery { + return &MatchPhraseQuery{name: name, value: value} +} + +// Analyzer explicitly sets the analyzer to use. It defaults to use explicit +// mapping config for the field, or, if not set, the default search analyzer. +func (q *MatchPhraseQuery) Analyzer(analyzer string) *MatchPhraseQuery { + q.analyzer = analyzer + return q +} + +// Slop sets the phrase slop if evaluated to a phrase query type. +func (q *MatchPhraseQuery) Slop(slop int) *MatchPhraseQuery { + q.slop = &slop + return q +} + +// Boost sets the boost to apply to this query. +func (q *MatchPhraseQuery) Boost(boost float64) *MatchPhraseQuery { + q.boost = &boost + return q +} + +// QueryName sets the query name for the filter that can be used when +// searching for matched filters per hit. +func (q *MatchPhraseQuery) QueryName(queryName string) *MatchPhraseQuery { + q.queryName = queryName + return q +} + +// Source returns JSON for the function score query. +func (q *MatchPhraseQuery) Source() (interface{}, error) { + // {"match_phrase":{"name":{"query":"value","analyzer":"my_analyzer"}}} + source := make(map[string]interface{}) + + match := make(map[string]interface{}) + source["match_phrase"] = match + + query := make(map[string]interface{}) + match[q.name] = query + + query["query"] = q.value + + if q.analyzer != "" { + query["analyzer"] = q.analyzer + } + if q.slop != nil { + query["slop"] = *q.slop + } + if q.boost != nil { + query["boost"] = *q.boost + } + if q.queryName != "" { + query["_name"] = q.queryName + } + + return source, nil +} diff --git a/search_queries_match_phrase_prefix.go b/search_queries_match_phrase_prefix.go new file mode 100644 index 000000000..1eeba8af5 --- /dev/null +++ b/search_queries_match_phrase_prefix.go @@ -0,0 +1,89 @@ +// 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 + +// MatchPhrasePrefixQuery is the same as match_phrase, except that it allows for +// prefix matches on the last term in the text. +// +// For more details, see +// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-match-query-phrase-prefix.html +type MatchPhrasePrefixQuery struct { + name string + value interface{} + analyzer string + slop *int + maxExpansions *int + boost *float64 + queryName string +} + +// NewMatchPhrasePrefixQuery creates and initializes a new MatchPhrasePrefixQuery. +func NewMatchPhrasePrefixQuery(name string, value interface{}) *MatchPhrasePrefixQuery { + return &MatchPhrasePrefixQuery{name: name, value: value} +} + +// Analyzer explicitly sets the analyzer to use. It defaults to use explicit +// mapping config for the field, or, if not set, the default search analyzer. +func (q *MatchPhrasePrefixQuery) Analyzer(analyzer string) *MatchPhrasePrefixQuery { + q.analyzer = analyzer + return q +} + +// Slop sets the phrase slop if evaluated to a phrase query type. +func (q *MatchPhrasePrefixQuery) Slop(slop int) *MatchPhrasePrefixQuery { + q.slop = &slop + return q +} + +// MaxExpansions sets the number of term expansions to use. +func (q *MatchPhrasePrefixQuery) MaxExpansions(n int) *MatchPhrasePrefixQuery { + q.maxExpansions = &n + return q +} + +// Boost sets the boost to apply to this query. +func (q *MatchPhrasePrefixQuery) Boost(boost float64) *MatchPhrasePrefixQuery { + q.boost = &boost + return q +} + +// QueryName sets the query name for the filter that can be used when +// searching for matched filters per hit. +func (q *MatchPhrasePrefixQuery) QueryName(queryName string) *MatchPhrasePrefixQuery { + q.queryName = queryName + return q +} + +// Source returns JSON for the function score query. +func (q *MatchPhrasePrefixQuery) Source() (interface{}, error) { + // {"match_phrase_prefix":{"name":{"query":"value","max_expansions":10}}} + source := make(map[string]interface{}) + + match := make(map[string]interface{}) + source["match_phrase_prefix"] = match + + query := make(map[string]interface{}) + match[q.name] = query + + query["query"] = q.value + + if q.analyzer != "" { + query["analyzer"] = q.analyzer + } + if q.slop != nil { + query["slop"] = *q.slop + } + if q.maxExpansions != nil { + query["max_expansions"] = *q.maxExpansions + } + if q.boost != nil { + query["boost"] = *q.boost + } + if q.queryName != "" { + query["_name"] = q.queryName + } + + return source, nil +} diff --git a/search_queries_match_phrase_prefix_test.go b/search_queries_match_phrase_prefix_test.go new file mode 100644 index 000000000..82a02f17d --- /dev/null +++ b/search_queries_match_phrase_prefix_test.go @@ -0,0 +1,27 @@ +// 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 ( + "encoding/json" + "testing" +) + +func TestMatchPhrasePrefixQuery(t *testing.T) { + q := NewMatchPhrasePrefixQuery("message", "this is a test").Boost(0.3).MaxExpansions(5) + src, err := q.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"match_phrase_prefix":{"message":{"boost":0.3,"max_expansions":5,"query":"this is a test"}}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} diff --git a/search_queries_match_phrase_test.go b/search_queries_match_phrase_test.go new file mode 100644 index 000000000..85e60d8b5 --- /dev/null +++ b/search_queries_match_phrase_test.go @@ -0,0 +1,29 @@ +// 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 ( + "encoding/json" + "testing" +) + +func TestMatchPhraseQuery(t *testing.T) { + q := NewMatchPhraseQuery("message", "this is a test"). + Analyzer("my_analyzer"). + Boost(0.7) + src, err := q.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"match_phrase":{"message":{"analyzer":"my_analyzer","boost":0.7,"query":"this is a test"}}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} diff --git a/search_queries_match_test.go b/search_queries_match_test.go index af3fe688a..dd750cf93 100644 --- a/search_queries_match_test.go +++ b/search_queries_match_test.go @@ -26,40 +26,6 @@ func TestMatchQuery(t *testing.T) { } } -func TestMatchPhraseQuery(t *testing.T) { - q := NewMatchPhraseQuery("message", "this is a test") - src, err := q.Source() - if err != nil { - t.Fatal(err) - } - data, err := json.Marshal(src) - if err != nil { - t.Fatalf("marshaling to JSON failed: %v", err) - } - got := string(data) - expected := `{"match":{"message":{"query":"this is a test","type":"phrase"}}}` - if got != expected { - t.Errorf("expected\n%s\n,got:\n%s", expected, got) - } -} - -func TestMatchPhrasePrefixQuery(t *testing.T) { - q := NewMatchPhrasePrefixQuery("message", "this is a test") - src, err := q.Source() - if err != nil { - t.Fatal(err) - } - data, err := json.Marshal(src) - if err != nil { - t.Fatalf("marshaling to JSON failed: %v", err) - } - got := string(data) - expected := `{"match":{"message":{"query":"this is a test","type":"phrase_prefix"}}}` - if got != expected { - t.Errorf("expected\n%s\n,got:\n%s", expected, got) - } -} - func TestMatchQueryWithOptions(t *testing.T) { q := NewMatchQuery("message", "this is a test").Analyzer("whitespace").Operator("or").Boost(2.5) src, err := q.Source() diff --git a/search_queries_more_like_this_test.go b/search_queries_more_like_this_test.go index 6fc5b1c72..dcbbe74d1 100644 --- a/search_queries_more_like_this_test.go +++ b/search_queries_more_like_this_test.go @@ -57,17 +57,17 @@ func TestMoreLikeThisQuery(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/search_queries_simple_query_string_test.go b/search_queries_simple_query_string_test.go index cef7c5f51..ea4a341ec 100644 --- a/search_queries_simple_query_string_test.go +++ b/search_queries_simple_query_string_test.go @@ -36,17 +36,17 @@ func TestSimpleQueryStringQueryExec(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/search_request.go b/search_request.go index ad22a5a3f..03513085f 100644 --- a/search_request.go +++ b/search_request.go @@ -194,9 +194,12 @@ func (r *SearchRequest) header() interface{} { return h } -// body is used by MultiSearch to get information about the search body +// Body allows to access the search body of the request, as generated by the DSL. +// Notice that Body is read-only. You must not change the request body. +// +// Body is used e.g. by MultiSearch to get information about the search body // of one SearchRequest. -// See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-multi-search.html -func (r *SearchRequest) body() interface{} { +// See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-multi-search.html +func (r *SearchRequest) Body() interface{} { return r.source } diff --git a/search_source_test.go b/search_source_test.go index 1e4c814f4..49e52f660 100644 --- a/search_source_test.go +++ b/search_source_test.go @@ -178,7 +178,7 @@ func TestSearchSourceHighlight(t *testing.T) { func TestSearchSourceRescoring(t *testing.T) { matchAllQ := NewMatchAllQuery() - rescorerQuery := NewMatchQuery("field1", "the quick brown fox").Type("phrase").Slop(2) + rescorerQuery := NewMatchPhraseQuery("field1", "the quick brown fox").Slop(2) rescorer := NewQueryRescorer(rescorerQuery) rescorer = rescorer.QueryWeight(0.7) rescorer = rescorer.RescoreQueryWeight(1.2) @@ -193,7 +193,7 @@ func TestSearchSourceRescoring(t *testing.T) { t.Fatalf("marshaling to JSON failed: %v", err) } got := string(data) - expected := `{"query":{"match_all":{}},"rescore":{"query":{"query_weight":0.7,"rescore_query":{"match":{"field1":{"query":"the quick brown fox","slop":2,"type":"phrase"}}},"rescore_query_weight":1.2},"window_size":50}}` + expected := `{"query":{"match_all":{}},"rescore":{"query":{"query_weight":0.7,"rescore_query":{"match_phrase":{"field1":{"query":"the quick brown fox","slop":2}}},"rescore_query_weight":1.2},"window_size":50}}` if got != expected { t.Errorf("expected\n%s\n,got:\n%s", expected, got) } diff --git a/search_suggester_test.go b/search_suggester_test.go index 78232e9d6..387ee90d7 100644 --- a/search_suggester_test.go +++ b/search_suggester_test.go @@ -17,17 +17,17 @@ func TestTermSuggester(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -92,17 +92,17 @@ func TestPhraseSuggester(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -172,17 +172,17 @@ func TestCompletionSuggester(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -238,3 +238,109 @@ func TestCompletionSuggester(t *testing.T) { t.Errorf("expected Text = 'Golang'; got %s", myOption.Text) } } + +func TestContextSuggester(t *testing.T) { + client := setupTestClientAndCreateIndex(t) // , SetTraceLog(log.New(os.Stdout, "", 0))) + + // TODO make a nice way of creating tweets, as currently the context fields are unsupported as part of the suggestion fields + tweet1 := ` + { + "user":"olivere", + "message":"Welcome to Golang and Elasticsearch.", + "retweets":0, + "created":"0001-01-01T00:00:00Z", + "suggest_field":{ + "input":[ + "Golang", + "Elasticsearch" + ], + "contexts":{ + "user_name": ["olivere"] + } + } + } + ` + tweet2 := ` + { + "user":"sandrae", + "message":"I like golfing", + "retweets":0, + "created":"0001-01-01T00:00:00Z", + "suggest_field":{ + "input":[ + "Golfing" + ], + "contexts":{ + "user_name": ["sandrae"] + } + } + } + ` + + // Add all documents + _, err := client.Index().Index(testIndexName).Type("doc").Id("1").BodyString(tweet1).Do(context.TODO()) + if err != nil { + t.Fatal(err) + } + + _, err = client.Index().Index(testIndexName).Type("doc").Id("2").BodyString(tweet2).Do(context.TODO()) + if err != nil { + t.Fatal(err) + } + + _, err = client.Flush().Index(testIndexName).Do(context.TODO()) + if err != nil { + t.Fatal(err) + } + + suggesterName := "my-suggestions" + cs := NewContextSuggester(suggesterName) + cs = cs.Prefix("Gol") + cs = cs.Field("suggest_field") + cs = cs.ContextQueries( + NewSuggesterCategoryQuery("user_name", "olivere"), + ) + + searchResult, err := client.Search(). + Index(testIndexName). + Suggester(cs). + Do(context.TODO()) + if err != nil { + t.Fatal(err) + } + if searchResult.Suggest == nil { + t.Errorf("expected SearchResult.Suggest != nil; got nil") + } + mySuggestions, found := searchResult.Suggest[suggesterName] + if !found { + t.Errorf("expected to find SearchResult.Suggest[%s]; got false", suggesterName) + } + if mySuggestions == nil { + t.Errorf("expected SearchResult.Suggest[%s] != nil; got nil", suggesterName) + } + + // sandra's tweet is not returned because of the user_name context + if len(mySuggestions) != 1 { + t.Errorf("expected 1 suggestion; got %d", len(mySuggestions)) + } + mySuggestion := mySuggestions[0] + if mySuggestion.Text != "Gol" { + t.Errorf("expected Text = 'Gol'; got %s", mySuggestion.Text) + } + if mySuggestion.Offset != 0 { + t.Errorf("expected Offset = %d; got %d", 0, mySuggestion.Offset) + } + if mySuggestion.Length != 3 { + t.Errorf("expected Length = %d; got %d", 3, mySuggestion.Length) + } + if len(mySuggestion.Options) != 1 { + t.Errorf("expected 1 option; got %d", len(mySuggestion.Options)) + } + myOption := mySuggestion.Options[0] + if myOption.Text != "Golang" { + t.Errorf("expected Text = 'Golang'; got %s", myOption.Text) + } + if myOption.Id != "1" { + t.Errorf("expected Id = '1'; got %s", myOption.Id) + } +} diff --git a/search_test.go b/search_test.go index 96346b8b0..d2b3d4a7a 100644 --- a/search_test.go +++ b/search_test.go @@ -215,17 +215,17 @@ func TestSearchSorting(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -288,17 +288,17 @@ func TestSearchSortingBySorters(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -350,17 +350,17 @@ func TestSearchSpecificFields(t *testing.T) { tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."} // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -442,17 +442,17 @@ func TestSearchExplain(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -520,17 +520,17 @@ func TestSearchSource(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -583,17 +583,17 @@ func TestSearchRawString(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -639,17 +639,17 @@ func TestSearchSearchSource(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -716,11 +716,11 @@ func TestSearchInnerHitsOnHasChild(t *testing.T) { comment3b := comment{User: "olivere", Comment: "It sure is."} // Add all documents - _, err = client.Index().Index(testIndexName).Type("tweet").Id("t1").BodyJson(&tweet1).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("t1").BodyJson(&tweet1).Do(context.TODO()) if err != nil { t.Fatal(err) } - _, err = client.Index().Index(testIndexName).Type("tweet").Id("t2").BodyJson(&tweet2).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("t2").BodyJson(&tweet2).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -728,7 +728,7 @@ func TestSearchInnerHitsOnHasChild(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = client.Index().Index(testIndexName).Type("tweet").Id("t3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("t3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -854,11 +854,11 @@ func TestSearchInnerHitsOnHasParent(t *testing.T) { comment3b := comment{User: "olivere", Comment: "It sure is."} // Add all documents - _, err = client.Index().Index(testIndexName).Type("tweet").Id("t1").BodyJson(&tweet1).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("t1").BodyJson(&tweet1).Do(context.TODO()) if err != nil { t.Fatal(err) } - _, err = client.Index().Index(testIndexName).Type("tweet").Id("t2").BodyJson(&tweet2).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("t2").BodyJson(&tweet2).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -866,7 +866,7 @@ func TestSearchInnerHitsOnHasParent(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = client.Index().Index(testIndexName).Type("tweet").Id("t3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("t3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -886,7 +886,7 @@ func TestSearchInnerHitsOnHasParent(t *testing.T) { bq := NewBoolQuery() bq = bq.Must(NewMatchAllQuery()) - bq = bq.Filter(NewHasParentQuery("tweet", NewMatchAllQuery()). + bq = bq.Filter(NewHasParentQuery("doc", NewMatchAllQuery()). InnerHit(NewInnerHit().Name("tweets"))) searchResult, err := client.Search(). @@ -1045,7 +1045,7 @@ func TestSearchFilterPath(t *testing.T) { all := NewMatchAllQuery() searchResult, err := client.Search(). Index(testIndexName). - Type("tweet"). + Type("doc"). Query(all). FilterPath( "took", @@ -1119,17 +1119,17 @@ func TestSearchAfter(t *testing.T) { } // Add all documents - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").BodyJson(&tweet3).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } @@ -1168,7 +1168,7 @@ func TestSearchResultWithFieldCollapsing(t *testing.T) { searchResult, err := client.Search(). Index(testIndexName). - Type("tweet"). + Type("doc"). Query(NewMatchAllQuery()). Collapse(NewCollapseBuilder("user")). Pretty(true). @@ -1215,7 +1215,7 @@ func TestSearchResultWithFieldCollapsingAndInnerHits(t *testing.T) { searchResult, err := client.Search(). Index(testIndexName). - Type("tweet"). + Type("doc"). Query(NewMatchAllQuery()). Collapse( NewCollapseBuilder("user"). diff --git a/setup_test.go b/setup_test.go index b3c04c362..654dcbaa7 100644 --- a/setup_test.go +++ b/setup_test.go @@ -16,15 +16,15 @@ import ( const ( testIndexName = "elastic-test" testIndexName2 = "elastic-test2" + testIndexName3 = "elastic-test3" testMapping = ` { "settings":{ "number_of_shards":1, - "number_of_replicas":0, - "index.mapping.single_type" : false + "number_of_replicas":0 }, "mappings":{ - "tweet":{ + "doc":{ "properties":{ "user":{ "type":"keyword" @@ -41,16 +41,35 @@ const ( "type":"geo_point" }, "suggest_field":{ - "type":"completion" + "type":"completion", + "contexts":[ + { + "name":"user_name", + "type":"category" + } + ] + }, + "comments_join_field": { + "type": "join", + "relations": { + "tweet": "comment" + } } } - }, - "comment":{ - "_parent": { - "type": "tweet" - } - }, - "order":{ + } + } +} +` + + testOrderIndex = "elastic-orders" + testOrderMapping = ` +{ + "settings":{ + "number_of_shards":1, + "number_of_replicas":0 + }, + "mappings":{ + "doc":{ "properties":{ "article":{ "type":"text" @@ -66,8 +85,20 @@ const ( "format": "YYYY-MM-dd" } } - }, - "doctype":{ + } + } +} +` + + testDoctypeIndex = "elastic-doctypes" + testDoctypeMapping = ` +{ + "settings":{ + "number_of_shards":1, + "number_of_replicas":0 + }, + "mappings":{ + "doc":{ "properties":{ "message":{ "type":"text", @@ -75,9 +106,21 @@ const ( "fielddata": true } } - }, - "queries":{ - "properties": { + } + } +} +` + + testQueryIndex = "elastic-queries" + testQueryMapping = ` +{ + "settings":{ + "number_of_shards":1, + "number_of_replicas":0 + }, + "mappings":{ + "doc":{ + "properties":{ "query": { "type": "percolator" } @@ -163,6 +206,10 @@ func setupTestClient(t logger, options ...ClientOptionFunc) (client *Client) { client.DeleteIndex(testIndexName).Do(context.TODO()) client.DeleteIndex(testIndexName2).Do(context.TODO()) + client.DeleteIndex(testIndexName3).Do(context.TODO()) + client.DeleteIndex(testOrderIndex).Do(context.TODO()) + client.DeleteIndex(testDoctypeIndex).Do(context.TODO()) + client.DeleteIndex(testQueryIndex).Do(context.TODO()) return client } @@ -202,24 +249,26 @@ func setupTestClientAndCreateIndexAndAddDocs(t logger, options ...ClientOptionFu 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."} - comment1 := comment{User: "nico", Comment: "You bet."} + //comment1 := comment{User: "nico", Comment: "You bet."} - _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do(context.TODO()) + _, 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("tweet").Id("2").BodyJson(&tweet2).Do(context.TODO()) + _, 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("tweet").Id("3").Routing("someroutingkey").BodyJson(&tweet3).Do(context.TODO()) - if err != nil { - t.Fatal(err) - } - _, err = client.Index().Index(testIndexName).Type("comment").Id("1").Parent("3").BodyJson(&comment1).Do(context.TODO()) + _, err = client.Index().Index(testIndexName).Type("doc").Id("3").Routing("someroutingkey").BodyJson(&tweet3).Do(context.TODO()) if err != nil { t.Fatal(err) } + /* + _, err = client.Index().Index(testIndexName).Type("comment").Id("1").Parent("3").BodyJson(&comment1).Do(context.TODO()) + if err != nil { + t.Fatal(err) + } + */ // Add orders var orders []order @@ -233,7 +282,7 @@ func setupTestClientAndCreateIndexAndAddDocs(t logger, options ...ClientOptionFu orders = append(orders, order{Article: "T-Shirt", Manufacturer: "h&m", Price: 19, Time: "2015-06-18"}) for i, o := range orders { id := fmt.Sprintf("%d", i) - _, err = client.Index().Index(testIndexName).Type("order").Id(id).BodyJson(&o).Do(context.TODO()) + _, err = client.Index().Index(testOrderIndex).Type("doc").Id(id).BodyJson(&o).Do(context.TODO()) if err != nil { t.Fatal(err) } diff --git a/snapshot_create.go b/snapshot_create.go index cec4a4c62..1965f9829 100644 --- a/snapshot_create.go +++ b/snapshot_create.go @@ -137,7 +137,12 @@ func (s *SnapshotCreateService) Do(ctx context.Context) (*SnapshotCreateResponse } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/snapshot_create_repository.go b/snapshot_create_repository.go index 6564ad121..961a3188f 100644 --- a/snapshot_create_repository.go +++ b/snapshot_create_repository.go @@ -179,7 +179,12 @@ func (s *SnapshotCreateRepositoryService) Do(ctx context.Context) (*SnapshotCrea } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "PUT", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "PUT", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/snapshot_delete_repository.go b/snapshot_delete_repository.go index 3b11f689f..47fcdf8e1 100644 --- a/snapshot_delete_repository.go +++ b/snapshot_delete_repository.go @@ -107,7 +107,11 @@ func (s *SnapshotDeleteRepositoryService) Do(ctx context.Context) (*SnapshotDele } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "DELETE", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "DELETE", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/snapshot_get_repository.go b/snapshot_get_repository.go index 71c73fce3..c99db8982 100644 --- a/snapshot_get_repository.go +++ b/snapshot_get_repository.go @@ -106,7 +106,11 @@ func (s *SnapshotGetRepositoryService) Do(ctx context.Context) (SnapshotGetRepos } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/snapshot_verify_repository.go b/snapshot_verify_repository.go index 0f0abdf62..4fe0e066f 100644 --- a/snapshot_verify_repository.go +++ b/snapshot_verify_repository.go @@ -105,7 +105,11 @@ func (s *SnapshotVerifyRepositoryService) Do(ctx context.Context) (*SnapshotVeri } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/suggester_context.go b/suggester_context.go index caf477669..ade099151 100644 --- a/suggester_context.go +++ b/suggester_context.go @@ -4,8 +4,121 @@ package elastic +import "errors" + // SuggesterContextQuery is used to define context information within // a suggestion request. type SuggesterContextQuery interface { Source() (interface{}, error) } + +// ContextSuggester is a fast suggester for e.g. type-ahead completion that supports filtering and boosting based on contexts. +// See https://www.elastic.co/guide/en/elasticsearch/reference/current/suggester-context.html +// for more details. +type ContextSuggester struct { + Suggester + name string + prefix string + field string + size *int + contextQueries []SuggesterContextQuery +} + +// Creates a new context suggester. +func NewContextSuggester(name string) *ContextSuggester { + return &ContextSuggester{ + name: name, + contextQueries: make([]SuggesterContextQuery, 0), + } +} + +func (q *ContextSuggester) Name() string { + return q.name +} + +func (q *ContextSuggester) Prefix(prefix string) *ContextSuggester { + q.prefix = prefix + return q +} + +func (q *ContextSuggester) Field(field string) *ContextSuggester { + q.field = field + return q +} + +func (q *ContextSuggester) Size(size int) *ContextSuggester { + q.size = &size + return q +} + +func (q *ContextSuggester) ContextQuery(query SuggesterContextQuery) *ContextSuggester { + q.contextQueries = append(q.contextQueries, query) + return q +} + +func (q *ContextSuggester) ContextQueries(queries ...SuggesterContextQuery) *ContextSuggester { + q.contextQueries = append(q.contextQueries, queries...) + return q +} + +// contextSuggesterRequest is necessary because the order in which +// the JSON elements are routed to Elasticsearch is relevant. +// We got into trouble when using plain maps because the text element +// needs to go before the completion element. +type contextSuggesterRequest struct { + Prefix string `json:"prefix"` + Completion interface{} `json:"completion"` +} + +// Creates the source for the context suggester. +func (q *ContextSuggester) Source(includeName bool) (interface{}, error) { + cs := &contextSuggesterRequest{} + + if q.prefix != "" { + cs.Prefix = q.prefix + } + + suggester := make(map[string]interface{}) + cs.Completion = suggester + + if q.field != "" { + suggester["field"] = q.field + } + if q.size != nil { + suggester["size"] = *q.size + } + switch len(q.contextQueries) { + case 0: + case 1: + src, err := q.contextQueries[0].Source() + if err != nil { + return nil, err + } + suggester["context"] = src + default: + ctxq := make(map[string]interface{}) + for _, query := range q.contextQueries { + src, err := query.Source() + if err != nil { + return nil, err + } + // Merge the dictionary into ctxq + m, ok := src.(map[string]interface{}) + if !ok { + return nil, errors.New("elastic: context query is not a map") + } + for k, v := range m { + ctxq[k] = v + } + } + suggester["contexts"] = ctxq + } + + if !includeName { + return cs, nil + } + + source := make(map[string]interface{}) + source[q.name] = cs + return source, nil +} diff --git a/suggester_context_test.go b/suggester_context_test.go new file mode 100644 index 000000000..cd3c5586c --- /dev/null +++ b/suggester_context_test.go @@ -0,0 +1,55 @@ +// 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 ( + "encoding/json" + "testing" +) + +func TestContextSuggesterSource(t *testing.T) { + s := NewContextSuggester("place_suggestion"). + Prefix("tim"). + Field("suggest") + src, err := s.Source(true) + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"place_suggestion":{"prefix":"tim","completion":{"field":"suggest"}}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} + +func TestContextSuggesterSourceWithMultipleContexts(t *testing.T) { + s := NewContextSuggester("place_suggestion"). + Prefix("tim"). + Field("suggest"). + ContextQueries( + NewSuggesterCategoryQuery("place_type", "cafe", "restaurants"), + ) + src, err := s.Source(true) + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + // Due to the randomization of dictionary key, we could actually have two different valid expected outcomes + expected := `{"place_suggestion":{"prefix":"tim","completion":{"context":{"place_type":[{"context":"cafe"},{"context":"restaurants"}]},"field":"suggest"}}}` + if got != expected { + expected := `{"place_suggestion":{"prefix":"tim","completion":{"context":{"place_type":[{"context":"restaurants"},{"context":"cafe"}]},"field":"suggest"}}}` + if got != expected { + t.Errorf("expected %s\n,got:\n%s", expected, got) + } + } +} diff --git a/tasks_cancel.go b/tasks_cancel.go index 067a9d950..140cc3491 100644 --- a/tasks_cancel.go +++ b/tasks_cancel.go @@ -131,7 +131,11 @@ func (s *TasksCancelService) Do(ctx context.Context) (*TasksListResponse, error) } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/tasks_get_task.go b/tasks_get_task.go index 1ccae8774..c08f237c8 100644 --- a/tasks_get_task.go +++ b/tasks_get_task.go @@ -85,7 +85,11 @@ func (s *TasksGetTaskService) Do(ctx context.Context) (*TasksGetTaskResponse, er } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/tasks_list.go b/tasks_list.go index 8703cdc43..dfbf4c3b6 100644 --- a/tasks_list.go +++ b/tasks_list.go @@ -156,7 +156,11 @@ func (s *TasksListService) Do(ctx context.Context) (*TasksListResponse, error) { } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, nil) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + }) if err != nil { return nil, err } diff --git a/termvectors.go b/termvectors.go index 3a1c0a763..2dc1580ff 100644 --- a/termvectors.go +++ b/termvectors.go @@ -316,7 +316,12 @@ func (s *TermvectorsService) Do(ctx context.Context) (*TermvectorsResponse, erro } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "GET", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "GET", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/termvectors_test.go b/termvectors_test.go index fb0ede146..0391f2b0a 100644 --- a/termvectors_test.go +++ b/termvectors_test.go @@ -21,15 +21,15 @@ func TestTermVectorsBuildURL(t *testing.T) { }{ { "twitter", - "tweet", + "doc", "", - "/twitter/tweet/_termvectors", + "/twitter/doc/_termvectors", }, { "twitter", - "tweet", + "doc", "1", - "/twitter/tweet/1/_termvectors", + "/twitter/doc/1/_termvectors", }, } @@ -56,7 +56,7 @@ func TestTermVectorsWithId(t *testing.T) { // Add a document indexResult, err := client.Index(). Index(testIndexName). - Type("tweet"). + Type("doc"). Id("1"). BodyJson(&tweet1). Refresh("true"). @@ -70,7 +70,7 @@ func TestTermVectorsWithId(t *testing.T) { // TermVectors by specifying ID field := "Message" - result, err := client.TermVectors(testIndexName, "tweet"). + result, err := client.TermVectors(testIndexName, "doc"). Id("1"). Fields(field). FieldStatistics(true). @@ -104,7 +104,7 @@ func TestTermVectorsWithDoc(t *testing.T) { "fullname": "keyword", } - result, err := client.TermVectors(testIndexName, "tweet"). + result, err := client.TermVectors(testIndexName, "doc"). Doc(doc). PerFieldAnalyzer(perFieldAnalyzer). FieldStatistics(true). @@ -138,7 +138,7 @@ func TestTermVectorsWithFilter(t *testing.T) { "fullname": "keyword", } - result, err := client.TermVectors(testIndexName, "tweet"). + result, err := client.TermVectors(testIndexName, "doc"). Doc(doc). PerFieldAnalyzer(perFieldAnalyzer). FieldStatistics(true). diff --git a/update.go b/update.go index a0468d1f3..c8d073b21 100644 --- a/update.go +++ b/update.go @@ -293,7 +293,12 @@ func (b *UpdateService) Do(ctx context.Context) (*UpdateResponse, error) { } // Get response - res, err := b.client.PerformRequest(ctx, "POST", path, params, body) + res, err := b.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } @@ -308,12 +313,15 @@ func (b *UpdateService) Do(ctx context.Context) (*UpdateResponse, error) { // UpdateResponse is the result of updating a document in Elasticsearch. type UpdateResponse struct { - Index string `json:"_index"` - Type string `json:"_type"` - Id string `json:"_id"` - Version int `json:"_version"` - Shards *shardsInfo `json:"_shards"` + Index string `json:"_index,omitempty"` + Type string `json:"_type,omitempty"` + Id string `json:"_id,omitempty"` + Version int64 `json:"_version,omitempty"` Result string `json:"result,omitempty"` + Shards *shardsInfo `json:"_shards,omitempty"` + SeqNo int64 `json:"_seq_no,omitempty"` + PrimaryTerm int64 `json:"_primary_term,omitempty"` + Status int `json:"status,omitempty"` ForcedRefresh bool `json:"forced_refresh,omitempty"` GetResult *GetResult `json:"get,omitempty"` } diff --git a/update_by_query.go b/update_by_query.go index 7b1f03b93..c7934fcf3 100644 --- a/update_by_query.go +++ b/update_by_query.go @@ -636,7 +636,12 @@ func (s *UpdateByQueryService) Do(ctx context.Context) (*BulkIndexByScrollRespon } // Get HTTP response - res, err := s.client.PerformRequest(ctx, "POST", path, params, body) + res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ + Method: "POST", + Path: path, + Params: params, + Body: body, + }) if err != nil { return nil, err } diff --git a/update_test.go b/update_test.go index 8801bacb2..fd5c62deb 100644 --- a/update_test.go +++ b/update_test.go @@ -275,7 +275,7 @@ func TestUpdateViaDocAndUpsertAndFetchSource(t *testing.T) { func TestUpdateAndFetchSource(t *testing.T) { client := setupTestClientAndCreateIndexAndAddDocs(t) // , SetTraceLog(log.New(os.Stdout, "", 0))) res, err := client.Update(). - Index(testIndexName).Type("tweet").Id("1"). + Index(testIndexName).Type("doc").Id("1"). Doc(map[string]interface{}{"user": "sandrae"}). DetectNoop(true). FetchSource(true).