Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions search/explanation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion search/scorer/scorer_disjunction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 0 additions & 7 deletions search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions search/searcher/search_disjunction_heap.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
2 changes: 0 additions & 2 deletions search/searcher/search_disjunction_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
73 changes: 52 additions & 21 deletions search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
}
}

Expand All @@ -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)
Expand All @@ -1296,18 +1304,25 @@ 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
mq3 := NewMatchQuery("patrick")
mq3.SetField("description")

sr = NewSearchRequest(mq3)
sr.Explain = true
res, err = idx.Search(sr)
if err != nil {
t.Fatal(err)
Expand All @@ -1316,18 +1331,25 @@ 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
mq4 := NewMatchQuery("patrick stewart manager")
mq4.SetField("description")

sr = NewSearchRequest(mq4)
sr.Explain = true
res, err = idx.Search(sr)
if err != nil {
t.Fatal(err)
Expand All @@ -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)
}
}

Expand All @@ -1350,14 +1378,17 @@ 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)
}
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")
}
}
Expand Down
Loading