move phrase search logic into phrase searcher
the logic of how a phrase search works should be an internal detail of the phrase searcher. further, these changes will allow proper scoring of phrase matches, which require access to the underlying searcher objects, which were hidden in the previous approach.
This commit is contained in:
parent
97a428f5b0
commit
4e38c49287
|
@ -25,10 +25,9 @@ import (
|
|||
)
|
||||
|
||||
type PhraseQuery struct {
|
||||
Terms []string `json:"terms"`
|
||||
Field string `json:"field,omitempty"`
|
||||
BoostVal *Boost `json:"boost,omitempty"`
|
||||
termQueries []Query
|
||||
Terms []string `json:"terms"`
|
||||
Field string `json:"field,omitempty"`
|
||||
BoostVal *Boost `json:"boost,omitempty"`
|
||||
}
|
||||
|
||||
// NewPhraseQuery creates a new Query for finding
|
||||
|
@ -38,18 +37,9 @@ type PhraseQuery struct {
|
|||
// specified field. Queried field must have been indexed with
|
||||
// IncludeTermVectors set to true.
|
||||
func NewPhraseQuery(terms []string, field string) *PhraseQuery {
|
||||
termQueries := make([]Query, 0)
|
||||
for _, term := range terms {
|
||||
if term != "" {
|
||||
tq := NewTermQuery(term)
|
||||
tq.SetField(field)
|
||||
termQueries = append(termQueries, tq)
|
||||
}
|
||||
}
|
||||
return &PhraseQuery{
|
||||
Terms: terms,
|
||||
Field: field,
|
||||
termQueries: termQueries,
|
||||
Terms: terms,
|
||||
Field: field,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,18 +53,11 @@ func (q *PhraseQuery) Boost() float64 {
|
|||
}
|
||||
|
||||
func (q *PhraseQuery) Searcher(i index.IndexReader, m mapping.IndexMapping, options search.SearcherOptions) (search.Searcher, error) {
|
||||
options.IncludeTermVectors = true
|
||||
|
||||
conjunctionQuery := NewConjunctionQuery(q.termQueries)
|
||||
conjunctionSearcher, err := conjunctionQuery.Searcher(i, m, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return searcher.NewPhraseSearcher(i, conjunctionSearcher.(*searcher.ConjunctionSearcher), q.Terms)
|
||||
return searcher.NewPhraseSearcher(i, q.Terms, q.Field, options)
|
||||
}
|
||||
|
||||
func (q *PhraseQuery) Validate() error {
|
||||
if len(q.termQueries) < 1 {
|
||||
if len(q.Terms) < 1 {
|
||||
return fmt.Errorf("phrase query must contain at least one term")
|
||||
}
|
||||
return nil
|
||||
|
@ -90,9 +73,5 @@ func (q *PhraseQuery) UnmarshalJSON(data []byte) error {
|
|||
q.Terms = tmp.Terms
|
||||
q.Field = tmp.Field
|
||||
q.BoostVal = tmp.BoostVal
|
||||
q.termQueries = make([]Query, len(q.Terms))
|
||||
for i, term := range q.Terms {
|
||||
q.termQueries[i] = &TermQuery{Term: term, FieldVal: q.Field, BoostVal: q.BoostVal}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -301,14 +301,6 @@ func expandQuery(m mapping.IndexMapping, query Query) (Query, error) {
|
|||
return nil, err
|
||||
}
|
||||
return &q, nil
|
||||
case *PhraseQuery:
|
||||
q := *query.(*PhraseQuery)
|
||||
children, err := expandSlice(q.termQueries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q.termQueries = children
|
||||
return &q, nil
|
||||
default:
|
||||
return query, nil
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package searcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
|
@ -31,7 +32,24 @@ type PhraseSearcher struct {
|
|||
initialized bool
|
||||
}
|
||||
|
||||
func NewPhraseSearcher(indexReader index.IndexReader, mustSearcher *ConjunctionSearcher, terms []string) (*PhraseSearcher, error) {
|
||||
func NewPhraseSearcher(indexReader index.IndexReader, terms []string, field string, options search.SearcherOptions) (*PhraseSearcher, error) {
|
||||
options.IncludeTermVectors = true
|
||||
termSearchers := make([]search.Searcher, 0)
|
||||
for _, term := range terms {
|
||||
if term != "" {
|
||||
ts, err := NewTermSearcher(indexReader, term, field, 1.0, options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("phrase searcher error building term searcher: %v", err)
|
||||
}
|
||||
termSearchers = append(termSearchers, ts)
|
||||
}
|
||||
}
|
||||
|
||||
mustSearcher, err := NewConjunctionSearcher(indexReader, termSearchers, options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("phrase searcher error building conjunction searcher: %v", err)
|
||||
}
|
||||
|
||||
// build our searcher
|
||||
rv := PhraseSearcher{
|
||||
indexReader: indexReader,
|
||||
|
|
|
@ -36,20 +36,7 @@ func TestPhraseSearch(t *testing.T) {
|
|||
}()
|
||||
|
||||
soptions := search.SearcherOptions{Explain: true, IncludeTermVectors: true}
|
||||
|
||||
angstTermSearcher, err := NewTermSearcher(twoDocIndexReader, "angst", "desc", 1.0, soptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, soptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mustSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{angstTermSearcher, beerTermSearcher}, soptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
phraseSearcher, err := NewPhraseSearcher(twoDocIndexReader, mustSearcher, []string{"angst", "beer"})
|
||||
phraseSearcher, err := NewPhraseSearcher(twoDocIndexReader, []string{"angst", "beer"}, "desc", soptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue