diff --git a/search/explanation.go b/search/explanation.go index b1ac29aa8..924050016 100644 --- a/search/explanation.go +++ b/search/explanation.go @@ -30,9 +30,10 @@ func init() { } type Explanation struct { - Value float64 `json:"value"` - Message string `json:"message"` - Children []*Explanation `json:"children,omitempty"` + Value float64 `json:"value"` + Message string `json:"message"` + PartialMatch bool `json:"partial_match,omitempty"` + Children []*Explanation `json:"children,omitempty"` } func (expl *Explanation) String() string { diff --git a/search/scorer/scorer_disjunction.go b/search/scorer/scorer_disjunction.go index fe319bbeb..b3e96ddc7 100644 --- a/search/scorer/scorer_disjunction.go +++ b/search/scorer/scorer_disjunction.go @@ -69,7 +69,7 @@ func (s *DisjunctionQueryScorer) Score(ctx *search.SearchContext, constituents [ ce := make([]*search.Explanation, 2) ce[0] = rawExpl ce[1] = &search.Explanation{Value: coord, Message: fmt.Sprintf("coord(%d/%d)", countMatch, countTotal)} - newExpl = &search.Explanation{Value: newScore, Message: "product of:", Children: ce} + newExpl = &search.Explanation{Value: newScore, Message: "product of:", Children: ce, PartialMatch: countMatch != countTotal} } // reuse constituents[0] as the return value diff --git a/search/search.go b/search/search.go index 8cc5115dc..066f88587 100644 --- a/search/search.go +++ b/search/search.go @@ -167,13 +167,6 @@ type DocumentMatch struct { // results are completed FieldTermLocations []FieldTermLocation `json:"-"` - // used to indicate if this match is a partial match - // in the case of a disjunction search - // this means that the match is partial because - // not all sub-queries matched - // if false, all the sub-queries matched - PartialMatch bool `json:"partial_match,omitempty"` - // used to indicate the sub-scores that combined to form the // final score for this document match. This is only populated // when the search request's query is a DisjunctionQuery diff --git a/search/searcher/search_disjunction_heap.go b/search/searcher/search_disjunction_heap.go index 89bcd498f..3da876bd3 100644 --- a/search/searcher/search_disjunction_heap.go +++ b/search/searcher/search_disjunction_heap.go @@ -218,9 +218,7 @@ func (s *DisjunctionHeapSearcher) Next(ctx *search.SearchContext) ( rv = s.scorer.ScoreAndExplBreakdown(ctx, s.matching, s.matchingIdxs, nil, s.numSearchers) } else { // score this match - partialMatch := len(s.matching) != len(s.searchers) rv = s.scorer.Score(ctx, s.matching, len(s.matching), s.numSearchers) - rv.PartialMatch = partialMatch } } diff --git a/search/searcher/search_disjunction_slice.go b/search/searcher/search_disjunction_slice.go index 81b00cc22..fadfa59ca 100644 --- a/search/searcher/search_disjunction_slice.go +++ b/search/searcher/search_disjunction_slice.go @@ -230,9 +230,7 @@ func (s *DisjunctionSliceSearcher) Next(ctx *search.SearchContext) ( rv = s.scorer.ScoreAndExplBreakdown(ctx, s.matching, s.matchingIdxs, s.originalPos, s.numSearchers) } else { // score this match - partialMatch := len(s.matching) != len(s.searchers) rv = s.scorer.Score(ctx, s.matching, len(s.matching), s.numSearchers) - rv.PartialMatch = partialMatch } } diff --git a/search_test.go b/search_test.go index fdfaa3efb..2271018a6 100644 --- a/search_test.go +++ b/search_test.go @@ -1266,6 +1266,7 @@ func TestMatchQueryPartialMatch(t *testing.T) { mq1.SetField("description") sr := NewSearchRequest(mq1) + sr.Explain = true res, err := idx.Search(sr) if err != nil { t.Fatal(err) @@ -1274,11 +1275,17 @@ func TestMatchQueryPartialMatch(t *testing.T) { t.Errorf("Expected 2 results, but got: %v", res.Total) } for _, hit := range res.Hits { - if hit.ID == "doc1" && hit.PartialMatch { - t.Errorf("Expected doc1 to be a full match") - } - if hit.ID == "doc2" && !hit.PartialMatch { - t.Errorf("Expected doc2 to be a partial match") + switch hit.ID { + case "doc1": + if hit.Expl.PartialMatch { + t.Errorf("Expected doc1 to be a full match") + } + case "doc2": + if !hit.Expl.PartialMatch { + t.Errorf("Expected doc2 to be a partial match") + } + default: + t.Errorf("Unexpected document ID: %s", hit.ID) } } @@ -1288,6 +1295,7 @@ func TestMatchQueryPartialMatch(t *testing.T) { mq2.SetFuzziness(2) sr = NewSearchRequest(mq2) + sr.Explain = true res, err = idx.Search(sr) if err != nil { t.Fatal(err) @@ -1296,11 +1304,17 @@ func TestMatchQueryPartialMatch(t *testing.T) { t.Errorf("Expected 2 results, but got: %v", res.Total) } for _, hit := range res.Hits { - if hit.ID == "doc1" && !hit.PartialMatch { - t.Errorf("Expected doc1 to be a partial match") - } - if hit.ID == "doc2" && hit.PartialMatch { - t.Errorf("Expected doc2 to be a full match") + switch hit.ID { + case "doc1": + if !hit.Expl.PartialMatch { + t.Errorf("Expected doc1 to be a partial match") + } + case "doc2": + if hit.Expl.PartialMatch { + t.Errorf("Expected doc2 to be a full match") + } + default: + t.Errorf("Unexpected document ID: %s", hit.ID) } } // Test 3 - Two Docs hits, both full match @@ -1308,6 +1322,7 @@ func TestMatchQueryPartialMatch(t *testing.T) { mq3.SetField("description") sr = NewSearchRequest(mq3) + sr.Explain = true res, err = idx.Search(sr) if err != nil { t.Fatal(err) @@ -1316,11 +1331,17 @@ func TestMatchQueryPartialMatch(t *testing.T) { t.Errorf("Expected 2 results, but got: %v", res.Total) } for _, hit := range res.Hits { - if hit.ID == "doc1" && hit.PartialMatch { - t.Errorf("Expected doc1 to be a full match") - } - if hit.ID == "doc2" && hit.PartialMatch { - t.Errorf("Expected doc2 to be a full match") + switch hit.ID { + case "doc1": + if hit.Expl.PartialMatch { + t.Errorf("Expected doc1 to be a full match") + } + case "doc2": + if hit.Expl.PartialMatch { + t.Errorf("Expected doc2 to be a full match") + } + default: + t.Errorf("Unexpected document ID: %s", hit.ID) } } // Test 4 - Two Docs hits, both partial match @@ -1328,6 +1349,7 @@ func TestMatchQueryPartialMatch(t *testing.T) { mq4.SetField("description") sr = NewSearchRequest(mq4) + sr.Explain = true res, err = idx.Search(sr) if err != nil { t.Fatal(err) @@ -1336,11 +1358,17 @@ func TestMatchQueryPartialMatch(t *testing.T) { t.Errorf("Expected 2 results, but got: %v", res.Total) } for _, hit := range res.Hits { - if hit.ID == "doc1" && !hit.PartialMatch { - t.Errorf("Expected doc1 to be a partial match") - } - if hit.ID == "doc2" && !hit.PartialMatch { - t.Errorf("Expected doc2 to be a partial match") + switch hit.ID { + case "doc1": + if !hit.Expl.PartialMatch { + t.Errorf("Expected doc1 to be a full match") + } + case "doc2": + if !hit.Expl.PartialMatch { + t.Errorf("Expected doc2 to be a full match") + } + default: + t.Errorf("Unexpected document ID: %s", hit.ID) } } @@ -1350,6 +1378,7 @@ func TestMatchQueryPartialMatch(t *testing.T) { mq5.SetOperator(1) sr = NewSearchRequest(mq5) + sr.Explain = true res, err = idx.Search(sr) if err != nil { t.Fatal(err) @@ -1357,7 +1386,9 @@ func TestMatchQueryPartialMatch(t *testing.T) { if res.Total != 1 { t.Errorf("Expected 1 result, but got: %v", res.Total) } - if res.Hits[0].ID == "doc2" || res.Hits[0].PartialMatch { + hit := res.Hits[0] + fmt.Println(hit.Expl, hit.ID) + if hit.ID != "doc1" || hit.Expl.PartialMatch { t.Errorf("Expected doc1 to be a full match") } }