added conjunction term search/query/score
This commit is contained in:
parent
aeebcdd7fe
commit
aa53d0b340
|
@ -24,8 +24,9 @@ func NewDocument(id string) *Document {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *Document) AddField(f *Field) {
|
||||
func (d *Document) AddField(f *Field) *Document {
|
||||
d.Fields = append(d.Fields, f)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Document) String() string {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
import (
|
||||
"github.com/couchbaselabs/bleve/document"
|
||||
"github.com/couchbaselabs/bleve/index/mock"
|
||||
)
|
||||
|
||||
// sets up some mock data used in many tests in this package
|
||||
|
||||
var twoDocIndexDocs = []*document.Document{
|
||||
// must have 4/4 beer
|
||||
document.NewDocument("1").
|
||||
AddField(document.NewTextField("name", []byte("marty"))).
|
||||
AddField(document.NewTextField("desc", []byte("beer beer beer beer"))),
|
||||
// must have 1/4 beer
|
||||
document.NewDocument("2").
|
||||
AddField(document.NewTextField("name", []byte("steve"))).
|
||||
AddField(document.NewTextField("desc", []byte("angst beer couch database"))),
|
||||
// must have 1/4 beer
|
||||
document.NewDocument("3").
|
||||
AddField(document.NewTextField("name", []byte("dustin"))).
|
||||
AddField(document.NewTextField("desc", []byte("apple beer column dank"))),
|
||||
// must have 65/65 beer
|
||||
document.NewDocument("4").
|
||||
AddField(document.NewTextField("name", []byte("ravi"))).
|
||||
AddField(document.NewTextField("desc", []byte("beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer"))),
|
||||
// must have 0/x beer
|
||||
document.NewDocument("5").
|
||||
AddField(document.NewTextField("name", []byte("bobert"))).
|
||||
AddField(document.NewTextField("desc", []byte("water"))),
|
||||
}
|
||||
|
||||
var twoDocIndex *mock.MockIndex = mock.NewMockIndexWithDocs(twoDocIndexDocs)
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
type OrderedSearcherList []Searcher
|
||||
|
||||
// sort.Interface
|
||||
|
||||
func (otrl OrderedSearcherList) Len() int {
|
||||
return len(otrl)
|
||||
}
|
||||
|
||||
func (otrl OrderedSearcherList) Less(i, j int) bool {
|
||||
return otrl[i].Count() < otrl[j].Count()
|
||||
}
|
||||
|
||||
func (otrl OrderedSearcherList) Swap(i, j int) {
|
||||
otrl[i], otrl[j] = otrl[j], otrl[i]
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
mode: set
|
||||
github.com/couchbaselabs/bleve/search/explanation.go:22.42,24.16 2 0
|
||||
github.com/couchbaselabs/bleve/search/explanation.go:27.2,27.19 1 0
|
||||
github.com/couchbaselabs/bleve/search/explanation.go:24.16,26.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:34.100,46.13 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:53.2,53.12 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:46.13,51.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:56.44,59.2 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:61.55,67.15 3 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:67.15,83.3 5 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:86.79,91.9 3 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:143.2,143.21 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:147.2,151.15 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:155.2,155.60 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:171.2,171.12 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:91.9,94.38 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:100.3,102.16 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:121.3,121.27 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:135.3,135.39 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:94.38,96.4 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:96.5,98.4 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:102.16,118.4 5 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:121.27,123.17 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:123.17,132.5 4 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:135.39,137.17 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:137.17,139.5 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:143.21,145.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:151.15,153.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:155.60,157.39 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:165.3,168.36 4 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term.go:157.39,164.4 2 1
|
||||
github.com/couchbaselabs/bleve/search/query_term.go:22.37,24.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/query_term.go:26.67,28.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/query_term.go:30.38,32.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/query_term_conjunction.go:21.48,23.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/query_term_conjunction.go:25.78,27.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/query_term_conjunction.go:29.49,31.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:17.78,21.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:23.90,30.15 4 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:34.2,35.40 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:44.2,45.15 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:49.2,49.25 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:55.2,55.12 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:30.15,32.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:35.40,37.16 2 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:40.3,40.32 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:37.16,39.4 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:40.32,42.4 1 0
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:45.15,47.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:49.25,51.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:51.4,51.31 1 1
|
||||
github.com/couchbaselabs/bleve/search/scorer_term_conjunction.go:51.31,53.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/sqrt_cache.go:19.13,21.38 2 1
|
||||
github.com/couchbaselabs/bleve/search/sqrt_cache.go:21.38,23.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:24.54,29.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:31.47,33.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:35.51,37.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:39.53,41.2 1 0
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:43.65,46.32 3 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:51.2,52.16 2 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:55.2,55.12 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:46.32,49.3 2 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:52.16,54.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:58.65,63.30 2 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:67.2,67.56 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:81.2,82.33 2 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:63.30,65.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:67.56,69.28 2 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:69.28,73.35 2 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:77.4,77.10 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:73.35,76.5 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:82.33,85.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:88.66,91.55 3 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:95.2,95.11 1 1
|
||||
github.com/couchbaselabs/bleve/search/collector_top_score.go:91.55,94.3 2 1
|
||||
github.com/couchbaselabs/bleve/search/ordered_searchers_list.go:15.43,17.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/ordered_searchers_list.go:19.53,21.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/ordered_searchers_list.go:23.48,25.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:27.115,30.40 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:38.2,48.16 5 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:52.2,52.17 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:30.40,32.17 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:35.3,35.26 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:32.17,34.4 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:48.16,50.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:55.54,58.43 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:62.2,64.43 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:58.43,60.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:64.43,66.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:69.57,72.43 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:79.2,79.22 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:86.2,86.12 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:72.43,74.17 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:74.17,76.4 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:79.22,80.24 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:80.24,82.4 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:82.5,84.4 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:89.52,91.39 2 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:94.2,94.11 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:91.39,93.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:97.63,98.39 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:98.39,100.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:103.66,107.24 3 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:150.2,150.16 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:107.24,108.44 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:135.3,139.17 3 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:142.3,142.24 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:148.3,148.8 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:108.44,109.36 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:109.36,112.19 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:115.5,115.26 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:119.5,119.37 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:112.19,114.6 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:115.26,117.20 2 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:119.37,122.20 2 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:125.6,125.27 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:130.6,130.20 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:122.20,124.7 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:125.27,127.7 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:127.8,129.7 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:139.17,141.4 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:142.24,144.4 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:144.5,146.4 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:153.78,156.2 2 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:158.50,161.39 2 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:164.2,164.12 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:161.39,163.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:167.43,168.39 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term_conjunction.go:168.39,170.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:22.82,24.16 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:27.2,33.8 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:24.16,26.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:36.39,38.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:40.41,42.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:44.52,46.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:48.55,50.16 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:54.2,54.22 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:59.2,61.22 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:50.16,52.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:54.22,56.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:65.67,67.16 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:71.2,71.22 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:76.2,79.22 2 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:67.16,69.3 1 0
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:71.22,73.3 1 1
|
||||
github.com/couchbaselabs/bleve/search/search_term.go:82.32,84.2 1 1
|
||||
github.com/couchbaselabs/bleve/search/util.go:11.76,14.38 2 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:26.2,26.11 1 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:14.38,16.53 2 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:16.53,18.18 2 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:18.18,20.5 1 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:20.6,22.5 1 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:29.71,30.39 1 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:35.2,35.11 1 0
|
||||
github.com/couchbaselabs/bleve/search/util.go:30.39,34.3 1 0
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
import (
|
||||
"github.com/couchbaselabs/bleve/index"
|
||||
)
|
||||
|
||||
type TermConjunctionQuery struct {
|
||||
Terms []Query `json:"terms"`
|
||||
BoostVal float64 `json:"boost"`
|
||||
Explain bool `json:"explain"`
|
||||
}
|
||||
|
||||
func (q *TermConjunctionQuery) Boost() float64 {
|
||||
return q.BoostVal
|
||||
}
|
||||
|
||||
func (q *TermConjunctionQuery) Searcher(index index.Index) (Searcher, error) {
|
||||
return NewTermConjunctionSearcher(index, q)
|
||||
}
|
||||
|
||||
func (q *TermConjunctionQuery) Validate() error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
import ()
|
||||
|
||||
type TermConjunctionQueryScorer struct {
|
||||
explain bool
|
||||
}
|
||||
|
||||
func NewTermConjunctionQueryScorer(explain bool) *TermConjunctionQueryScorer {
|
||||
return &TermConjunctionQueryScorer{
|
||||
explain: explain,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TermConjunctionQueryScorer) Score(constituents []*DocumentMatch) *DocumentMatch {
|
||||
rv := DocumentMatch{
|
||||
ID: constituents[0].ID,
|
||||
}
|
||||
|
||||
var sum float64
|
||||
var childrenExplanations []*Explanation
|
||||
if s.explain {
|
||||
childrenExplanations = make([]*Explanation, len(constituents))
|
||||
}
|
||||
|
||||
locations := []FieldTermLocationMap{}
|
||||
for i, docMatch := range constituents {
|
||||
sum += docMatch.Score
|
||||
if s.explain {
|
||||
childrenExplanations[i] = docMatch.Expl
|
||||
}
|
||||
if docMatch.Locations != nil {
|
||||
locations = append(locations, docMatch.Locations)
|
||||
}
|
||||
}
|
||||
rv.Score = sum
|
||||
if s.explain {
|
||||
rv.Expl = &Explanation{Value: sum, Message: "sum of:", Children: childrenExplanations}
|
||||
}
|
||||
|
||||
if len(locations) == 1 {
|
||||
rv.Locations = locations[0]
|
||||
} else if len(locations) > 1 {
|
||||
rv.Locations = mergeLocations(locations)
|
||||
}
|
||||
|
||||
return &rv
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"github.com/couchbaselabs/bleve/index"
|
||||
)
|
||||
|
||||
type TermConjunctionSearcher struct {
|
||||
index index.Index
|
||||
searchers OrderedSearcherList
|
||||
queryNorm float64
|
||||
currs []*DocumentMatch
|
||||
currentId string
|
||||
scorer *TermConjunctionQueryScorer
|
||||
}
|
||||
|
||||
func NewTermConjunctionSearcher(index index.Index, query *TermConjunctionQuery) (*TermConjunctionSearcher, error) {
|
||||
// build the downstream searchres
|
||||
searchers := make(OrderedSearcherList, len(query.Terms))
|
||||
for i, termQuery := range query.Terms {
|
||||
searcher, err := termQuery.Searcher(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
searchers[i] = searcher
|
||||
}
|
||||
// sort the searchers
|
||||
sort.Sort(searchers)
|
||||
// build our searcher
|
||||
rv := TermConjunctionSearcher{
|
||||
index: index,
|
||||
searchers: searchers,
|
||||
currs: make([]*DocumentMatch, len(searchers)),
|
||||
scorer: NewTermConjunctionQueryScorer(query.Explain),
|
||||
}
|
||||
rv.computeQueryNorm()
|
||||
err := rv.initSearchers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &rv, nil
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) computeQueryNorm() {
|
||||
// first calculate sum of squared weights
|
||||
sumOfSquaredWeights := 0.0
|
||||
for _, termSearcher := range s.searchers {
|
||||
sumOfSquaredWeights += termSearcher.Weight()
|
||||
}
|
||||
// now compute query norm from this
|
||||
s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights)
|
||||
// finally tell all the downsteam searchers the norm
|
||||
for _, termSearcher := range s.searchers {
|
||||
termSearcher.SetQueryNorm(s.queryNorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) initSearchers() error {
|
||||
var err error
|
||||
// get all searchers pointing at their first match
|
||||
for i, termSearcher := range s.searchers {
|
||||
s.currs[i], err = termSearcher.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.currs) > 0 {
|
||||
if s.currs[0] != nil {
|
||||
s.currentId = s.currs[0].ID
|
||||
} else {
|
||||
s.currentId = ""
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) Weight() float64 {
|
||||
var rv float64
|
||||
for _, searcher := range s.searchers {
|
||||
rv += searcher.Weight()
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) SetQueryNorm(qnorm float64) {
|
||||
for _, searcher := range s.searchers {
|
||||
searcher.SetQueryNorm(qnorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) Next() (*DocumentMatch, error) {
|
||||
var rv *DocumentMatch
|
||||
var err error
|
||||
OUTER:
|
||||
for s.currentId != "" {
|
||||
for i, termSearcher := range s.searchers {
|
||||
if s.currs[i].ID != s.currentId {
|
||||
// this reader doesn't have the currentId, try to advance
|
||||
s.currs[i], err = termSearcher.Advance(s.currentId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.currs[i] == nil {
|
||||
s.currentId = ""
|
||||
continue OUTER
|
||||
}
|
||||
if s.currs[i].ID != s.currentId {
|
||||
// if it still doesn't have the currentId, next and start over
|
||||
s.currs[i], err = termSearcher.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.currs[i] == nil {
|
||||
s.currentId = ""
|
||||
} else {
|
||||
s.currentId = s.currs[i].ID
|
||||
}
|
||||
continue OUTER
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we get here, a doc matched all readers, sum the score and add it
|
||||
rv = s.scorer.Score(s.currs)
|
||||
|
||||
// prepare for next entry
|
||||
s.currs[0], err = s.searchers[0].Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.currs[0] == nil {
|
||||
s.currentId = ""
|
||||
} else {
|
||||
s.currentId = s.currs[0].ID
|
||||
}
|
||||
// don't continue now, wait for next call the Next()
|
||||
break
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) Advance(ID string) (*DocumentMatch, error) {
|
||||
s.currentId = ID
|
||||
return s.Next()
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) Count() uint64 {
|
||||
// for now return a worst case
|
||||
var sum uint64 = 0
|
||||
for _, searcher := range s.searchers {
|
||||
sum += searcher.Count()
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (s *TermConjunctionSearcher) Close() {
|
||||
for _, searcher := range s.searchers {
|
||||
searcher.Close()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/couchbaselabs/bleve/index"
|
||||
)
|
||||
|
||||
func TestTermConjunctionSearch(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
index index.Index
|
||||
query *TermConjunctionQuery
|
||||
results []*DocumentMatch
|
||||
}{
|
||||
{
|
||||
index: twoDocIndex,
|
||||
query: &TermConjunctionQuery{
|
||||
Terms: []Query{
|
||||
&TermQuery{
|
||||
Term: "beer",
|
||||
Field: "desc",
|
||||
BoostVal: 1.0,
|
||||
Explain: true,
|
||||
},
|
||||
&TermQuery{
|
||||
Term: "marty",
|
||||
Field: "name",
|
||||
BoostVal: 5.0,
|
||||
Explain: true,
|
||||
},
|
||||
},
|
||||
Explain: true,
|
||||
},
|
||||
results: []*DocumentMatch{
|
||||
&DocumentMatch{
|
||||
ID: "1",
|
||||
Score: 2.0097428702814377,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
index: twoDocIndex,
|
||||
query: &TermConjunctionQuery{
|
||||
Terms: []Query{
|
||||
&TermQuery{
|
||||
Term: "angst",
|
||||
Field: "desc",
|
||||
BoostVal: 1.0,
|
||||
Explain: true,
|
||||
},
|
||||
&TermQuery{
|
||||
Term: "beer",
|
||||
Field: "desc",
|
||||
BoostVal: 1.0,
|
||||
Explain: true,
|
||||
},
|
||||
},
|
||||
Explain: true,
|
||||
},
|
||||
results: []*DocumentMatch{
|
||||
&DocumentMatch{
|
||||
ID: "2",
|
||||
Score: 1.0807601687084403,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for testIndex, test := range tests {
|
||||
searcher, err := NewTermConjunctionSearcher(test.index, test.query)
|
||||
defer searcher.Close()
|
||||
|
||||
next, err := searcher.Next()
|
||||
i := 0
|
||||
for err == nil && next != nil {
|
||||
if i < len(test.results) {
|
||||
if next.ID != test.results[i].ID {
|
||||
t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex)
|
||||
}
|
||||
if next.Score != test.results[i].Score {
|
||||
t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex)
|
||||
t.Logf("scoring explanation: %s", next.Expl)
|
||||
}
|
||||
}
|
||||
next, err = searcher.Next()
|
||||
i++
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("error iterating searcher: %v for test %d", err, testIndex)
|
||||
}
|
||||
if len(test.results) != i {
|
||||
t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package search
|
||||
|
||||
func mergeLocations(locations []FieldTermLocationMap) FieldTermLocationMap {
|
||||
rv := locations[0]
|
||||
|
||||
for i := 1; i < len(locations); i++ {
|
||||
nextLocations := locations[i]
|
||||
for field, termLocationMap := range nextLocations {
|
||||
rvTermLocationMap, rvHasField := rv[field]
|
||||
if rvHasField {
|
||||
rv[field] = mergeTermLocationMaps(rvTermLocationMap, termLocationMap)
|
||||
} else {
|
||||
rv[field] = termLocationMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
func mergeTermLocationMaps(rv, other TermLocationMap) TermLocationMap {
|
||||
for term, locationMap := range other {
|
||||
// for a given term/document there cannot be different locations
|
||||
// if they can back from different clauses, overwrite is ok
|
||||
rv[term] = locationMap
|
||||
}
|
||||
return rv
|
||||
}
|
Loading…
Reference in New Issue