Upgrade server dependencies, manage them with govendor
This commit is contained in:
parent
ebee2746d6
commit
971278e7e5
1748 changed files with 196165 additions and 194500 deletions
35
vendor/github.com/blevesearch/bleve/search/searcher/ordered_searchers_list.go
generated
vendored
Normal file
35
vendor/github.com/blevesearch/bleve/search/searcher/ordered_searchers_list.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
type OrderedSearcherList []search.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]
|
||||
}
|
391
vendor/github.com/blevesearch/bleve/search/searcher/search_boolean.go
generated
vendored
Normal file
391
vendor/github.com/blevesearch/bleve/search/searcher/search_boolean.go
generated
vendored
Normal file
|
@ -0,0 +1,391 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
"github.com/blevesearch/bleve/search/scorer"
|
||||
)
|
||||
|
||||
type BooleanSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
mustSearcher search.Searcher
|
||||
shouldSearcher search.Searcher
|
||||
mustNotSearcher search.Searcher
|
||||
queryNorm float64
|
||||
currMust *search.DocumentMatch
|
||||
currShould *search.DocumentMatch
|
||||
currMustNot *search.DocumentMatch
|
||||
currentID index.IndexInternalID
|
||||
min uint64
|
||||
scorer *scorer.ConjunctionQueryScorer
|
||||
matches []*search.DocumentMatch
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func NewBooleanSearcher(indexReader index.IndexReader, mustSearcher search.Searcher, shouldSearcher search.Searcher, mustNotSearcher search.Searcher, options search.SearcherOptions) (*BooleanSearcher, error) {
|
||||
// build our searcher
|
||||
rv := BooleanSearcher{
|
||||
indexReader: indexReader,
|
||||
mustSearcher: mustSearcher,
|
||||
shouldSearcher: shouldSearcher,
|
||||
mustNotSearcher: mustNotSearcher,
|
||||
scorer: scorer.NewConjunctionQueryScorer(options),
|
||||
matches: make([]*search.DocumentMatch, 2),
|
||||
}
|
||||
rv.computeQueryNorm()
|
||||
return &rv, nil
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) computeQueryNorm() {
|
||||
// first calculate sum of squared weights
|
||||
sumOfSquaredWeights := 0.0
|
||||
if s.mustSearcher != nil {
|
||||
sumOfSquaredWeights += s.mustSearcher.Weight()
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
sumOfSquaredWeights += s.shouldSearcher.Weight()
|
||||
}
|
||||
|
||||
// now compute query norm from this
|
||||
s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights)
|
||||
// finally tell all the downstream searchers the norm
|
||||
if s.mustSearcher != nil {
|
||||
s.mustSearcher.SetQueryNorm(s.queryNorm)
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
s.shouldSearcher.SetQueryNorm(s.queryNorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) initSearchers(ctx *search.SearchContext) error {
|
||||
var err error
|
||||
// get all searchers pointing at their first match
|
||||
if s.mustSearcher != nil {
|
||||
if s.currMust != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currMust)
|
||||
}
|
||||
s.currMust, err = s.mustSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.shouldSearcher != nil {
|
||||
if s.currShould != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currShould)
|
||||
}
|
||||
s.currShould, err = s.shouldSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.mustNotSearcher != nil {
|
||||
if s.currMustNot != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currMustNot)
|
||||
}
|
||||
s.currMustNot, err = s.mustNotSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.mustSearcher != nil && s.currMust != nil {
|
||||
s.currentID = s.currMust.IndexInternalID
|
||||
} else if s.mustSearcher == nil && s.currShould != nil {
|
||||
s.currentID = s.currShould.IndexInternalID
|
||||
} else {
|
||||
s.currentID = nil
|
||||
}
|
||||
|
||||
s.initialized = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) advanceNextMust(ctx *search.SearchContext, skipReturn *search.DocumentMatch) error {
|
||||
var err error
|
||||
|
||||
if s.mustSearcher != nil {
|
||||
if s.currMust != skipReturn {
|
||||
ctx.DocumentMatchPool.Put(s.currMust)
|
||||
}
|
||||
s.currMust, err = s.mustSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if s.currShould != skipReturn {
|
||||
ctx.DocumentMatchPool.Put(s.currShould)
|
||||
}
|
||||
s.currShould, err = s.shouldSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.mustSearcher != nil && s.currMust != nil {
|
||||
s.currentID = s.currMust.IndexInternalID
|
||||
} else if s.mustSearcher == nil && s.currShould != nil {
|
||||
s.currentID = s.currShould.IndexInternalID
|
||||
} else {
|
||||
s.currentID = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) Weight() float64 {
|
||||
var rv float64
|
||||
if s.mustSearcher != nil {
|
||||
rv += s.mustSearcher.Weight()
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
rv += s.shouldSearcher.Weight()
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) SetQueryNorm(qnorm float64) {
|
||||
if s.mustSearcher != nil {
|
||||
s.mustSearcher.SetQueryNorm(qnorm)
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
s.shouldSearcher.SetQueryNorm(qnorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
var rv *search.DocumentMatch
|
||||
|
||||
for s.currentID != nil {
|
||||
if s.currMustNot != nil {
|
||||
cmp := s.currMustNot.IndexInternalID.Compare(s.currentID)
|
||||
if cmp < 0 {
|
||||
ctx.DocumentMatchPool.Put(s.currMustNot)
|
||||
// advance must not searcher to our candidate entry
|
||||
s.currMustNot, err = s.mustNotSearcher.Advance(ctx, s.currentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.currMustNot != nil && s.currMustNot.IndexInternalID.Equals(s.currentID) {
|
||||
// the candidate is excluded
|
||||
err = s.advanceNextMust(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else if cmp == 0 {
|
||||
// the candidate is excluded
|
||||
err = s.advanceNextMust(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
shouldCmpOrNil := 1 // NOTE: shouldCmp will also be 1 when currShould == nil.
|
||||
if s.currShould != nil {
|
||||
shouldCmpOrNil = s.currShould.IndexInternalID.Compare(s.currentID)
|
||||
}
|
||||
|
||||
if shouldCmpOrNil < 0 {
|
||||
ctx.DocumentMatchPool.Put(s.currShould)
|
||||
// advance should searcher to our candidate entry
|
||||
s.currShould, err = s.shouldSearcher.Advance(ctx, s.currentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.currShould != nil && s.currShould.IndexInternalID.Equals(s.currentID) {
|
||||
// score bonus matches should
|
||||
var cons []*search.DocumentMatch
|
||||
if s.currMust != nil {
|
||||
cons = s.matches
|
||||
cons[0] = s.currMust
|
||||
cons[1] = s.currShould
|
||||
} else {
|
||||
cons = s.matches[0:1]
|
||||
cons[0] = s.currShould
|
||||
}
|
||||
rv = s.scorer.Score(ctx, cons)
|
||||
err = s.advanceNextMust(ctx, rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
} else if s.shouldSearcher.Min() == 0 {
|
||||
// match is OK anyway
|
||||
cons := s.matches[0:1]
|
||||
cons[0] = s.currMust
|
||||
rv = s.scorer.Score(ctx, cons)
|
||||
err = s.advanceNextMust(ctx, rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if shouldCmpOrNil == 0 {
|
||||
// score bonus matches should
|
||||
var cons []*search.DocumentMatch
|
||||
if s.currMust != nil {
|
||||
cons = s.matches
|
||||
cons[0] = s.currMust
|
||||
cons[1] = s.currShould
|
||||
} else {
|
||||
cons = s.matches[0:1]
|
||||
cons[0] = s.currShould
|
||||
}
|
||||
rv = s.scorer.Score(ctx, cons)
|
||||
err = s.advanceNextMust(ctx, rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
} else if s.shouldSearcher == nil || s.shouldSearcher.Min() == 0 {
|
||||
// match is OK anyway
|
||||
cons := s.matches[0:1]
|
||||
cons[0] = s.currMust
|
||||
rv = s.scorer.Score(ctx, cons)
|
||||
err = s.advanceNextMust(ctx, rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
err = s.advanceNextMust(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if s.mustSearcher != nil {
|
||||
if s.currMust != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currMust)
|
||||
}
|
||||
s.currMust, err = s.mustSearcher.Advance(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
if s.currShould != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currShould)
|
||||
}
|
||||
s.currShould, err = s.shouldSearcher.Advance(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if s.mustNotSearcher != nil {
|
||||
if s.currMustNot != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currMustNot)
|
||||
}
|
||||
s.currMustNot, err = s.mustNotSearcher.Advance(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if s.mustSearcher != nil && s.currMust != nil {
|
||||
s.currentID = s.currMust.IndexInternalID
|
||||
} else if s.mustSearcher == nil && s.currShould != nil {
|
||||
s.currentID = s.currShould.IndexInternalID
|
||||
} else {
|
||||
s.currentID = nil
|
||||
}
|
||||
|
||||
return s.Next(ctx)
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) Count() uint64 {
|
||||
|
||||
// for now return a worst case
|
||||
var sum uint64
|
||||
if s.mustSearcher != nil {
|
||||
sum += s.mustSearcher.Count()
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
sum += s.shouldSearcher.Count()
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) Close() error {
|
||||
var err0, err1, err2 error
|
||||
if s.mustSearcher != nil {
|
||||
err0 = s.mustSearcher.Close()
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
err1 = s.shouldSearcher.Close()
|
||||
}
|
||||
if s.mustNotSearcher != nil {
|
||||
err2 = s.mustNotSearcher.Close()
|
||||
}
|
||||
if err0 != nil {
|
||||
return err0
|
||||
}
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *BooleanSearcher) DocumentMatchPoolSize() int {
|
||||
rv := 3
|
||||
if s.mustSearcher != nil {
|
||||
rv += s.mustSearcher.DocumentMatchPoolSize()
|
||||
}
|
||||
if s.shouldSearcher != nil {
|
||||
rv += s.shouldSearcher.DocumentMatchPoolSize()
|
||||
}
|
||||
if s.mustNotSearcher != nil {
|
||||
rv += s.mustNotSearcher.DocumentMatchPoolSize()
|
||||
}
|
||||
return rv
|
||||
}
|
232
vendor/github.com/blevesearch/bleve/search/searcher/search_conjunction.go
generated
vendored
Normal file
232
vendor/github.com/blevesearch/bleve/search/searcher/search_conjunction.go
generated
vendored
Normal file
|
@ -0,0 +1,232 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
"github.com/blevesearch/bleve/search/scorer"
|
||||
)
|
||||
|
||||
type ConjunctionSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
searchers OrderedSearcherList
|
||||
queryNorm float64
|
||||
currs []*search.DocumentMatch
|
||||
maxIDIdx int
|
||||
scorer *scorer.ConjunctionQueryScorer
|
||||
initialized bool
|
||||
options search.SearcherOptions
|
||||
}
|
||||
|
||||
func NewConjunctionSearcher(indexReader index.IndexReader, qsearchers []search.Searcher, options search.SearcherOptions) (*ConjunctionSearcher, error) {
|
||||
// build the downstream searchers
|
||||
searchers := make(OrderedSearcherList, len(qsearchers))
|
||||
for i, searcher := range qsearchers {
|
||||
searchers[i] = searcher
|
||||
}
|
||||
// sort the searchers
|
||||
sort.Sort(searchers)
|
||||
// build our searcher
|
||||
rv := ConjunctionSearcher{
|
||||
indexReader: indexReader,
|
||||
options: options,
|
||||
searchers: searchers,
|
||||
currs: make([]*search.DocumentMatch, len(searchers)),
|
||||
scorer: scorer.NewConjunctionQueryScorer(options),
|
||||
}
|
||||
rv.computeQueryNorm()
|
||||
return &rv, nil
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) 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 downstream searchers the norm
|
||||
for _, termSearcher := range s.searchers {
|
||||
termSearcher.SetQueryNorm(s.queryNorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) initSearchers(ctx *search.SearchContext) error {
|
||||
var err error
|
||||
// get all searchers pointing at their first match
|
||||
for i, termSearcher := range s.searchers {
|
||||
if s.currs[i] != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currs[i])
|
||||
}
|
||||
s.currs[i], err = termSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
s.initialized = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) Weight() float64 {
|
||||
var rv float64
|
||||
for _, searcher := range s.searchers {
|
||||
rv += searcher.Weight()
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) SetQueryNorm(qnorm float64) {
|
||||
for _, searcher := range s.searchers {
|
||||
searcher.SetQueryNorm(qnorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var rv *search.DocumentMatch
|
||||
var err error
|
||||
OUTER:
|
||||
for s.currs[s.maxIDIdx] != nil {
|
||||
maxID := s.currs[s.maxIDIdx].IndexInternalID
|
||||
|
||||
i := 0
|
||||
for i < len(s.currs) {
|
||||
if s.currs[i] == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if i == s.maxIDIdx {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
cmp := maxID.Compare(s.currs[i].IndexInternalID)
|
||||
if cmp == 0 {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if cmp < 0 {
|
||||
// maxID < currs[i], so we found a new maxIDIdx
|
||||
s.maxIDIdx = i
|
||||
|
||||
// advance the positions where [0 <= x < i], since we
|
||||
// know they were equal to the former max entry
|
||||
maxID = s.currs[s.maxIDIdx].IndexInternalID
|
||||
for x := 0; x < i; x++ {
|
||||
err = s.advanceChild(ctx, x, maxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
// maxID > currs[i], so need to advance searchers[i]
|
||||
err = s.advanceChild(ctx, i, maxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// don't bump i, so that we'll examine the just-advanced
|
||||
// currs[i] again
|
||||
}
|
||||
|
||||
// if we get here, a doc matched all readers, so score and add it
|
||||
rv = s.scorer.Score(ctx, s.currs)
|
||||
|
||||
// we know all the searchers are pointing at the same thing
|
||||
// so they all need to be bumped
|
||||
for i, termSearcher := range s.searchers {
|
||||
if s.currs[i] != rv {
|
||||
ctx.DocumentMatchPool.Put(s.currs[i])
|
||||
}
|
||||
s.currs[i], err = termSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// don't continue now, wait for the next call to Next()
|
||||
break
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for i := range s.searchers {
|
||||
err := s.advanceChild(ctx, i, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.Next(ctx)
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) advanceChild(ctx *search.SearchContext, i int, ID index.IndexInternalID) (err error) {
|
||||
if s.currs[i] != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currs[i])
|
||||
}
|
||||
s.currs[i], err = s.searchers[i].Advance(ctx, ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) Count() uint64 {
|
||||
// for now return a worst case
|
||||
var sum uint64
|
||||
for _, searcher := range s.searchers {
|
||||
sum += searcher.Count()
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) Close() (rv error) {
|
||||
for _, searcher := range s.searchers {
|
||||
err := searcher.Close()
|
||||
if err != nil && rv == nil {
|
||||
rv = err
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *ConjunctionSearcher) DocumentMatchPoolSize() int {
|
||||
rv := len(s.currs)
|
||||
for _, s := range s.searchers {
|
||||
rv += s.DocumentMatchPoolSize()
|
||||
}
|
||||
return rv
|
||||
}
|
271
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction.go
generated
vendored
Normal file
271
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction.go
generated
vendored
Normal file
|
@ -0,0 +1,271 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
"github.com/blevesearch/bleve/search/scorer"
|
||||
)
|
||||
|
||||
// DisjunctionMaxClauseCount is a compile time setting that applications can
|
||||
// adjust to non-zero value to cause the DisjunctionSearcher to return an
|
||||
// error instead of exeucting searches when the size exceeds this value.
|
||||
var DisjunctionMaxClauseCount = 0
|
||||
|
||||
type DisjunctionSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
searchers OrderedSearcherList
|
||||
numSearchers int
|
||||
queryNorm float64
|
||||
currs []*search.DocumentMatch
|
||||
scorer *scorer.DisjunctionQueryScorer
|
||||
min int
|
||||
matching []*search.DocumentMatch
|
||||
matchingIdxs []int
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func tooManyClauses(count int) bool {
|
||||
if DisjunctionMaxClauseCount != 0 && count > DisjunctionMaxClauseCount {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tooManyClausesErr() error {
|
||||
return fmt.Errorf("TooManyClauses[maxClauseCount is set to %d]",
|
||||
DisjunctionMaxClauseCount)
|
||||
}
|
||||
|
||||
func NewDisjunctionSearcher(indexReader index.IndexReader,
|
||||
qsearchers []search.Searcher, min float64, options search.SearcherOptions) (
|
||||
*DisjunctionSearcher, error) {
|
||||
return newDisjunctionSearcher(indexReader, qsearchers, min, options,
|
||||
true)
|
||||
}
|
||||
|
||||
func newDisjunctionSearcher(indexReader index.IndexReader,
|
||||
qsearchers []search.Searcher, min float64, options search.SearcherOptions,
|
||||
limit bool) (
|
||||
*DisjunctionSearcher, error) {
|
||||
if limit && tooManyClauses(len(qsearchers)) {
|
||||
return nil, tooManyClausesErr()
|
||||
}
|
||||
// build the downstream searchers
|
||||
searchers := make(OrderedSearcherList, len(qsearchers))
|
||||
for i, searcher := range qsearchers {
|
||||
searchers[i] = searcher
|
||||
}
|
||||
// sort the searchers
|
||||
sort.Sort(sort.Reverse(searchers))
|
||||
// build our searcher
|
||||
rv := DisjunctionSearcher{
|
||||
indexReader: indexReader,
|
||||
searchers: searchers,
|
||||
numSearchers: len(searchers),
|
||||
currs: make([]*search.DocumentMatch, len(searchers)),
|
||||
scorer: scorer.NewDisjunctionQueryScorer(options),
|
||||
min: int(min),
|
||||
matching: make([]*search.DocumentMatch, len(searchers)),
|
||||
matchingIdxs: make([]int, len(searchers)),
|
||||
}
|
||||
rv.computeQueryNorm()
|
||||
return &rv, nil
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) 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 downstream searchers the norm
|
||||
for _, termSearcher := range s.searchers {
|
||||
termSearcher.SetQueryNorm(s.queryNorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) initSearchers(ctx *search.SearchContext) error {
|
||||
var err error
|
||||
// get all searchers pointing at their first match
|
||||
for i, termSearcher := range s.searchers {
|
||||
if s.currs[i] != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currs[i])
|
||||
}
|
||||
s.currs[i], err = termSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = s.updateMatches()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.initialized = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) updateMatches() error {
|
||||
matching := s.matching[:0]
|
||||
matchingIdxs := s.matchingIdxs[:0]
|
||||
|
||||
for i := 0; i < len(s.currs); i++ {
|
||||
curr := s.currs[i]
|
||||
if curr == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(matching) > 0 {
|
||||
cmp := curr.IndexInternalID.Compare(matching[0].IndexInternalID)
|
||||
if cmp > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if cmp < 0 {
|
||||
matching = matching[:0]
|
||||
matchingIdxs = matchingIdxs[:0]
|
||||
}
|
||||
}
|
||||
|
||||
matching = append(matching, curr)
|
||||
matchingIdxs = append(matchingIdxs, i)
|
||||
}
|
||||
|
||||
s.matching = matching
|
||||
s.matchingIdxs = matchingIdxs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) Weight() float64 {
|
||||
var rv float64
|
||||
for _, searcher := range s.searchers {
|
||||
rv += searcher.Weight()
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) SetQueryNorm(qnorm float64) {
|
||||
for _, searcher := range s.searchers {
|
||||
searcher.SetQueryNorm(qnorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) Next(ctx *search.SearchContext) (
|
||||
*search.DocumentMatch, error) {
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
var rv *search.DocumentMatch
|
||||
|
||||
found := false
|
||||
for !found && len(s.matching) > 0 {
|
||||
if len(s.matching) >= s.min {
|
||||
found = true
|
||||
// score this match
|
||||
rv = s.scorer.Score(ctx, s.matching, len(s.matching), s.numSearchers)
|
||||
}
|
||||
|
||||
// invoke next on all the matching searchers
|
||||
for _, i := range s.matchingIdxs {
|
||||
searcher := s.searchers[i]
|
||||
if s.currs[i] != rv {
|
||||
ctx.DocumentMatchPool.Put(s.currs[i])
|
||||
}
|
||||
s.currs[i], err = searcher.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = s.updateMatches()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) Advance(ctx *search.SearchContext,
|
||||
ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// get all searchers pointing at their first match
|
||||
var err error
|
||||
for i, termSearcher := range s.searchers {
|
||||
if s.currs[i] != nil {
|
||||
ctx.DocumentMatchPool.Put(s.currs[i])
|
||||
}
|
||||
s.currs[i], err = termSearcher.Advance(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = s.updateMatches()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.Next(ctx)
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) Count() uint64 {
|
||||
// for now return a worst case
|
||||
var sum uint64
|
||||
for _, searcher := range s.searchers {
|
||||
sum += searcher.Count()
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) Close() (rv error) {
|
||||
for _, searcher := range s.searchers {
|
||||
err := searcher.Close()
|
||||
if err != nil && rv == nil {
|
||||
rv = err
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) Min() int {
|
||||
return s.min
|
||||
}
|
||||
|
||||
func (s *DisjunctionSearcher) DocumentMatchPoolSize() int {
|
||||
rv := len(s.currs)
|
||||
for _, s := range s.searchers {
|
||||
rv += s.DocumentMatchPoolSize()
|
||||
}
|
||||
return rv
|
||||
}
|
93
vendor/github.com/blevesearch/bleve/search/searcher/search_docid.go
generated
vendored
Normal file
93
vendor/github.com/blevesearch/bleve/search/searcher/search_docid.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2015 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
"github.com/blevesearch/bleve/search/scorer"
|
||||
)
|
||||
|
||||
// DocIDSearcher returns documents matching a predefined set of identifiers.
|
||||
type DocIDSearcher struct {
|
||||
reader index.DocIDReader
|
||||
scorer *scorer.ConstantScorer
|
||||
count int
|
||||
}
|
||||
|
||||
func NewDocIDSearcher(indexReader index.IndexReader, ids []string, boost float64,
|
||||
options search.SearcherOptions) (searcher *DocIDSearcher, err error) {
|
||||
|
||||
reader, err := indexReader.DocIDReaderOnly(ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scorer := scorer.NewConstantScorer(1.0, boost, options)
|
||||
return &DocIDSearcher{
|
||||
scorer: scorer,
|
||||
reader: reader,
|
||||
count: len(ids),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) Count() uint64 {
|
||||
return uint64(s.count)
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) Weight() float64 {
|
||||
return s.scorer.Weight()
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) SetQueryNorm(qnorm float64) {
|
||||
s.scorer.SetQueryNorm(qnorm)
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
docidMatch, err := s.reader.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if docidMatch == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
docMatch := s.scorer.Score(ctx, docidMatch)
|
||||
return docMatch, nil
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
docidMatch, err := s.reader.Advance(ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if docidMatch == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
docMatch := s.scorer.Score(ctx, docidMatch)
|
||||
return docMatch, nil
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) Close() error {
|
||||
return s.reader.Close()
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *DocIDSearcher) DocumentMatchPoolSize() int {
|
||||
return 1
|
||||
}
|
88
vendor/github.com/blevesearch/bleve/search/searcher/search_filter.go
generated
vendored
Normal file
88
vendor/github.com/blevesearch/bleve/search/searcher/search_filter.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) 2017 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
// FilterFunc defines a function which can filter documents
|
||||
// returning true means keep the document
|
||||
// returning false means do not keep the document
|
||||
type FilterFunc func(d *search.DocumentMatch) bool
|
||||
|
||||
// FilteringSearcher wraps any other searcher, but checks any Next/Advance
|
||||
// call against the supplied FilterFunc
|
||||
type FilteringSearcher struct {
|
||||
child search.Searcher
|
||||
accept FilterFunc
|
||||
}
|
||||
|
||||
func NewFilteringSearcher(s search.Searcher, filter FilterFunc) *FilteringSearcher {
|
||||
return &FilteringSearcher{
|
||||
child: s,
|
||||
accept: filter,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
next, err := f.child.Next(ctx)
|
||||
for next != nil && err == nil {
|
||||
if f.accept(next) {
|
||||
return next, nil
|
||||
}
|
||||
next, err = f.child.Next(ctx)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
adv, err := f.child.Advance(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if adv == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if f.accept(adv) {
|
||||
return adv, nil
|
||||
}
|
||||
return f.Next(ctx)
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) Close() error {
|
||||
return f.child.Close()
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) Weight() float64 {
|
||||
return f.child.Weight()
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) SetQueryNorm(n float64) {
|
||||
f.child.SetQueryNorm(n)
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) Count() uint64 {
|
||||
return f.child.Count()
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) Min() int {
|
||||
return f.child.Min()
|
||||
}
|
||||
|
||||
func (f *FilteringSearcher) DocumentMatchPoolSize() int {
|
||||
return f.child.DocumentMatchPoolSize()
|
||||
}
|
74
vendor/github.com/blevesearch/bleve/search/searcher/search_fuzzy.go
generated
vendored
Normal file
74
vendor/github.com/blevesearch/bleve/search/searcher/search_fuzzy.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewFuzzySearcher(indexReader index.IndexReader, term string,
|
||||
prefix, fuzziness int, field string, boost float64,
|
||||
options search.SearcherOptions) (search.Searcher, error) {
|
||||
// Note: we don't byte slice the term for a prefix because of runes.
|
||||
prefixTerm := ""
|
||||
for i, r := range term {
|
||||
if i < prefix {
|
||||
prefixTerm += string(r)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
candidateTerms, err := findFuzzyCandidateTerms(indexReader, term, fuzziness,
|
||||
field, prefixTerm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewMultiTermSearcher(indexReader, candidateTerms, field,
|
||||
boost, options, true)
|
||||
}
|
||||
|
||||
func findFuzzyCandidateTerms(indexReader index.IndexReader, term string,
|
||||
fuzziness int, field, prefixTerm string) (rv []string, err error) {
|
||||
rv = make([]string, 0)
|
||||
var fieldDict index.FieldDict
|
||||
if len(prefixTerm) > 0 {
|
||||
fieldDict, err = indexReader.FieldDictPrefix(field, []byte(prefixTerm))
|
||||
} else {
|
||||
fieldDict, err = indexReader.FieldDict(field)
|
||||
}
|
||||
defer func() {
|
||||
if cerr := fieldDict.Close(); cerr != nil && err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
|
||||
// enumerate terms and check levenshtein distance
|
||||
tfd, err := fieldDict.Next()
|
||||
for err == nil && tfd != nil {
|
||||
ld, exceeded := search.LevenshteinDistanceMax(term, tfd.Term, fuzziness)
|
||||
if !exceeded && ld <= fuzziness {
|
||||
rv = append(rv, tfd.Term)
|
||||
if tooManyClauses(len(rv)) {
|
||||
return rv, tooManyClausesErr()
|
||||
}
|
||||
}
|
||||
tfd, err = fieldDict.Next()
|
||||
}
|
||||
|
||||
return rv, err
|
||||
}
|
173
vendor/github.com/blevesearch/bleve/search/searcher/search_geoboundingbox.go
generated
vendored
Normal file
173
vendor/github.com/blevesearch/bleve/search/searcher/search_geoboundingbox.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) 2017 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/document"
|
||||
"github.com/blevesearch/bleve/geo"
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/numeric"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewGeoBoundingBoxSearcher(indexReader index.IndexReader, minLon, minLat,
|
||||
maxLon, maxLat float64, field string, boost float64,
|
||||
options search.SearcherOptions, checkBoundaries bool) (
|
||||
search.Searcher, error) {
|
||||
|
||||
// track list of opened searchers, for cleanup on early exit
|
||||
var openedSearchers []search.Searcher
|
||||
cleanupOpenedSearchers := func() {
|
||||
for _, s := range openedSearchers {
|
||||
_ = s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// do math to produce list of terms needed for this search
|
||||
onBoundaryTerms, notOnBoundaryTerms := ComputeGeoRange(0, (geo.GeoBits<<1)-1,
|
||||
minLon, minLat, maxLon, maxLat, checkBoundaries)
|
||||
|
||||
var onBoundarySearcher search.Searcher
|
||||
if len(onBoundaryTerms) > 0 {
|
||||
rawOnBoundarySearcher, err := NewMultiTermSearcherBytes(indexReader,
|
||||
onBoundaryTerms, field, boost, options, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// add filter to check points near the boundary
|
||||
onBoundarySearcher = NewFilteringSearcher(rawOnBoundarySearcher,
|
||||
buildRectFilter(indexReader, field, minLon, minLat, maxLon, maxLat))
|
||||
openedSearchers = append(openedSearchers, onBoundarySearcher)
|
||||
}
|
||||
|
||||
var notOnBoundarySearcher search.Searcher
|
||||
if len(notOnBoundaryTerms) > 0 {
|
||||
var err error
|
||||
notOnBoundarySearcher, err = NewMultiTermSearcherBytes(indexReader,
|
||||
notOnBoundaryTerms, field, boost, options, false)
|
||||
if err != nil {
|
||||
cleanupOpenedSearchers()
|
||||
return nil, err
|
||||
}
|
||||
openedSearchers = append(openedSearchers, notOnBoundarySearcher)
|
||||
}
|
||||
|
||||
if onBoundarySearcher != nil && notOnBoundarySearcher != nil {
|
||||
rv, err := NewDisjunctionSearcher(indexReader,
|
||||
[]search.Searcher{
|
||||
onBoundarySearcher,
|
||||
notOnBoundarySearcher,
|
||||
},
|
||||
0, options)
|
||||
if err != nil {
|
||||
cleanupOpenedSearchers()
|
||||
return nil, err
|
||||
}
|
||||
return rv, nil
|
||||
} else if onBoundarySearcher != nil {
|
||||
return onBoundarySearcher, nil
|
||||
} else if notOnBoundarySearcher != nil {
|
||||
return notOnBoundarySearcher, nil
|
||||
}
|
||||
|
||||
return NewMatchNoneSearcher(indexReader)
|
||||
}
|
||||
|
||||
var geoMaxShift = document.GeoPrecisionStep * 4
|
||||
var geoDetailLevel = ((geo.GeoBits << 1) - geoMaxShift) / 2
|
||||
|
||||
func ComputeGeoRange(term uint64, shift uint,
|
||||
sminLon, sminLat, smaxLon, smaxLat float64,
|
||||
checkBoundaries bool) (
|
||||
onBoundary [][]byte, notOnBoundary [][]byte) {
|
||||
split := term | uint64(0x1)<<shift
|
||||
var upperMax uint64
|
||||
if shift < 63 {
|
||||
upperMax = term | ((uint64(1) << (shift + 1)) - 1)
|
||||
} else {
|
||||
upperMax = 0xffffffffffffffff
|
||||
}
|
||||
lowerMax := split - 1
|
||||
onBoundary, notOnBoundary = relateAndRecurse(term, lowerMax, shift,
|
||||
sminLon, sminLat, smaxLon, smaxLat, checkBoundaries)
|
||||
plusOnBoundary, plusNotOnBoundary := relateAndRecurse(split, upperMax, shift,
|
||||
sminLon, sminLat, smaxLon, smaxLat, checkBoundaries)
|
||||
onBoundary = append(onBoundary, plusOnBoundary...)
|
||||
notOnBoundary = append(notOnBoundary, plusNotOnBoundary...)
|
||||
return
|
||||
}
|
||||
|
||||
func relateAndRecurse(start, end uint64, res uint,
|
||||
sminLon, sminLat, smaxLon, smaxLat float64,
|
||||
checkBoundaries bool) (
|
||||
onBoundary [][]byte, notOnBoundary [][]byte) {
|
||||
minLon := geo.MortonUnhashLon(start)
|
||||
minLat := geo.MortonUnhashLat(start)
|
||||
maxLon := geo.MortonUnhashLon(end)
|
||||
maxLat := geo.MortonUnhashLat(end)
|
||||
|
||||
level := ((geo.GeoBits << 1) - res) >> 1
|
||||
|
||||
within := res%document.GeoPrecisionStep == 0 &&
|
||||
geo.RectWithin(minLon, minLat, maxLon, maxLat,
|
||||
sminLon, sminLat, smaxLon, smaxLat)
|
||||
if within || (level == geoDetailLevel &&
|
||||
geo.RectIntersects(minLon, minLat, maxLon, maxLat,
|
||||
sminLon, sminLat, smaxLon, smaxLat)) {
|
||||
if !within && checkBoundaries {
|
||||
return [][]byte{
|
||||
numeric.MustNewPrefixCodedInt64(int64(start), res),
|
||||
}, nil
|
||||
}
|
||||
return nil,
|
||||
[][]byte{
|
||||
numeric.MustNewPrefixCodedInt64(int64(start), res),
|
||||
}
|
||||
} else if level < geoDetailLevel &&
|
||||
geo.RectIntersects(minLon, minLat, maxLon, maxLat,
|
||||
sminLon, sminLat, smaxLon, smaxLat) {
|
||||
return ComputeGeoRange(start, res-1, sminLon, sminLat, smaxLon, smaxLat,
|
||||
checkBoundaries)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func buildRectFilter(indexReader index.IndexReader, field string,
|
||||
minLon, minLat, maxLon, maxLat float64) FilterFunc {
|
||||
return func(d *search.DocumentMatch) bool {
|
||||
var lon, lat float64
|
||||
var found bool
|
||||
err := indexReader.DocumentVisitFieldTerms(d.IndexInternalID,
|
||||
[]string{field}, func(field string, term []byte) {
|
||||
// only consider the values which are shifted 0
|
||||
prefixCoded := numeric.PrefixCoded(term)
|
||||
shift, err := prefixCoded.Shift()
|
||||
if err == nil && shift == 0 {
|
||||
var i64 int64
|
||||
i64, err = prefixCoded.Int64()
|
||||
if err == nil {
|
||||
lon = geo.MortonUnhashLon(uint64(i64))
|
||||
lat = geo.MortonUnhashLat(uint64(i64))
|
||||
found = true
|
||||
}
|
||||
}
|
||||
})
|
||||
if err == nil && found {
|
||||
return geo.BoundingBoxContains(lon, lat,
|
||||
minLon, minLat, maxLon, maxLat)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
115
vendor/github.com/blevesearch/bleve/search/searcher/search_geopointdistance.go
generated
vendored
Normal file
115
vendor/github.com/blevesearch/bleve/search/searcher/search_geopointdistance.go
generated
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2017 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/geo"
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/numeric"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewGeoPointDistanceSearcher(indexReader index.IndexReader, centerLon,
|
||||
centerLat, dist float64, field string, boost float64,
|
||||
options search.SearcherOptions) (search.Searcher, error) {
|
||||
|
||||
// compute bounding box containing the circle
|
||||
topLeftLon, topLeftLat, bottomRightLon, bottomRightLat :=
|
||||
geo.ComputeBoundingBox(centerLon, centerLat, dist)
|
||||
|
||||
// build a searcher for the box
|
||||
boxSearcher, err := boxSearcher(indexReader,
|
||||
topLeftLon, topLeftLat, bottomRightLon, bottomRightLat,
|
||||
field, boost, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// wrap it in a filtering searcher which checks the actual distance
|
||||
return NewFilteringSearcher(boxSearcher,
|
||||
buildDistFilter(indexReader, field, centerLon, centerLat, dist)), nil
|
||||
}
|
||||
|
||||
// boxSearcher builds a searcher for the described bounding box
|
||||
// if the desired box crosses the dateline, it is automatically split into
|
||||
// two boxes joined through a disjunction searcher
|
||||
func boxSearcher(indexReader index.IndexReader,
|
||||
topLeftLon, topLeftLat, bottomRightLon, bottomRightLat float64,
|
||||
field string, boost float64, options search.SearcherOptions) (
|
||||
search.Searcher, error) {
|
||||
if bottomRightLon < topLeftLon {
|
||||
// cross date line, rewrite as two parts
|
||||
|
||||
leftSearcher, err := NewGeoBoundingBoxSearcher(indexReader,
|
||||
-180, bottomRightLat, bottomRightLon, topLeftLat,
|
||||
field, boost, options, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rightSearcher, err := NewGeoBoundingBoxSearcher(indexReader,
|
||||
topLeftLon, bottomRightLat, 180, topLeftLat, field, boost, options, false)
|
||||
if err != nil {
|
||||
_ = leftSearcher.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boxSearcher, err := NewDisjunctionSearcher(indexReader,
|
||||
[]search.Searcher{leftSearcher, rightSearcher}, 0, options)
|
||||
if err != nil {
|
||||
_ = leftSearcher.Close()
|
||||
_ = rightSearcher.Close()
|
||||
return nil, err
|
||||
}
|
||||
return boxSearcher, nil
|
||||
}
|
||||
|
||||
// build geoboundinggox searcher for that bounding box
|
||||
boxSearcher, err := NewGeoBoundingBoxSearcher(indexReader,
|
||||
topLeftLon, bottomRightLat, bottomRightLon, topLeftLat, field, boost,
|
||||
options, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return boxSearcher, nil
|
||||
}
|
||||
|
||||
func buildDistFilter(indexReader index.IndexReader, field string,
|
||||
centerLon, centerLat, maxDist float64) FilterFunc {
|
||||
return func(d *search.DocumentMatch) bool {
|
||||
var lon, lat float64
|
||||
var found bool
|
||||
err := indexReader.DocumentVisitFieldTerms(d.IndexInternalID,
|
||||
[]string{field}, func(field string, term []byte) {
|
||||
// only consider the values which are shifted 0
|
||||
prefixCoded := numeric.PrefixCoded(term)
|
||||
shift, err := prefixCoded.Shift()
|
||||
if err == nil && shift == 0 {
|
||||
i64, err := prefixCoded.Int64()
|
||||
if err == nil {
|
||||
lon = geo.MortonUnhashLon(uint64(i64))
|
||||
lat = geo.MortonUnhashLat(uint64(i64))
|
||||
found = true
|
||||
}
|
||||
}
|
||||
})
|
||||
if err == nil && found {
|
||||
dist := geo.Haversin(lon, lat, centerLon, centerLat)
|
||||
if dist <= maxDist/1000 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
105
vendor/github.com/blevesearch/bleve/search/searcher/search_match_all.go
generated
vendored
Normal file
105
vendor/github.com/blevesearch/bleve/search/searcher/search_match_all.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
"github.com/blevesearch/bleve/search/scorer"
|
||||
)
|
||||
|
||||
type MatchAllSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
reader index.DocIDReader
|
||||
scorer *scorer.ConstantScorer
|
||||
count uint64
|
||||
}
|
||||
|
||||
func NewMatchAllSearcher(indexReader index.IndexReader, boost float64, options search.SearcherOptions) (*MatchAllSearcher, error) {
|
||||
reader, err := indexReader.DocIDReaderAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count, err := indexReader.DocCount()
|
||||
if err != nil {
|
||||
_ = reader.Close()
|
||||
return nil, err
|
||||
}
|
||||
scorer := scorer.NewConstantScorer(1.0, boost, options)
|
||||
return &MatchAllSearcher{
|
||||
indexReader: indexReader,
|
||||
reader: reader,
|
||||
scorer: scorer,
|
||||
count: count,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) Count() uint64 {
|
||||
return s.count
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) Weight() float64 {
|
||||
return s.scorer.Weight()
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) SetQueryNorm(qnorm float64) {
|
||||
s.scorer.SetQueryNorm(qnorm)
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
id, err := s.reader.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if id == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// score match
|
||||
docMatch := s.scorer.Score(ctx, id)
|
||||
// return doc match
|
||||
return docMatch, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
id, err := s.reader.Advance(ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if id == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// score match
|
||||
docMatch := s.scorer.Score(ctx, id)
|
||||
|
||||
// return doc match
|
||||
return docMatch, nil
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) Close() error {
|
||||
return s.reader.Close()
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *MatchAllSearcher) DocumentMatchPoolSize() int {
|
||||
return 1
|
||||
}
|
62
vendor/github.com/blevesearch/bleve/search/searcher/search_match_none.go
generated
vendored
Normal file
62
vendor/github.com/blevesearch/bleve/search/searcher/search_match_none.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
type MatchNoneSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
}
|
||||
|
||||
func NewMatchNoneSearcher(indexReader index.IndexReader) (*MatchNoneSearcher, error) {
|
||||
return &MatchNoneSearcher{
|
||||
indexReader: indexReader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) Count() uint64 {
|
||||
return uint64(0)
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) Weight() float64 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) SetQueryNorm(qnorm float64) {
|
||||
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *MatchNoneSearcher) DocumentMatchPoolSize() int {
|
||||
return 0
|
||||
}
|
85
vendor/github.com/blevesearch/bleve/search/searcher/search_multi_term.go
generated
vendored
Normal file
85
vendor/github.com/blevesearch/bleve/search/searcher/search_multi_term.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 2017 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewMultiTermSearcher(indexReader index.IndexReader, terms []string,
|
||||
field string, boost float64, options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
qsearchers := make([]search.Searcher, len(terms))
|
||||
qsearchersClose := func() {
|
||||
for _, searcher := range qsearchers {
|
||||
if searcher != nil {
|
||||
_ = searcher.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, term := range terms {
|
||||
var err error
|
||||
qsearchers[i], err = NewTermSearcher(indexReader, term, field, boost, options)
|
||||
if err != nil {
|
||||
qsearchersClose()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// build disjunction searcher of these ranges
|
||||
return newMultiTermSearcherBytes(indexReader, qsearchers, field, boost,
|
||||
options, limit)
|
||||
}
|
||||
|
||||
func NewMultiTermSearcherBytes(indexReader index.IndexReader, terms [][]byte,
|
||||
field string, boost float64, options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
qsearchers := make([]search.Searcher, len(terms))
|
||||
qsearchersClose := func() {
|
||||
for _, searcher := range qsearchers {
|
||||
if searcher != nil {
|
||||
_ = searcher.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, term := range terms {
|
||||
var err error
|
||||
qsearchers[i], err = NewTermSearcherBytes(indexReader, term, field, boost, options)
|
||||
if err != nil {
|
||||
qsearchersClose()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return newMultiTermSearcherBytes(indexReader, qsearchers, field, boost,
|
||||
options, limit)
|
||||
}
|
||||
|
||||
func newMultiTermSearcherBytes(indexReader index.IndexReader,
|
||||
searchers []search.Searcher, field string, boost float64,
|
||||
options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
|
||||
// build disjunction searcher of these ranges
|
||||
searcher, err := newDisjunctionSearcher(indexReader, searchers, 0, options,
|
||||
limit)
|
||||
if err != nil {
|
||||
for _, s := range searchers {
|
||||
_ = s.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return searcher, nil
|
||||
}
|
169
vendor/github.com/blevesearch/bleve/search/searcher/search_numeric_range.go
generated
vendored
Normal file
169
vendor/github.com/blevesearch/bleve/search/searcher/search_numeric_range.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/numeric"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewNumericRangeSearcher(indexReader index.IndexReader,
|
||||
min *float64, max *float64, inclusiveMin, inclusiveMax *bool, field string,
|
||||
boost float64, options search.SearcherOptions) (search.Searcher, error) {
|
||||
// account for unbounded edges
|
||||
if min == nil {
|
||||
negInf := math.Inf(-1)
|
||||
min = &negInf
|
||||
}
|
||||
if max == nil {
|
||||
Inf := math.Inf(1)
|
||||
max = &Inf
|
||||
}
|
||||
if inclusiveMin == nil {
|
||||
defaultInclusiveMin := true
|
||||
inclusiveMin = &defaultInclusiveMin
|
||||
}
|
||||
if inclusiveMax == nil {
|
||||
defaultInclusiveMax := false
|
||||
inclusiveMax = &defaultInclusiveMax
|
||||
}
|
||||
// find all the ranges
|
||||
minInt64 := numeric.Float64ToInt64(*min)
|
||||
if !*inclusiveMin && minInt64 != math.MaxInt64 {
|
||||
minInt64++
|
||||
}
|
||||
maxInt64 := numeric.Float64ToInt64(*max)
|
||||
if !*inclusiveMax && maxInt64 != math.MinInt64 {
|
||||
maxInt64--
|
||||
}
|
||||
// FIXME hard-coded precision, should match field declaration
|
||||
termRanges := splitInt64Range(minInt64, maxInt64, 4)
|
||||
terms := termRanges.Enumerate()
|
||||
if tooManyClauses(len(terms)) {
|
||||
return nil, tooManyClausesErr()
|
||||
}
|
||||
|
||||
return NewMultiTermSearcherBytes(indexReader, terms, field, boost, options,
|
||||
true)
|
||||
}
|
||||
|
||||
type termRange struct {
|
||||
startTerm []byte
|
||||
endTerm []byte
|
||||
}
|
||||
|
||||
func (t *termRange) Enumerate() [][]byte {
|
||||
var rv [][]byte
|
||||
next := t.startTerm
|
||||
for bytes.Compare(next, t.endTerm) <= 0 {
|
||||
rv = append(rv, next)
|
||||
next = incrementBytes(next)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func incrementBytes(in []byte) []byte {
|
||||
rv := make([]byte, len(in))
|
||||
copy(rv, in)
|
||||
for i := len(rv) - 1; i >= 0; i-- {
|
||||
rv[i] = rv[i] + 1
|
||||
if rv[i] != 0 {
|
||||
// didn't overflow, so stop
|
||||
break
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
type termRanges []*termRange
|
||||
|
||||
func (tr termRanges) Enumerate() [][]byte {
|
||||
var rv [][]byte
|
||||
for _, tri := range tr {
|
||||
trie := tri.Enumerate()
|
||||
rv = append(rv, trie...)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func splitInt64Range(minBound, maxBound int64, precisionStep uint) termRanges {
|
||||
rv := make(termRanges, 0)
|
||||
if minBound > maxBound {
|
||||
return rv
|
||||
}
|
||||
|
||||
for shift := uint(0); ; shift += precisionStep {
|
||||
|
||||
diff := int64(1) << (shift + precisionStep)
|
||||
mask := ((int64(1) << precisionStep) - int64(1)) << shift
|
||||
hasLower := (minBound & mask) != int64(0)
|
||||
hasUpper := (maxBound & mask) != mask
|
||||
|
||||
var nextMinBound int64
|
||||
if hasLower {
|
||||
nextMinBound = (minBound + diff) &^ mask
|
||||
} else {
|
||||
nextMinBound = minBound &^ mask
|
||||
}
|
||||
var nextMaxBound int64
|
||||
if hasUpper {
|
||||
nextMaxBound = (maxBound - diff) &^ mask
|
||||
} else {
|
||||
nextMaxBound = maxBound &^ mask
|
||||
}
|
||||
|
||||
lowerWrapped := nextMinBound < minBound
|
||||
upperWrapped := nextMaxBound > maxBound
|
||||
|
||||
if shift+precisionStep >= 64 || nextMinBound > nextMaxBound ||
|
||||
lowerWrapped || upperWrapped {
|
||||
// We are in the lowest precision or the next precision is not available.
|
||||
rv = append(rv, newRange(minBound, maxBound, shift))
|
||||
// exit the split recursion loop
|
||||
break
|
||||
}
|
||||
|
||||
if hasLower {
|
||||
rv = append(rv, newRange(minBound, minBound|mask, shift))
|
||||
}
|
||||
if hasUpper {
|
||||
rv = append(rv, newRange(maxBound&^mask, maxBound, shift))
|
||||
}
|
||||
|
||||
// recurse to next precision
|
||||
minBound = nextMinBound
|
||||
maxBound = nextMaxBound
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
func newRange(minBound, maxBound int64, shift uint) *termRange {
|
||||
maxBound |= (int64(1) << shift) - int64(1)
|
||||
minBytes := numeric.MustNewPrefixCodedInt64(minBound, shift)
|
||||
maxBytes := numeric.MustNewPrefixCodedInt64(maxBound, shift)
|
||||
return newRangeBytes(minBytes, maxBytes)
|
||||
}
|
||||
|
||||
func newRangeBytes(minBytes, maxBytes []byte) *termRange {
|
||||
return &termRange{
|
||||
startTerm: minBytes,
|
||||
endTerm: maxBytes,
|
||||
}
|
||||
}
|
341
vendor/github.com/blevesearch/bleve/search/searcher/search_phrase.go
generated
vendored
Normal file
341
vendor/github.com/blevesearch/bleve/search/searcher/search_phrase.go
generated
vendored
Normal file
|
@ -0,0 +1,341 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
type PhraseSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
mustSearcher *ConjunctionSearcher
|
||||
queryNorm float64
|
||||
currMust *search.DocumentMatch
|
||||
slop int
|
||||
terms [][]string
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func NewPhraseSearcher(indexReader index.IndexReader, terms []string, field string, options search.SearcherOptions) (*PhraseSearcher, error) {
|
||||
// turn flat terms []string into [][]string
|
||||
mterms := make([][]string, len(terms))
|
||||
for i, term := range terms {
|
||||
mterms[i] = []string{term}
|
||||
}
|
||||
return NewMultiPhraseSearcher(indexReader, mterms, field, options)
|
||||
}
|
||||
|
||||
func NewMultiPhraseSearcher(indexReader index.IndexReader, terms [][]string, field string, options search.SearcherOptions) (*PhraseSearcher, error) {
|
||||
options.IncludeTermVectors = true
|
||||
var termPositionSearchers []search.Searcher
|
||||
for _, termPos := range terms {
|
||||
if len(termPos) == 1 && termPos[0] != "" {
|
||||
// single term
|
||||
ts, err := NewTermSearcher(indexReader, termPos[0], field, 1.0, options)
|
||||
if err != nil {
|
||||
// close any searchers already opened
|
||||
for _, ts := range termPositionSearchers {
|
||||
_ = ts.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("phrase searcher error building term searcher: %v", err)
|
||||
}
|
||||
termPositionSearchers = append(termPositionSearchers, ts)
|
||||
} else if len(termPos) > 1 {
|
||||
// multiple terms
|
||||
var termSearchers []search.Searcher
|
||||
for _, term := range termPos {
|
||||
if term == "" {
|
||||
continue
|
||||
}
|
||||
ts, err := NewTermSearcher(indexReader, term, field, 1.0, options)
|
||||
if err != nil {
|
||||
// close any searchers already opened
|
||||
for _, ts := range termPositionSearchers {
|
||||
_ = ts.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("phrase searcher error building term searcher: %v", err)
|
||||
}
|
||||
termSearchers = append(termSearchers, ts)
|
||||
}
|
||||
disjunction, err := NewDisjunctionSearcher(indexReader, termSearchers, 1, options)
|
||||
if err != nil {
|
||||
// close any searchers already opened
|
||||
for _, ts := range termPositionSearchers {
|
||||
_ = ts.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("phrase searcher error building term position disjunction searcher: %v", err)
|
||||
}
|
||||
termPositionSearchers = append(termPositionSearchers, disjunction)
|
||||
}
|
||||
}
|
||||
|
||||
mustSearcher, err := NewConjunctionSearcher(indexReader, termPositionSearchers, options)
|
||||
if err != nil {
|
||||
// close any searchers already opened
|
||||
for _, ts := range termPositionSearchers {
|
||||
_ = ts.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("phrase searcher error building conjunction searcher: %v", err)
|
||||
}
|
||||
|
||||
// build our searcher
|
||||
rv := PhraseSearcher{
|
||||
indexReader: indexReader,
|
||||
mustSearcher: mustSearcher,
|
||||
terms: terms,
|
||||
}
|
||||
rv.computeQueryNorm()
|
||||
return &rv, nil
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) computeQueryNorm() {
|
||||
// first calculate sum of squared weights
|
||||
sumOfSquaredWeights := 0.0
|
||||
if s.mustSearcher != nil {
|
||||
sumOfSquaredWeights += s.mustSearcher.Weight()
|
||||
}
|
||||
|
||||
// now compute query norm from this
|
||||
s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights)
|
||||
// finally tell all the downstream searchers the norm
|
||||
if s.mustSearcher != nil {
|
||||
s.mustSearcher.SetQueryNorm(s.queryNorm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) initSearchers(ctx *search.SearchContext) error {
|
||||
err := s.advanceNextMust(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.initialized = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) advanceNextMust(ctx *search.SearchContext) error {
|
||||
var err error
|
||||
|
||||
if s.mustSearcher != nil {
|
||||
s.currMust, err = s.mustSearcher.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) Weight() float64 {
|
||||
return s.mustSearcher.Weight()
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) SetQueryNorm(qnorm float64) {
|
||||
s.mustSearcher.SetQueryNorm(qnorm)
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for s.currMust != nil {
|
||||
// check this match against phrase constraints
|
||||
rv := s.checkCurrMustMatch(ctx)
|
||||
|
||||
// prepare for next iteration (either loop or subsequent call to Next())
|
||||
err := s.advanceNextMust(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if match satisfied phrase constraints return it as a hit
|
||||
if rv != nil {
|
||||
return rv, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// checkCurrMustMatch is soley concerned with determining if the DocumentMatch
|
||||
// pointed to by s.currMust (which satisifies the pre-condition searcher)
|
||||
// also satisfies the phase constraints. if so, it returns a DocumentMatch
|
||||
// for this document, otherwise nil
|
||||
func (s *PhraseSearcher) checkCurrMustMatch(ctx *search.SearchContext) *search.DocumentMatch {
|
||||
rvftlm := make(search.FieldTermLocationMap, 0)
|
||||
freq := 0
|
||||
// typically we would expect there to only actually be results in
|
||||
// one field, but we allow for this to not be the case
|
||||
// but, we note that phrase constraints can only be satisfied within
|
||||
// a single field, so we can check them each independently
|
||||
for field, tlm := range s.currMust.Locations {
|
||||
|
||||
f, rvtlm := s.checkCurrMustMatchField(ctx, tlm)
|
||||
if f > 0 {
|
||||
freq += f
|
||||
rvftlm[field] = rvtlm
|
||||
}
|
||||
}
|
||||
|
||||
if freq > 0 {
|
||||
// return match
|
||||
rv := s.currMust
|
||||
rv.Locations = rvftlm
|
||||
return rv
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkCurrMustMatchField is soley concerned with determining if one particular
|
||||
// field within the currMust DocumentMatch Locations satisfies the phase
|
||||
// constraints (possibly more than once). if so, the number of times it was
|
||||
// satisfied, and these locations are returned. otherwise 0 and either
|
||||
// a nil or empty TermLocationMap
|
||||
func (s *PhraseSearcher) checkCurrMustMatchField(ctx *search.SearchContext, tlm search.TermLocationMap) (int, search.TermLocationMap) {
|
||||
paths := findPhrasePaths(0, nil, s.terms, tlm, nil, 0)
|
||||
rv := make(search.TermLocationMap, len(s.terms))
|
||||
for _, p := range paths {
|
||||
p.MergeInto(rv)
|
||||
}
|
||||
return len(paths), rv
|
||||
}
|
||||
|
||||
type phrasePart struct {
|
||||
term string
|
||||
loc *search.Location
|
||||
}
|
||||
|
||||
type phrasePath []*phrasePart
|
||||
|
||||
func (p phrasePath) MergeInto(in search.TermLocationMap) {
|
||||
for _, pp := range p {
|
||||
in[pp.term] = append(in[pp.term], pp.loc)
|
||||
}
|
||||
}
|
||||
|
||||
// findPhrasePaths is a function to identify phase matches from a set of known
|
||||
// term locations. the implementation is recursive, so care must be taken
|
||||
// with arguments and return values.
|
||||
//
|
||||
// prev - the previous location, nil on first invocation
|
||||
// phraseTerms - slice containing the phrase terms themselves
|
||||
// may contain empty string as placeholder (don't care)
|
||||
// tlm - the Term Location Map containing all relevant term locations
|
||||
// offset - the offset from the previous that this next term must match
|
||||
// p - the current path being explored (appended to in recursive calls)
|
||||
// this is the primary state being built during the traversal
|
||||
//
|
||||
// returns slice of paths, or nil if invocation did not find any successul paths
|
||||
func findPhrasePaths(prevPos uint64, ap search.ArrayPositions, phraseTerms [][]string, tlm search.TermLocationMap, p phrasePath, remainingSlop int) []phrasePath {
|
||||
|
||||
// no more terms
|
||||
if len(phraseTerms) < 1 {
|
||||
return []phrasePath{p}
|
||||
}
|
||||
|
||||
car := phraseTerms[0]
|
||||
cdr := phraseTerms[1:]
|
||||
|
||||
// empty term is treated as match (continue)
|
||||
if len(car) == 0 || (len(car) == 1 && car[0] == "") {
|
||||
nextPos := prevPos + 1
|
||||
if prevPos == 0 {
|
||||
// if prevPos was 0, don't set it to 1 (as thats not a real abs pos)
|
||||
nextPos = 0 // don't advance nextPos if prevPos was 0
|
||||
}
|
||||
return findPhrasePaths(nextPos, ap, cdr, tlm, p, remainingSlop)
|
||||
}
|
||||
|
||||
var rv []phrasePath
|
||||
// locations for this term
|
||||
for _, carTerm := range car {
|
||||
locations := tlm[carTerm]
|
||||
for _, loc := range locations {
|
||||
if prevPos != 0 && !loc.ArrayPositions.Equals(ap) {
|
||||
// if the array positions are wrong, can't match, try next location
|
||||
continue
|
||||
}
|
||||
|
||||
// compute distance from previous phrase term
|
||||
dist := 0
|
||||
if prevPos != 0 {
|
||||
dist = editDistance(prevPos+1, loc.Pos)
|
||||
}
|
||||
|
||||
// if enough slop reamining, continue recursively
|
||||
if prevPos == 0 || (remainingSlop-dist) >= 0 {
|
||||
// this location works, add it to the path (but not for empty term)
|
||||
px := append(p, &phrasePart{term: carTerm, loc: loc})
|
||||
rv = append(rv, findPhrasePaths(loc.Pos, loc.ArrayPositions, cdr, tlm, px, remainingSlop-dist)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func editDistance(p1, p2 uint64) int {
|
||||
dist := int(p1 - p2)
|
||||
if dist < 0 {
|
||||
return -dist
|
||||
}
|
||||
return dist
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
if !s.initialized {
|
||||
err := s.initSearchers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
s.currMust, err = s.mustSearcher.Advance(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.Next(ctx)
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) Count() uint64 {
|
||||
// for now return a worst case
|
||||
return s.mustSearcher.Count()
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) Close() error {
|
||||
if s.mustSearcher != nil {
|
||||
err := s.mustSearcher.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *PhraseSearcher) DocumentMatchPoolSize() int {
|
||||
return s.mustSearcher.DocumentMatchPoolSize() + 1
|
||||
}
|
80
vendor/github.com/blevesearch/bleve/search/searcher/search_regexp.go
generated
vendored
Normal file
80
vendor/github.com/blevesearch/bleve/search/searcher/search_regexp.go
generated
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) 2015 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 searcher
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
// NewRegexpSearcher creates a searcher which will match documents that
|
||||
// contain terms which match the pattern regexp. The match must be EXACT
|
||||
// matching the entire term. The provided regexp SHOULD NOT start with ^
|
||||
// or end with $ as this can intefere with the implementation. Separately,
|
||||
// matches will be checked to ensure they match the entire term.
|
||||
func NewRegexpSearcher(indexReader index.IndexReader, pattern *regexp.Regexp,
|
||||
field string, boost float64, options search.SearcherOptions) (
|
||||
search.Searcher, error) {
|
||||
|
||||
prefixTerm, complete := pattern.LiteralPrefix()
|
||||
var candidateTerms []string
|
||||
if complete {
|
||||
// there is no pattern
|
||||
candidateTerms = []string{prefixTerm}
|
||||
} else {
|
||||
var err error
|
||||
candidateTerms, err = findRegexpCandidateTerms(indexReader, pattern, field,
|
||||
prefixTerm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return NewMultiTermSearcher(indexReader, candidateTerms, field, boost,
|
||||
options, true)
|
||||
}
|
||||
|
||||
func findRegexpCandidateTerms(indexReader index.IndexReader,
|
||||
pattern *regexp.Regexp, field, prefixTerm string) (rv []string, err error) {
|
||||
rv = make([]string, 0)
|
||||
var fieldDict index.FieldDict
|
||||
if len(prefixTerm) > 0 {
|
||||
fieldDict, err = indexReader.FieldDictPrefix(field, []byte(prefixTerm))
|
||||
} else {
|
||||
fieldDict, err = indexReader.FieldDict(field)
|
||||
}
|
||||
defer func() {
|
||||
if cerr := fieldDict.Close(); cerr != nil && err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
|
||||
// enumerate the terms and check against regexp
|
||||
tfd, err := fieldDict.Next()
|
||||
for err == nil && tfd != nil {
|
||||
matchPos := pattern.FindStringIndex(tfd.Term)
|
||||
if matchPos != nil && matchPos[0] == 0 && matchPos[1] == len(tfd.Term) {
|
||||
rv = append(rv, tfd.Term)
|
||||
if tooManyClauses(len(rv)) {
|
||||
return rv, tooManyClausesErr()
|
||||
}
|
||||
}
|
||||
tfd, err = fieldDict.Next()
|
||||
}
|
||||
|
||||
return rv, err
|
||||
}
|
122
vendor/github.com/blevesearch/bleve/search/searcher/search_term.go
generated
vendored
Normal file
122
vendor/github.com/blevesearch/bleve/search/searcher/search_term.go
generated
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
"github.com/blevesearch/bleve/search/scorer"
|
||||
)
|
||||
|
||||
type TermSearcher struct {
|
||||
indexReader index.IndexReader
|
||||
reader index.TermFieldReader
|
||||
scorer *scorer.TermQueryScorer
|
||||
tfd index.TermFieldDoc
|
||||
}
|
||||
|
||||
func NewTermSearcher(indexReader index.IndexReader, term string, field string, boost float64, options search.SearcherOptions) (*TermSearcher, error) {
|
||||
reader, err := indexReader.TermFieldReader([]byte(term), field, true, true, options.IncludeTermVectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count, err := indexReader.DocCount()
|
||||
if err != nil {
|
||||
_ = reader.Close()
|
||||
return nil, err
|
||||
}
|
||||
scorer := scorer.NewTermQueryScorer([]byte(term), field, boost, count, reader.Count(), options)
|
||||
return &TermSearcher{
|
||||
indexReader: indexReader,
|
||||
reader: reader,
|
||||
scorer: scorer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewTermSearcherBytes(indexReader index.IndexReader, term []byte, field string, boost float64, options search.SearcherOptions) (*TermSearcher, error) {
|
||||
reader, err := indexReader.TermFieldReader(term, field, true, true, options.IncludeTermVectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count, err := indexReader.DocCount()
|
||||
if err != nil {
|
||||
_ = reader.Close()
|
||||
return nil, err
|
||||
}
|
||||
scorer := scorer.NewTermQueryScorer(term, field, boost, count, reader.Count(), options)
|
||||
return &TermSearcher{
|
||||
indexReader: indexReader,
|
||||
reader: reader,
|
||||
scorer: scorer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *TermSearcher) Count() uint64 {
|
||||
return s.reader.Count()
|
||||
}
|
||||
|
||||
func (s *TermSearcher) Weight() float64 {
|
||||
return s.scorer.Weight()
|
||||
}
|
||||
|
||||
func (s *TermSearcher) SetQueryNorm(qnorm float64) {
|
||||
s.scorer.SetQueryNorm(qnorm)
|
||||
}
|
||||
|
||||
func (s *TermSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
|
||||
termMatch, err := s.reader.Next(s.tfd.Reset())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if termMatch == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// score match
|
||||
docMatch := s.scorer.Score(ctx, termMatch)
|
||||
// return doc match
|
||||
return docMatch, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *TermSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
|
||||
termMatch, err := s.reader.Advance(ID, s.tfd.Reset())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if termMatch == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// score match
|
||||
docMatch := s.scorer.Score(ctx, termMatch)
|
||||
|
||||
// return doc match
|
||||
return docMatch, nil
|
||||
}
|
||||
|
||||
func (s *TermSearcher) Close() error {
|
||||
return s.reader.Close()
|
||||
}
|
||||
|
||||
func (s *TermSearcher) Min() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *TermSearcher) DocumentMatchPoolSize() int {
|
||||
return 1
|
||||
}
|
39
vendor/github.com/blevesearch/bleve/search/searcher/search_term_prefix.go
generated
vendored
Normal file
39
vendor/github.com/blevesearch/bleve/search/searcher/search_term_prefix.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewTermPrefixSearcher(indexReader index.IndexReader, prefix string,
|
||||
field string, boost float64, options search.SearcherOptions) (
|
||||
search.Searcher, error) {
|
||||
// find the terms with this prefix
|
||||
fieldDict, err := indexReader.FieldDictPrefix(field, []byte(prefix))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var terms []string
|
||||
tfd, err := fieldDict.Next()
|
||||
for err == nil && tfd != nil {
|
||||
terms = append(terms, tfd.Term)
|
||||
tfd, err = fieldDict.Next()
|
||||
}
|
||||
|
||||
return NewMultiTermSearcher(indexReader, terms, field, boost, options, true)
|
||||
}
|
75
vendor/github.com/blevesearch/bleve/search/searcher/search_term_range.go
generated
vendored
Normal file
75
vendor/github.com/blevesearch/bleve/search/searcher/search_term_range.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2017 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 searcher
|
||||
|
||||
import (
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
||||
func NewTermRangeSearcher(indexReader index.IndexReader,
|
||||
min, max []byte, inclusiveMin, inclusiveMax *bool, field string,
|
||||
boost float64, options search.SearcherOptions) (search.Searcher, error) {
|
||||
|
||||
if inclusiveMin == nil {
|
||||
defaultInclusiveMin := true
|
||||
inclusiveMin = &defaultInclusiveMin
|
||||
}
|
||||
if inclusiveMax == nil {
|
||||
defaultInclusiveMax := false
|
||||
inclusiveMax = &defaultInclusiveMax
|
||||
}
|
||||
|
||||
if min == nil {
|
||||
min = []byte{}
|
||||
}
|
||||
|
||||
rangeMax := max
|
||||
if rangeMax != nil {
|
||||
// the term dictionary range end has an unfortunate implementation
|
||||
rangeMax = append(rangeMax, 0)
|
||||
}
|
||||
|
||||
// find the terms with this prefix
|
||||
fieldDict, err := indexReader.FieldDictRange(field, min, rangeMax)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var terms []string
|
||||
tfd, err := fieldDict.Next()
|
||||
for err == nil && tfd != nil {
|
||||
terms = append(terms, tfd.Term)
|
||||
tfd, err = fieldDict.Next()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(terms) < 1 {
|
||||
return NewMatchNoneSearcher(indexReader)
|
||||
}
|
||||
|
||||
if !*inclusiveMin && min != nil && string(min) == terms[0] {
|
||||
terms = terms[1:]
|
||||
}
|
||||
|
||||
// if our term list included the max, it would be the last item
|
||||
if !*inclusiveMax && max != nil && string(max) == terms[len(terms)-1] {
|
||||
terms = terms[:len(terms)-1]
|
||||
}
|
||||
|
||||
return NewMultiTermSearcher(indexReader, terms, field, boost, options, true)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue