Repository: olivere/elastic (go)

Issue:
Elasticsearch 5.x  NewCompletionSuggester 返回score 为0 
Please use the following questions as a guideline to help me answer
your issue/question without further inquiry. Thank you.

### Which version of Elastic are you using?


[*] elastic.v5 (for Elasticsearch 5.x)


### Please describe the expected behavior
在用 NewCompletionSuggester  发现返回结果得分全部为0
 
### Please describe the actual behavior
源码search.go 中

// SearchSuggestionOption is an option of a SearchSuggestion.
// See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/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"`
	Highlighted  string           `json:"highlighted"`
	CollateMatch bool             `json:"collate_match"`
	Freq         int              `json:"freq"` // from TermSuggestion.Option in Java API
	Source       *json.RawMessage `json:"_source"`
}

### Any steps to reproduce the behavior?
Score        float64          `json:"score"`  应该 为   Score        float64          `json:"_score"`


Pull request description:
Fix suggester score problem
There's suggester problem that gets value from `_score` key instead of `score` key. I can also reproduce this using docker. Since it has the same with ES 6.x, I cherry-pick the [solution](https://github.com/olivere/elastic/commit/80585846d765de967183044c2840d4ed5e93f9e4) directly.

How to reproduce:
```shell
docker run -p 9200:9200 \
-e ES_JAVA_OPTS="-Xms1g -Xmx1g" -e xpack.security.enabled="false" \
docker.elastic.co/elasticsearch/elasticsearch:5.6.16
```

```shell
curl -X PUT "localhost:9200/music" -H 'Content-Type: application/json' -d'
{
    "mappings": {
        "doc" : {
            "properties" : {
                "suggest" : {
                    "type" : "completion"
                },
                "title" : {
                    "type": "keyword"
                }
            }
        }
    }
}
'
```

```shell
curl -X PUT "localhost:9200/music/doc/1?refresh" -H 'Content-Type: application/json' -d'
{
    "suggest" : {
        "input": [ "Nevermind", "Nirvana" ],
        "weight" : 34
    }
}
'
```



```shell
curl -X POST "localhost:9200/music/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "suggest": {
        "song-suggest" : {
            "prefix" : "nir", 
            "completion" : { 
                "field" : "suggest" 
            }
        }
    }
}
'
```

Result:
```json
{
  "took" : 13,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "suggest" : {
    "song-suggest" : [
      {
        "text" : "nir",
        "offset" : 0,
        "length" : 3,
        "options" : [
          {
            "text" : "Nirvana",
            "_index" : "music",
            "_type" : "doc",
            "_id" : "1",
            "_score" : 34.0,
            "_source" : {
              "suggest" : {
                "input" : [
                  "Nevermind",
                  "Nirvana"
                ],
                "weight" : 34
              }
            }
          }
        ]
      }
    ]
  }
}

```

Please check this @olivere

If there's no problem, we can
Close #1355 issue
Close #1356 PR

Thanks

Patch:
diff --git a/search.go b/search.go
index a9b5ee5..05b4e22 100644
--- a/search.go
+++ b/search.go
@@ -525,15 +525,16 @@ type SearchSuggestion struct {
 // SearchSuggestionOption is an option of a SearchSuggestion.
 // See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/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"`
-	Highlighted  string           `json:"highlighted"`
-	CollateMatch bool             `json:"collate_match"`
-	Freq         int              `json:"freq"` // from TermSuggestion.Option in Java API
-	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"`  // term and phrase suggesters uses "score" as of 5.x
+	ScoreUnderscore float64          `json:"_score"` // completion and context suggesters uses "_score" as of 5.x
+	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


Test patch:
diff --git a/search_suggester_test.go b/search_suggester_test.go
index a555e34..16b8994 100644
--- a/search_suggester_test.go
+++ b/search_suggester_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 func TestTermSuggester(t *testing.T) {
-	client := setupTestClientAndCreateIndex(t)
+	client := setupTestClientAndCreateIndex(t) // AndLog(t)
 
 	tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
 	tweet2 := tweet{User: "olivere", Message: "Another unrelated topic."}
@@ -47,6 +47,7 @@ func TestTermSuggester(t *testing.T) {
 		Index(testIndexName).
 		Query(NewMatchAllQuery()).
 		Suggester(ts).
+		Pretty(true).
 		Do(context.TODO())
 	if err != nil {
 		t.Fatal(err)
@@ -82,10 +83,13 @@ func TestTermSuggester(t *testing.T) {
 	if myOption.Text != "golang" {
 		t.Errorf("expected Text = 'golang'; got %s", myOption.Text)
 	}
+	if score := mySuggestion.Options[0].Score; score <= 0.0 {
+		t.Errorf("expected options[0].Score > 0.0; got %v", score)
+	}
 }
 
 func TestPhraseSuggester(t *testing.T) {
-	client := setupTestClientAndCreateIndex(t)
+	client := setupTestClientAndCreateIndex(t) // AndLog(t)
 
 	tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
 	tweet2 := tweet{User: "olivere", Message: "Another unrelated topic."}
@@ -122,6 +126,7 @@ func TestPhraseSuggester(t *testing.T) {
 		Index(testIndexName).
 		Query(NewMatchAllQuery()).
 		Suggester(ps).
+		Pretty(true).
 		Do(context.TODO())
 	if err != nil {
 		t.Fatal(err)
@@ -153,7 +158,7 @@ func TestPhraseSuggester(t *testing.T) {
 }
 
 func TestCompletionSuggester(t *testing.T) {
-	client := setupTestClientAndCreateIndex(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))
+	client := setupTestClientAndCreateIndex(t) // AndLog(t)
 
 	tweet1 := tweet{
 		User:    "olivere",
@@ -202,6 +207,7 @@ func TestCompletionSuggester(t *testing.T) {
 		Index(testIndexName).
 		Query(NewMatchAllQuery()).
 		Suggester(cs).
+		Pretty(true).
 		Do(context.TODO())
 	if err != nil {
 		t.Fatal(err)
@@ -237,10 +243,13 @@ func TestCompletionSuggester(t *testing.T) {
 	if myOption.Text != "Golang" {
 		t.Errorf("expected Text = 'Golang'; got %s", myOption.Text)
 	}
+	if score := mySuggestion.Options[0].ScoreUnderscore; score <= 0.0 {
+		t.Errorf("expected options[0].ScoreUnderscore > 0.0; got %v", score)
+	}
 }
 
 func TestContextSuggester(t *testing.T) {
-	client := setupTestClientAndCreateIndex(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))
+	client := setupTestClientAndCreateIndex(t) // AndLog(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 := `
@@ -304,6 +313,7 @@ func TestContextSuggester(t *testing.T) {
 	searchResult, err := client.Search().
 		Index(testIndexName).
 		Suggester(cs).
+		Pretty(true).
 		Do(context.TODO())
 	if err != nil {
 		t.Fatal(err)
@@ -343,4 +353,7 @@ func TestContextSuggester(t *testing.T) {
 	if myOption.Id != "1" {
 		t.Errorf("expected Id = '1'; got %s", myOption.Id)
 	}
+	if score := mySuggestion.Options[0].ScoreUnderscore; score <= 0.0 {
+		t.Errorf("expected options[0].ScoreUnderscore > 0.0; got %v", score)
+	}
 }