0
0
Fork 0

major refactor of search package

this started initially to relocate highlighting into
a self contained package, which would then also use
the registry
however, it turned into a much larger refactor in
order to avoid cyclic imports
now facets, searchers, scorers and collectors
are also broken out into subpackages of search
This commit is contained in:
Marty Schoch 2014-09-01 11:15:38 -04:00
parent 209f808722
commit 2ee7289bc8
61 changed files with 1148 additions and 694 deletions

View File

@ -11,9 +11,18 @@ package bleve
import (
"expvar"
"github.com/blevesearch/bleve/registry"
"time"
"github.com/blevesearch/bleve/search"
// fragment formatters
_ "github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi"
_ "github.com/blevesearch/bleve/search/highlight/fragment_formatters/html"
// fragmenters
_ "github.com/blevesearch/bleve/search/highlight/fragmenters/simple"
// highlighters
_ "github.com/blevesearch/bleve/search/highlight/highlighters/simple"
// char filters
_ "github.com/blevesearch/bleve/analysis/char_filters/html_char_filter"
@ -89,21 +98,15 @@ import (
var bleveExpVar = expvar.NewMap("bleve")
type HighlightConfig struct {
Highlighters map[string]search.Highlighter
}
type configuration struct {
Highlight *HighlightConfig
DefaultHighlighter *string
Cache *registry.Cache
DefaultHighlighter string
DefaultKVStore string
}
func newConfiguration() *configuration {
return &configuration{
Highlight: &HighlightConfig{
Highlighters: make(map[string]search.Highlighter),
},
Cache: registry.NewCache(),
}
}
@ -116,18 +119,26 @@ func init() {
// build the default configuration
Config = newConfiguration()
// register ansi highlighter
Config.Highlight.Highlighters["ansi"] = search.NewSimpleHighlighter()
Config.Cache.DefineFragmentFormatter("highlightSpanHTML", "html",
map[string]interface{}{
"before": `<span class="highlight">`,
"after": `</span>`,
})
// register html highlighter
htmlFormatter := search.NewHTMLFragmentFormatterCustom(`<span class="highlight">`, `</span>`)
htmlHighlighter := search.NewSimpleHighlighter()
htmlHighlighter.SetFragmentFormatter(htmlFormatter)
Config.Highlight.Highlighters["html"] = htmlHighlighter
Config.Cache.DefineHighlighter("html", "simple",
map[string]interface{}{
"fragmenter": "simple",
"formatter": "highlightSpanHTML",
})
Config.Cache.DefineHighlighter("ansi", "simple",
map[string]interface{}{
"fragmenter": "simple",
"formatter": "ansi",
})
// set the default highlighter
htmlHighlighterName := "html"
Config.DefaultHighlighter = &htmlHighlighterName
Config.DefaultHighlighter = "html"
// default kv store
Config.DefaultKVStore = "boltdb"

View File

@ -22,6 +22,8 @@ import (
"github.com/blevesearch/bleve/index/upside_down"
"github.com/blevesearch/bleve/registry"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/collectors"
"github.com/blevesearch/bleve/search/facets"
)
type indexImpl struct {
@ -320,7 +322,7 @@ func (i *indexImpl) Search(req *SearchRequest) (*SearchResult, error) {
return nil, ERROR_INDEX_CLOSED
}
collector := search.NewTopScorerSkipCollector(req.Size, req.From)
collector := collectors.NewTopScorerSkipCollector(req.Size, req.From)
searcher, err := req.Query.Searcher(i, req.Explain)
if err != nil {
return nil, err
@ -332,14 +334,14 @@ func (i *indexImpl) Search(req *SearchRequest) (*SearchResult, error) {
for facetName, facetRequest := range req.Facets {
if facetRequest.NumericRanges != nil {
// build numeric range facet
facetBuilder := search.NewNumericFacetBuilder(facetRequest.Field, facetRequest.Size)
facetBuilder := facets.NewNumericFacetBuilder(facetRequest.Field, facetRequest.Size)
for _, nr := range facetRequest.NumericRanges {
facetBuilder.AddRange(nr.Name, nr.Min, nr.Max)
}
facetsBuilder.Add(facetName, facetBuilder)
} else if facetRequest.DateTimeRanges != nil {
// build date range facet
facetBuilder := search.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size)
facetBuilder := facets.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size)
dateTimeParser := i.m.dateTimeParserNamed(i.m.DefaultDateTimeParser)
for _, dr := range facetRequest.DateTimeRanges {
dr.ParseDates(dateTimeParser)
@ -348,7 +350,7 @@ func (i *indexImpl) Search(req *SearchRequest) (*SearchResult, error) {
facetsBuilder.Add(facetName, facetBuilder)
} else {
// build terms facet
facetBuilder := search.NewTermsFacetBuilder(facetRequest.Field, facetRequest.Size)
facetBuilder := facets.NewTermsFacetBuilder(facetRequest.Field, facetRequest.Size)
facetsBuilder.Add(facetName, facetBuilder)
}
}
@ -364,13 +366,19 @@ func (i *indexImpl) Search(req *SearchRequest) (*SearchResult, error) {
if req.Highlight != nil {
// get the right highlighter
highlighter := Config.Highlight.Highlighters[*Config.DefaultHighlighter]
highlighter, err := Config.Cache.HighlighterNamed(Config.DefaultHighlighter)
if err != nil {
return nil, err
}
if req.Highlight.Style != nil {
highlighter = Config.Highlight.Highlighters[*req.Highlight.Style]
if highlighter == nil {
return nil, fmt.Errorf("no highlighter named `%s` registered", *req.Highlight.Style)
highlighter, err = Config.Cache.HighlighterNamed(*req.Highlight.Style)
if err != nil {
return nil, err
}
}
if highlighter == nil {
return nil, fmt.Errorf("no highlighter named `%s` registered", *req.Highlight.Style)
}
for _, hit := range hits {
doc, err := i.i.Document(hit.ID)

View File

@ -14,6 +14,7 @@ import (
"fmt"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type booleanQuery struct {
@ -97,7 +98,7 @@ func (q *booleanQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, er
}
}
return search.NewBooleanSearcher(i.i, mustSearcher, shouldSearcher, mustNotSearcher, explain)
return searchers.NewBooleanSearcher(i.i, mustSearcher, shouldSearcher, mustNotSearcher, explain)
}
func (q *booleanQuery) Validate() error {

View File

@ -13,6 +13,7 @@ import (
"encoding/json"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type conjunctionQuery struct {
@ -44,15 +45,15 @@ func (q *conjunctionQuery) AddQuery(aq Query) *conjunctionQuery {
}
func (q *conjunctionQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, error) {
searchers := make([]search.Searcher, len(q.Conjuncts))
ss := make([]search.Searcher, len(q.Conjuncts))
for in, conjunct := range q.Conjuncts {
var err error
searchers[in], err = conjunct.Searcher(i, explain)
ss[in], err = conjunct.Searcher(i, explain)
if err != nil {
return nil, err
}
}
return search.NewConjunctionSearcher(i.i, searchers, explain)
return searchers.NewConjunctionSearcher(i.i, ss, explain)
}
func (q *conjunctionQuery) Validate() error {

View File

@ -15,6 +15,7 @@ import (
"github.com/blevesearch/bleve/numeric_util"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type dateRangeQuery struct {
@ -99,7 +100,7 @@ func (q *dateRangeQuery) Searcher(i *indexImpl, explain bool) (search.Searcher,
max = numeric_util.Int64ToFloat64(endTime.UnixNano())
}
return search.NewNumericRangeSearcher(i.i, &min, &max, q.InclusiveStart, q.InclusiveEnd, field, q.BoostVal, explain)
return searchers.NewNumericRangeSearcher(i.i, &min, &max, q.InclusiveStart, q.InclusiveEnd, field, q.BoostVal, explain)
}
func (q *dateRangeQuery) Validate() error {

View File

@ -13,6 +13,7 @@ import (
"encoding/json"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type disjunctionQuery struct {
@ -64,15 +65,15 @@ func (q *disjunctionQuery) SetMin(m float64) Query {
}
func (q *disjunctionQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, error) {
searchers := make([]search.Searcher, len(q.Disjuncts))
ss := make([]search.Searcher, len(q.Disjuncts))
for in, disjunct := range q.Disjuncts {
var err error
searchers[in], err = disjunct.Searcher(i, explain)
ss[in], err = disjunct.Searcher(i, explain)
if err != nil {
return nil, err
}
}
return search.NewDisjunctionSearcher(i.i, searchers, q.MinVal, explain)
return searchers.NewDisjunctionSearcher(i.i, ss, q.MinVal, explain)
}
func (q *disjunctionQuery) Validate() error {

View File

@ -11,6 +11,7 @@ package bleve
import (
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type matchAllQuery struct {
@ -35,7 +36,7 @@ func (q *matchAllQuery) SetBoost(b float64) Query {
}
func (q *matchAllQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, error) {
return search.NewMatchAllSearcher(i.i, q.BoostVal, explain)
return searchers.NewMatchAllSearcher(i.i, q.BoostVal, explain)
}
func (q *matchAllQuery) Validate() error {

View File

@ -11,6 +11,7 @@ package bleve
import (
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type matchNoneQuery struct {
@ -35,7 +36,7 @@ func (q *matchNoneQuery) SetBoost(b float64) Query {
}
func (q *matchNoneQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, error) {
return search.NewMatchNoneSearcher(i.i)
return searchers.NewMatchNoneSearcher(i.i)
}
func (q *matchNoneQuery) Validate() error {

View File

@ -11,6 +11,7 @@ package bleve
import (
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type numericRangeQuery struct {
@ -68,7 +69,7 @@ func (q *numericRangeQuery) Searcher(i *indexImpl, explain bool) (search.Searche
if q.FieldVal == "" {
field = i.m.DefaultField
}
return search.NewNumericRangeSearcher(i.i, q.Min, q.Max, q.InclusiveMin, q.InclusiveMax, field, q.BoostVal, explain)
return searchers.NewNumericRangeSearcher(i.i, q.Min, q.Max, q.InclusiveMin, q.InclusiveMax, field, q.BoostVal, explain)
}
func (q *numericRangeQuery) Validate() error {

View File

@ -14,6 +14,7 @@ import (
"fmt"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type phraseQuery struct {
@ -58,7 +59,7 @@ func (q *phraseQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, err
if err != nil {
return nil, err
}
return search.NewPhraseSearcher(i.i, conjunctionSearcher.(*search.ConjunctionSearcher), terms)
return searchers.NewPhraseSearcher(i.i, conjunctionSearcher.(*searchers.ConjunctionSearcher), terms)
}
func (q *phraseQuery) Validate() error {

View File

@ -11,6 +11,7 @@ package bleve
import (
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type prefixQuery struct {
@ -52,7 +53,7 @@ func (q *prefixQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, err
if q.FieldVal == "" {
field = i.m.DefaultField
}
return search.NewTermPrefixSearcher(i.i, q.Prefix, field, q.BoostVal, explain)
return searchers.NewTermPrefixSearcher(i.i, q.Prefix, field, q.BoostVal, explain)
}
func (q *prefixQuery) Validate() error {

View File

@ -11,6 +11,7 @@ package bleve
import (
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/searchers"
)
type termQuery struct {
@ -51,7 +52,7 @@ func (q *termQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, error
if q.FieldVal == "" {
field = i.m.DefaultField
}
return search.NewTermSearcher(i.i, q.Term, field, q.BoostVal, explain)
return searchers.NewTermSearcher(i.i, q.Term, field, q.BoostVal, explain)
}
func (q *termQuery) Validate() error {

View File

@ -0,0 +1,61 @@
// 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 registry
import (
"fmt"
"github.com/blevesearch/bleve/search/highlight"
)
func RegisterFragmentFormatter(name string, constructor FragmentFormatterConstructor) {
_, exists := fragmentFormatters[name]
if exists {
panic(fmt.Errorf("attempted to register duplicate fragment formatter named '%s'", name))
}
fragmentFormatters[name] = constructor
}
type FragmentFormatterConstructor func(config map[string]interface{}, cache *Cache) (highlight.FragmentFormatter, error)
type FragmentFormatterRegistry map[string]FragmentFormatterConstructor
type FragmentFormatterCache map[string]highlight.FragmentFormatter
func (c FragmentFormatterCache) FragmentFormatterNamed(name string, cache *Cache) (highlight.FragmentFormatter, error) {
fragmentFormatter, cached := c[name]
if cached {
return fragmentFormatter, nil
}
fragmentFormatterConstructor, registered := fragmentFormatters[name]
if !registered {
return nil, fmt.Errorf("no fragment formatter with name or type '%s' registered", name)
}
fragmentFormatter, err := fragmentFormatterConstructor(nil, cache)
if err != nil {
return nil, fmt.Errorf("error building fragment formatter: %v", err)
}
c[name] = fragmentFormatter
return fragmentFormatter, nil
}
func (c FragmentFormatterCache) DefineFragmentFormatter(name string, typ string, config map[string]interface{}, cache *Cache) (highlight.FragmentFormatter, error) {
_, cached := c[name]
if cached {
return nil, fmt.Errorf("fragment formatter named '%s' already defined", name)
}
fragmentFormatterConstructor, registered := fragmentFormatters[typ]
if !registered {
return nil, fmt.Errorf("no fragment formatter type '%s' registered", typ)
}
fragmentFormatter, err := fragmentFormatterConstructor(config, cache)
if err != nil {
return nil, fmt.Errorf("error building fragment formatter: %v", err)
}
c[name] = fragmentFormatter
return fragmentFormatter, nil
}

61
registry/fragmenter.go Normal file
View File

@ -0,0 +1,61 @@
// 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 registry
import (
"fmt"
"github.com/blevesearch/bleve/search/highlight"
)
func RegisterFragmenter(name string, constructor FragmenterConstructor) {
_, exists := fragmenters[name]
if exists {
panic(fmt.Errorf("attempted to register duplicate fragmenter named '%s'", name))
}
fragmenters[name] = constructor
}
type FragmenterConstructor func(config map[string]interface{}, cache *Cache) (highlight.Fragmenter, error)
type FragmenterRegistry map[string]FragmenterConstructor
type FragmenterCache map[string]highlight.Fragmenter
func (c FragmenterCache) FragmenterNamed(name string, cache *Cache) (highlight.Fragmenter, error) {
fragmenter, cached := c[name]
if cached {
return fragmenter, nil
}
fragmenterConstructor, registered := fragmenters[name]
if !registered {
return nil, fmt.Errorf("no fragmenter with name or type '%s' registered", name)
}
fragmenter, err := fragmenterConstructor(nil, cache)
if err != nil {
return nil, fmt.Errorf("error building fragmenter: %v", err)
}
c[name] = fragmenter
return fragmenter, nil
}
func (c FragmenterCache) DefineFragmenter(name string, typ string, config map[string]interface{}, cache *Cache) (highlight.Fragmenter, error) {
_, cached := c[name]
if cached {
return nil, fmt.Errorf("fragmenter named '%s' already defined", name)
}
fragmenterConstructor, registered := fragmenters[typ]
if !registered {
return nil, fmt.Errorf("no fragmenter type '%s' registered", typ)
}
fragmenter, err := fragmenterConstructor(config, cache)
if err != nil {
return nil, fmt.Errorf("error building fragmenter: %v", err)
}
c[name] = fragmenter
return fragmenter, nil
}

61
registry/highlighter.go Normal file
View File

@ -0,0 +1,61 @@
// 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 registry
import (
"fmt"
"github.com/blevesearch/bleve/search/highlight"
)
func RegisterHighlighter(name string, constructor HighlighterConstructor) {
_, exists := highlighters[name]
if exists {
panic(fmt.Errorf("attempted to register duplicate highlighter named '%s'", name))
}
highlighters[name] = constructor
}
type HighlighterConstructor func(config map[string]interface{}, cache *Cache) (highlight.Highlighter, error)
type HighlighterRegistry map[string]HighlighterConstructor
type HighlighterCache map[string]highlight.Highlighter
func (c HighlighterCache) HighlighterNamed(name string, cache *Cache) (highlight.Highlighter, error) {
highlighter, cached := c[name]
if cached {
return highlighter, nil
}
highlighterConstructor, registered := highlighters[name]
if !registered {
return nil, fmt.Errorf("no highlighter with name or type '%s' registered", name)
}
highlighter, err := highlighterConstructor(nil, cache)
if err != nil {
return nil, fmt.Errorf("error building highlighter: %v", err)
}
c[name] = highlighter
return highlighter, nil
}
func (c HighlighterCache) DefineHighlighter(name string, typ string, config map[string]interface{}, cache *Cache) (highlight.Highlighter, error) {
_, cached := c[name]
if cached {
return nil, fmt.Errorf("highlighter named '%s' already defined", name)
}
highlighterConstructor, registered := highlighters[typ]
if !registered {
return nil, fmt.Errorf("no highlighter type '%s' registered", typ)
}
highlighter, err := highlighterConstructor(config, cache)
if err != nil {
return nil, fmt.Errorf("error building highlighter: %v", err)
}
c[name] = highlighter
return highlighter, nil
}

View File

@ -13,12 +13,18 @@ import (
"sort"
"github.com/blevesearch/bleve/analysis"
"github.com/blevesearch/bleve/search/highlight"
)
var stores = make(KVStoreRegistry, 0)
var byteArrayConverters = make(ByteArrayConverterRegistry, 0)
// highlight
var fragmentFormatters = make(FragmentFormatterRegistry, 0)
var fragmenters = make(FragmenterRegistry, 0)
var highlighters = make(HighlighterRegistry, 0)
// analysis
var charFilters = make(CharFilterRegistry, 0)
var tokenizers = make(TokenizerRegistry, 0)
@ -28,22 +34,28 @@ var analyzers = make(AnalyzerRegistry, 0)
var dateTimeParsers = make(DateTimeParserRegistry, 0)
type Cache struct {
CharFilters CharFilterCache
Tokenizers TokenizerCache
TokenMaps TokenMapCache
TokenFilters TokenFilterCache
Analyzers AnalyzerCache
DateTimeParsers DateTimeParserCache
CharFilters CharFilterCache
Tokenizers TokenizerCache
TokenMaps TokenMapCache
TokenFilters TokenFilterCache
Analyzers AnalyzerCache
DateTimeParsers DateTimeParserCache
FragmentFormatters FragmentFormatterCache
Fragmenters FragmenterCache
Highlighters HighlighterCache
}
func NewCache() *Cache {
return &Cache{
CharFilters: make(CharFilterCache, 0),
Tokenizers: make(TokenizerCache, 0),
TokenMaps: make(TokenMapCache, 0),
TokenFilters: make(TokenFilterCache, 0),
Analyzers: make(AnalyzerCache, 0),
DateTimeParsers: make(DateTimeParserCache, 0),
CharFilters: make(CharFilterCache, 0),
Tokenizers: make(TokenizerCache, 0),
TokenMaps: make(TokenMapCache, 0),
TokenFilters: make(TokenFilterCache, 0),
Analyzers: make(AnalyzerCache, 0),
DateTimeParsers: make(DateTimeParserCache, 0),
FragmentFormatters: make(FragmentFormatterCache, 0),
Fragmenters: make(FragmenterCache, 0),
Highlighters: make(HighlighterCache, 0),
}
}
@ -95,6 +107,30 @@ func (c *Cache) DefineDateTimeParser(name string, typ string, config map[string]
return c.DateTimeParsers.DefineDateTimeParser(name, typ, config, c)
}
func (c *Cache) FragmentFormatterNamed(name string) (highlight.FragmentFormatter, error) {
return c.FragmentFormatters.FragmentFormatterNamed(name, c)
}
func (c *Cache) DefineFragmentFormatter(name string, typ string, config map[string]interface{}) (highlight.FragmentFormatter, error) {
return c.FragmentFormatters.DefineFragmentFormatter(name, typ, config, c)
}
func (c *Cache) FragmenterNamed(name string) (highlight.Fragmenter, error) {
return c.Fragmenters.FragmenterNamed(name, c)
}
func (c *Cache) DefineFragmenter(name string, typ string, config map[string]interface{}) (highlight.Fragmenter, error) {
return c.Fragmenters.DefineFragmenter(name, typ, config, c)
}
func (c *Cache) HighlighterNamed(name string) (highlight.Highlighter, error) {
return c.Highlighters.HighlighterNamed(name, c)
}
func (c *Cache) DefineHighlighter(name string, typ string, config map[string]interface{}) (highlight.Highlighter, error) {
return c.Highlighters.DefineHighlighter(name, typ, config, c)
}
func PrintRegistry() {
sorted := make(sort.StringSlice, 0, len(charFilters))
for name, _ := range charFilters {
@ -183,4 +219,37 @@ func PrintRegistry() {
fmt.Printf("\t%s\n", name)
}
fmt.Println()
sorted = make(sort.StringSlice, 0, len(fragmentFormatters))
for name, _ := range fragmentFormatters {
sorted = append(sorted, name)
}
sorted.Sort()
fmt.Printf("Fragment Formatters:\n")
for _, name := range sorted {
fmt.Printf("\t%s\n", name)
}
fmt.Println()
sorted = make(sort.StringSlice, 0, len(fragmenters))
for name, _ := range fragmenters {
sorted = append(sorted, name)
}
sorted.Sort()
fmt.Printf("Fragmenters:\n")
for _, name := range sorted {
fmt.Printf("\t%s\n", name)
}
fmt.Println()
sorted = make(sort.StringSlice, 0, len(highlighters))
for name, _ := range highlighters {
sorted = append(sorted, name)
}
sorted.Sort()
fmt.Printf("Highlighters:\n")
for _, name := range sorted {
fmt.Printf("\t%s\n", name)
}
fmt.Println()
}

View File

@ -6,11 +6,13 @@
// 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
package collectors
import (
"container/list"
"time"
"github.com/blevesearch/bleve/search"
)
type TopScoreCollector struct {
@ -20,7 +22,7 @@ type TopScoreCollector struct {
took time.Duration
maxScore float64
total uint64
facetsBuilder *FacetsBuilder
facetsBuilder *search.FacetsBuilder
}
func NewTopScorerCollector(k int) *TopScoreCollector {
@ -51,7 +53,7 @@ func (tksc *TopScoreCollector) Took() time.Duration {
return tksc.took
}
func (tksc *TopScoreCollector) Collect(searcher Searcher) error {
func (tksc *TopScoreCollector) Collect(searcher search.Searcher) error {
startTime := time.Now()
next, err := searcher.Next()
for err == nil && next != nil {
@ -69,7 +71,7 @@ func (tksc *TopScoreCollector) Collect(searcher Searcher) error {
return nil
}
func (tksc *TopScoreCollector) collectSingle(dm *DocumentMatch) {
func (tksc *TopScoreCollector) collectSingle(dm *search.DocumentMatch) {
// increment total hits
tksc.total += 1
@ -79,7 +81,7 @@ func (tksc *TopScoreCollector) collectSingle(dm *DocumentMatch) {
}
for e := tksc.results.Front(); e != nil; e = e.Next() {
curr := e.Value.(*DocumentMatch)
curr := e.Value.(*search.DocumentMatch)
if dm.Score < curr.Score {
tksc.results.InsertBefore(dm, e)
@ -99,9 +101,9 @@ func (tksc *TopScoreCollector) collectSingle(dm *DocumentMatch) {
}
}
func (tksc *TopScoreCollector) Results() DocumentMatchCollection {
func (tksc *TopScoreCollector) Results() search.DocumentMatchCollection {
if tksc.results.Len()-tksc.skip > 0 {
rv := make(DocumentMatchCollection, tksc.results.Len()-tksc.skip)
rv := make(search.DocumentMatchCollection, tksc.results.Len()-tksc.skip)
i := 0
skipped := 0
for e := tksc.results.Back(); e != nil; e = e.Prev() {
@ -109,22 +111,22 @@ func (tksc *TopScoreCollector) Results() DocumentMatchCollection {
skipped++
continue
}
rv[i] = e.Value.(*DocumentMatch)
rv[i] = e.Value.(*search.DocumentMatch)
i++
}
return rv
}
return DocumentMatchCollection{}
return search.DocumentMatchCollection{}
}
func (tksc *TopScoreCollector) SetFacetsBuilder(facetsBuilder *FacetsBuilder) {
func (tksc *TopScoreCollector) SetFacetsBuilder(facetsBuilder *search.FacetsBuilder) {
tksc.facetsBuilder = facetsBuilder
}
func (tksc *TopScoreCollector) FacetResults() FacetResults {
func (tksc *TopScoreCollector) FacetResults() search.FacetResults {
if tksc.facetsBuilder != nil {
return tksc.facetsBuilder.Results()
} else {
return FacetResults{}
return search.FacetResults{}
}
}

View File

@ -6,10 +6,12 @@
// 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
package collectors
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestTop10Scores(t *testing.T) {
@ -18,60 +20,60 @@ func TestTop10Scores(t *testing.T) {
// the top-10 scores are > 10
// everything else is less than 10
searcher := &stubSearcher{
matches: DocumentMatchCollection{
&DocumentMatch{
matches: search.DocumentMatchCollection{
&search.DocumentMatch{
ID: "a",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "b",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "c",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "d",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "e",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "f",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "g",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "h",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "i",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "j",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "k",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "l",
Score: 99,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "m",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "n",
Score: 11,
},
@ -123,60 +125,60 @@ func TestTop10ScoresSkip10(t *testing.T) {
// the top-10 scores are > 10
// everything else is less than 10
searcher := &stubSearcher{
matches: DocumentMatchCollection{
&DocumentMatch{
matches: search.DocumentMatchCollection{
&search.DocumentMatch{
ID: "a",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "b",
Score: 9.5,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "c",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "d",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "e",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "f",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "g",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "h",
Score: 9,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "i",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "j",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "k",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "l",
Score: 99,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "m",
Score: 11,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "n",
Score: 11,
},

View File

@ -6,14 +6,18 @@
// 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
package collectors
import (
"github.com/blevesearch/bleve/search"
)
type stubSearcher struct {
index int
matches DocumentMatchCollection
matches search.DocumentMatchCollection
}
func (ss *stubSearcher) Next() (*DocumentMatch, error) {
func (ss *stubSearcher) Next() (*search.DocumentMatch, error) {
if ss.index < len(ss.matches) {
rv := ss.matches[ss.index]
ss.index++
@ -22,7 +26,7 @@ func (ss *stubSearcher) Next() (*DocumentMatch, error) {
return nil, nil
}
func (ss *stubSearcher) Advance(ID string) (*DocumentMatch, error) {
func (ss *stubSearcher) Advance(ID string) (*search.DocumentMatch, error) {
for ss.index < len(ss.matches) && ss.matches[ss.index].ID < ID {
ss.index++

View File

@ -6,7 +6,7 @@
// 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
package facets
import (
"container/list"
@ -14,6 +14,7 @@ import (
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/numeric_util"
"github.com/blevesearch/bleve/search"
)
type dateTimeRange struct {
@ -81,8 +82,8 @@ func (fb *DateTimeFacetBuilder) Update(ft index.FieldTerms) {
}
}
func (fb *DateTimeFacetBuilder) Result() FacetResult {
rv := FacetResult{
func (fb *DateTimeFacetBuilder) Result() search.FacetResult {
rv := search.FacetResult{
Field: fb.field,
Total: fb.total,
Missing: fb.missing,
@ -95,7 +96,7 @@ func (fb *DateTimeFacetBuilder) Result() FacetResult {
OUTER:
for term, count := range fb.termsCount {
dateRange := fb.ranges[term]
tf := &DateRangeFacet{
tf := &search.DateRangeFacet{
Name: term,
Count: count,
}
@ -109,7 +110,7 @@ OUTER:
}
for e := topN.Front(); e != nil; e = e.Next() {
curr := e.Value.(*DateRangeFacet)
curr := e.Value.(*search.DateRangeFacet)
if tf.Count < curr.Count {
topN.InsertBefore(tf, e)
@ -131,13 +132,13 @@ OUTER:
}
// we now have the list of the top N facets
rv.DateRanges = make([]*DateRangeFacet, topN.Len())
rv.DateRanges = make([]*search.DateRangeFacet, topN.Len())
i := 0
notOther := 0
for e := topN.Back(); e != nil; e = e.Prev() {
rv.DateRanges[i] = e.Value.(*DateRangeFacet)
rv.DateRanges[i] = e.Value.(*search.DateRangeFacet)
i++
notOther += e.Value.(*DateRangeFacet).Count
notOther += e.Value.(*search.DateRangeFacet).Count
}
rv.Other = fb.total - notOther

View File

@ -6,13 +6,14 @@
// 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
package facets
import (
"container/list"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/numeric_util"
"github.com/blevesearch/bleve/search"
)
type numericRange struct {
@ -80,8 +81,8 @@ func (fb *NumericFacetBuilder) Update(ft index.FieldTerms) {
}
}
func (fb *NumericFacetBuilder) Result() FacetResult {
rv := FacetResult{
func (fb *NumericFacetBuilder) Result() search.FacetResult {
rv := search.FacetResult{
Field: fb.field,
Total: fb.total,
Missing: fb.missing,
@ -94,7 +95,7 @@ func (fb *NumericFacetBuilder) Result() FacetResult {
OUTER:
for term, count := range fb.termsCount {
numericRange := fb.ranges[term]
tf := &NumericRangeFacet{
tf := &search.NumericRangeFacet{
Name: term,
Count: count,
Min: numericRange.min,
@ -102,7 +103,7 @@ OUTER:
}
for e := topN.Front(); e != nil; e = e.Next() {
curr := e.Value.(*NumericRangeFacet)
curr := e.Value.(*search.NumericRangeFacet)
if tf.Count < curr.Count {
topN.InsertBefore(tf, e)
@ -124,13 +125,13 @@ OUTER:
}
// we now have the list of the top N facets
rv.NumericRanges = make([]*NumericRangeFacet, topN.Len())
rv.NumericRanges = make([]*search.NumericRangeFacet, topN.Len())
i := 0
notOther := 0
for e := topN.Back(); e != nil; e = e.Prev() {
rv.NumericRanges[i] = e.Value.(*NumericRangeFacet)
rv.NumericRanges[i] = e.Value.(*search.NumericRangeFacet)
i++
notOther += e.Value.(*NumericRangeFacet).Count
notOther += e.Value.(*search.NumericRangeFacet).Count
}
rv.Other = fb.total - notOther

View File

@ -6,12 +6,13 @@
// 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
package facets
import (
"container/list"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
)
type TermsFacetBuilder struct {
@ -47,8 +48,8 @@ func (fb *TermsFacetBuilder) Update(ft index.FieldTerms) {
}
}
func (fb *TermsFacetBuilder) Result() FacetResult {
rv := FacetResult{
func (fb *TermsFacetBuilder) Result() search.FacetResult {
rv := search.FacetResult{
Field: fb.field,
Total: fb.total,
Missing: fb.missing,
@ -60,13 +61,13 @@ func (fb *TermsFacetBuilder) Result() FacetResult {
// walk entries and find top N
OUTER:
for term, count := range fb.termsCount {
tf := &TermFacet{
tf := &search.TermFacet{
Term: term,
Count: count,
}
for e := topN.Front(); e != nil; e = e.Next() {
curr := e.Value.(*TermFacet)
curr := e.Value.(*search.TermFacet)
if tf.Count < curr.Count {
topN.InsertBefore(tf, e)
@ -88,13 +89,13 @@ OUTER:
}
// we now have the list of the top N facets
rv.Terms = make([]*TermFacet, topN.Len())
rv.Terms = make([]*search.TermFacet, topN.Len())
i := 0
notOther := 0
for e := topN.Back(); e != nil; e = e.Prev() {
rv.Terms[i] = e.Value.(*TermFacet)
rv.Terms[i] = e.Value.(*search.TermFacet)
i++
notOther += e.Value.(*TermFacet).Count
notOther += e.Value.(*search.TermFacet).Count
}
rv.Other = fb.total - notOther

View File

@ -1,61 +0,0 @@
// 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 ()
const DEFAULT_HTML_HIGHLIGHT_BEFORE = "<b>"
const DEFAULT_HTML_HIGHLIGHT_AFTER = "</b>"
type HTMLFragmentFormatter struct {
before string
after string
}
func NewHTMLFragmentFormatter() *HTMLFragmentFormatter {
return &HTMLFragmentFormatter{
before: DEFAULT_HTML_HIGHLIGHT_BEFORE,
after: DEFAULT_HTML_HIGHLIGHT_AFTER,
}
}
func NewHTMLFragmentFormatterCustom(before, after string) *HTMLFragmentFormatter {
return &HTMLFragmentFormatter{
before: before,
after: after,
}
}
func (a *HTMLFragmentFormatter) Format(f *Fragment, tlm TermLocationMap) string {
orderedTermLocations := OrderTermLocations(tlm)
rv := ""
curr := f.start
for _, termLocation := range orderedTermLocations {
if termLocation.Start < curr {
continue
}
if termLocation.End > f.end {
break
}
// add the stuff before this location
rv += string(f.orig[curr:termLocation.Start])
// add the color
rv += a.before
// add the term itself
rv += string(f.orig[termLocation.Start:termLocation.End])
// reset the color
rv += a.after
// update current
curr = termLocation.End
}
// add any remaining text after the last token
rv += string(f.orig[curr:f.end])
return rv
}

View File

@ -6,9 +6,16 @@
// 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 ()
package ansi
import (
"github.com/blevesearch/bleve/registry"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight"
)
const Name = "ansi"
const DEFAULT_ANSI_HIGHLIGHT = bgYellow
@ -22,30 +29,30 @@ func NewANSIFragmentFormatter() *ANSIFragmentFormatter {
}
}
func (a *ANSIFragmentFormatter) Format(f *Fragment, tlm TermLocationMap) string {
orderedTermLocations := OrderTermLocations(tlm)
func (a *ANSIFragmentFormatter) Format(f *highlight.Fragment, tlm search.TermLocationMap) string {
orderedTermLocations := highlight.OrderTermLocations(tlm)
rv := ""
curr := f.start
curr := f.Start
for _, termLocation := range orderedTermLocations {
if termLocation.Start < curr {
continue
}
if termLocation.End > f.end {
if termLocation.End > f.End {
break
}
// add the stuff before this location
rv += string(f.orig[curr:termLocation.Start])
rv += string(f.Orig[curr:termLocation.Start])
// add the color
rv += a.color
// add the term itself
rv += string(f.orig[termLocation.Start:termLocation.End])
rv += string(f.Orig[termLocation.Start:termLocation.End])
// reset the color
rv += reset
// update current
curr = termLocation.End
}
// add any remaining text after the last token
rv += string(f.orig[curr:f.end])
rv += string(f.Orig[curr:f.End])
return rv
}
@ -77,3 +84,11 @@ const (
bgCyan = "\x1b[46m"
bgWhite = "\x1b[47m"
)
func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.FragmentFormatter, error) {
return NewANSIFragmentFormatter(), nil
}
func init() {
registry.RegisterFragmentFormatter(Name, Constructor)
}

View File

@ -0,0 +1,79 @@
// 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 html
import (
"github.com/blevesearch/bleve/registry"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight"
)
const Name = "html"
const defaultHtmlHighlightBefore = "<b>"
const defaultHtmlHighlightAfter = "</b>"
type HTMLFragmentFormatter struct {
before string
after string
}
func NewHTMLFragmentFormatter(before, after string) *HTMLFragmentFormatter {
return &HTMLFragmentFormatter{
before: before,
after: after,
}
}
func (a *HTMLFragmentFormatter) Format(f *highlight.Fragment, tlm search.TermLocationMap) string {
orderedTermLocations := highlight.OrderTermLocations(tlm)
rv := ""
curr := f.Start
for _, termLocation := range orderedTermLocations {
if termLocation.Start < curr {
continue
}
if termLocation.End > f.End {
break
}
// add the stuff before this location
rv += string(f.Orig[curr:termLocation.Start])
// add the color
rv += a.before
// add the term itself
rv += string(f.Orig[termLocation.Start:termLocation.End])
// reset the color
rv += a.after
// update current
curr = termLocation.End
}
// add any remaining text after the last token
rv += string(f.Orig[curr:f.End])
return rv
}
func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.FragmentFormatter, error) {
before := defaultHtmlHighlightBefore
beforeVal, ok := config["before"].(string)
if ok {
before = beforeVal
}
after := defaultHtmlHighlightAfter
afterVal, ok := config["after"].(string)
if ok {
after = afterVal
}
return NewHTMLFragmentFormatter(before, after), nil
}
func init() {
registry.RegisterFragmentFormatter(Name, Constructor)
}

View File

@ -6,27 +6,31 @@
// 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
package html
import (
"testing"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight"
)
func TestHTMLFragmentFormatterDefault(t *testing.T) {
func TestHTMLFragmentFormatter1(t *testing.T) {
tests := []struct {
fragment *Fragment
tlm TermLocationMap
fragment *highlight.Fragment
tlm search.TermLocationMap
output string
}{
{
fragment: &Fragment{
orig: []byte("the quick brown fox"),
start: 0,
end: 19,
fragment: &highlight.Fragment{
Orig: []byte("the quick brown fox"),
Start: 0,
End: 19,
},
tlm: TermLocationMap{
"quick": Locations{
&Location{
tlm: search.TermLocationMap{
"quick": search.Locations{
&search.Location{
Pos: 2,
Start: 4,
End: 9,
@ -37,7 +41,7 @@ func TestHTMLFragmentFormatterDefault(t *testing.T) {
},
}
emHtmlFormatter := NewHTMLFragmentFormatter()
emHtmlFormatter := NewHTMLFragmentFormatter("<b>", "</b>")
for _, test := range tests {
result := emHtmlFormatter.Format(test.fragment, test.tlm)
if result != test.output {
@ -46,21 +50,21 @@ func TestHTMLFragmentFormatterDefault(t *testing.T) {
}
}
func TestHTMLFragmentFormatterCustom(t *testing.T) {
func TestHTMLFragmentFormatter2(t *testing.T) {
tests := []struct {
fragment *Fragment
tlm TermLocationMap
fragment *highlight.Fragment
tlm search.TermLocationMap
output string
}{
{
fragment: &Fragment{
orig: []byte("the quick brown fox"),
start: 0,
end: 19,
fragment: &highlight.Fragment{
Orig: []byte("the quick brown fox"),
Start: 0,
End: 19,
},
tlm: TermLocationMap{
"quick": Locations{
&Location{
tlm: search.TermLocationMap{
"quick": search.Locations{
&search.Location{
Pos: 2,
Start: 4,
End: 9,
@ -71,7 +75,7 @@ func TestHTMLFragmentFormatterCustom(t *testing.T) {
},
}
emHtmlFormatter := NewHTMLFragmentFormatterCustom("<em>", "</em>")
emHtmlFormatter := NewHTMLFragmentFormatter("<em>", "</em>")
for _, test := range tests {
result := emHtmlFormatter.Format(test.fragment, test.tlm)
if result != test.output {

View File

@ -6,30 +6,30 @@
// 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 ()
package simple
const DEFAULT_FRAGMENT_SIZE = 200
import (
"github.com/blevesearch/bleve/registry"
"github.com/blevesearch/bleve/search/highlight"
)
const Name = "simple"
const defaultFragmentSize = 200
type SimpleFragmenter struct {
fragmentSize int
}
func NewSimpleFragmenter() *SimpleFragmenter {
return &SimpleFragmenter{
fragmentSize: DEFAULT_FRAGMENT_SIZE,
}
}
func NewSimpleFragmenterWithSize(fragmentSize int) *SimpleFragmenter {
func NewSimpleFragmenter(fragmentSize int) *SimpleFragmenter {
return &SimpleFragmenter{
fragmentSize: fragmentSize,
}
}
func (s *SimpleFragmenter) Fragment(orig []byte, ot termLocations) []*Fragment {
rv := make([]*Fragment, 0)
func (s *SimpleFragmenter) Fragment(orig []byte, ot highlight.TermLocations) []*highlight.Fragment {
rv := make([]*highlight.Fragment, 0)
maxbegin := 0
for currTermIndex, termLocation := range ot {
@ -65,7 +65,7 @@ func (s *SimpleFragmenter) Fragment(orig []byte, ot termLocations) []*Fragment {
}
offset := roomToMove / 2
rv = append(rv, &Fragment{orig: orig, start: start - offset, end: end - offset})
rv = append(rv, &highlight.Fragment{Orig: orig, Start: start - offset, End: end - offset})
// set maxbegin to the end of the current term location
// so that next one won't back up to include it
maxbegin = termLocation.End
@ -79,8 +79,21 @@ func (s *SimpleFragmenter) Fragment(orig []byte, ot termLocations) []*Fragment {
if end > len(orig) {
end = len(orig)
}
rv = append(rv, &Fragment{orig: orig, start: start, end: end})
rv = append(rv, &highlight.Fragment{Orig: orig, Start: start, End: end})
}
return rv
}
func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.Fragmenter, error) {
size := defaultFragmentSize
sizeVal, ok := config["size"].(float64)
if ok {
size = int(sizeVal)
}
return NewSimpleFragmenter(size), nil
}
func init() {
registry.RegisterFragmenter(Name, Constructor)
}

View File

@ -6,31 +6,34 @@
// 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
package simple
import (
"reflect"
"testing"
"github.com/blevesearch/bleve/search/highlight"
)
func TestSimpleFragmenter(t *testing.T) {
tests := []struct {
orig []byte
fragments []*Fragment
ot termLocations
fragments []*highlight.Fragment
ot highlight.TermLocations
}{
{
orig: []byte("this is a test"),
fragments: []*Fragment{
&Fragment{
orig: []byte("this is a test"),
start: 0,
end: 14,
fragments: []*highlight.Fragment{
&highlight.Fragment{
Orig: []byte("this is a test"),
Start: 0,
End: 14,
},
},
ot: termLocations{
&termLocation{
ot: highlight.TermLocations{
&highlight.TermLocation{
Term: "test",
Pos: 4,
Start: 10,
@ -40,15 +43,15 @@ func TestSimpleFragmenter(t *testing.T) {
},
{
orig: []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"),
fragments: []*Fragment{
&Fragment{
orig: []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"),
start: 0,
end: 100,
fragments: []*highlight.Fragment{
&highlight.Fragment{
Orig: []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"),
Start: 0,
End: 100,
},
},
ot: termLocations{
&termLocation{
ot: highlight.TermLocations{
&highlight.TermLocation{
Term: "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
Pos: 1,
Start: 0,
@ -58,114 +61,114 @@ func TestSimpleFragmenter(t *testing.T) {
},
{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
fragments: []*Fragment{
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 0,
end: 100,
fragments: []*highlight.Fragment{
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 0,
End: 100,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 10,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 10,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 20,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 20,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 30,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 30,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 40,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 40,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 50,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 50,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 60,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 60,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 70,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 70,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 80,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 80,
End: 101,
},
&Fragment{
orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
start: 90,
end: 101,
&highlight.Fragment{
Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"),
Start: 90,
End: 101,
},
},
ot: termLocations{
&termLocation{
ot: highlight.TermLocations{
&highlight.TermLocation{
Term: "0123456789",
Pos: 1,
Start: 0,
End: 10,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 2,
Start: 10,
End: 20,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 3,
Start: 20,
End: 30,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 4,
Start: 30,
End: 40,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 5,
Start: 40,
End: 50,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 6,
Start: 50,
End: 60,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 7,
Start: 60,
End: 70,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 8,
Start: 70,
End: 80,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 9,
Start: 80,
End: 90,
},
&termLocation{
&highlight.TermLocation{
Term: "0123456789",
Pos: 10,
Start: 90,
@ -175,7 +178,7 @@ func TestSimpleFragmenter(t *testing.T) {
},
}
fragmenter := NewSimpleFragmenterWithSize(100)
fragmenter := NewSimpleFragmenter(100)
for _, test := range tests {
fragments := fragmenter.Fragment(test.orig, test.ot)
if !reflect.DeepEqual(fragments, test.fragments) {
@ -191,31 +194,31 @@ func TestSimpleFragmenterWithSize(t *testing.T) {
tests := []struct {
orig []byte
fragments []*Fragment
ot termLocations
fragments []*highlight.Fragment
ot highlight.TermLocations
}{
{
orig: []byte("this is a test"),
fragments: []*Fragment{
&Fragment{
orig: []byte("this is a test"),
start: 0,
end: 5,
fragments: []*highlight.Fragment{
&highlight.Fragment{
Orig: []byte("this is a test"),
Start: 0,
End: 5,
},
&Fragment{
orig: []byte("this is a test"),
start: 9,
end: 14,
&highlight.Fragment{
Orig: []byte("this is a test"),
Start: 9,
End: 14,
},
},
ot: termLocations{
&termLocation{
ot: highlight.TermLocations{
&highlight.TermLocation{
Term: "this",
Pos: 1,
Start: 0,
End: 5,
},
&termLocation{
&highlight.TermLocation{
Term: "test",
Pos: 4,
Start: 10,
@ -225,7 +228,7 @@ func TestSimpleFragmenterWithSize(t *testing.T) {
},
}
fragmenter := NewSimpleFragmenterWithSize(5)
fragmenter := NewSimpleFragmenter(5)
for _, test := range tests {
fragments := fragmenter.Fragment(test.orig, test.ot)
if !reflect.DeepEqual(fragments, test.fragments) {

View File

@ -6,35 +6,37 @@
// 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
package highlight
import (
"github.com/blevesearch/bleve/document"
"github.com/blevesearch/bleve/search"
)
type Fragment struct {
orig []byte
start int
end int
score float64
index int // used by heap
Orig []byte
Start int
End int
Score float64
Index int // used by heap
}
func (f *Fragment) Overlaps(other *Fragment) bool {
if other.start >= f.start && other.start < f.end {
if other.Start >= f.Start && other.Start < f.End {
return true
} else if f.start >= other.start && f.start < other.end {
} else if f.Start >= other.Start && f.Start < other.End {
return true
}
return false
}
type Fragmenter interface {
Fragment([]byte, termLocations) []*Fragment
Fragment([]byte, TermLocations) []*Fragment
}
type FragmentFormatter interface {
Format(f *Fragment, tlm TermLocationMap) string
Format(f *Fragment, tlm search.TermLocationMap) string
}
type FragmentScorer interface {
@ -51,6 +53,6 @@ type Highlighter interface {
Separator() string
SetSeparator(string)
BestFragmentInField(*DocumentMatch, *document.Document, string) string
BestFragmentsInField(*DocumentMatch, *document.Document, string, int) []string
BestFragmentInField(*search.DocumentMatch, *document.Document, string) string
BestFragmentsInField(*search.DocumentMatch, *document.Document, string, int) []string
}

View File

@ -6,29 +6,33 @@
// 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 ()
package simple
import (
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight"
)
// SimpleFragmentScorer will score fragments by how many
// unique terms occur in the fragment with no regard for
// any boost values used in the original query
type SimpleFragmentScorer struct {
tlm TermLocationMap
tlm search.TermLocationMap
}
func NewSimpleFragmentScorer(tlm TermLocationMap) *SimpleFragmentScorer {
func NewSimpleFragmentScorer(tlm search.TermLocationMap) *SimpleFragmentScorer {
return &SimpleFragmentScorer{
tlm: tlm,
}
}
func (s *SimpleFragmentScorer) Score(f *Fragment) {
func (s *SimpleFragmentScorer) Score(f *highlight.Fragment) {
score := 0.0
OUTER:
for _, locations := range s.tlm {
for _, location := range locations {
if int(location.Start) >= f.start && int(location.End) <= f.end {
if int(location.Start) >= f.Start && int(location.End) <= f.End {
score += 1.0
// once we find a term in the fragment
// don't care about additional matches
@ -36,5 +40,5 @@ OUTER:
}
}
}
f.score = score
f.Score = score
}

View File

@ -6,28 +6,32 @@
// 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
package simple
import (
"testing"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight"
)
func TestSimpleFragmentScorer(t *testing.T) {
tests := []struct {
fragment *Fragment
tlm TermLocationMap
fragment *highlight.Fragment
tlm search.TermLocationMap
score float64
}{
{
fragment: &Fragment{
orig: []byte("cat in the hat"),
start: 0,
end: 14,
fragment: &highlight.Fragment{
Orig: []byte("cat in the hat"),
Start: 0,
End: 14,
},
tlm: TermLocationMap{
"cat": Locations{
&Location{
tlm: search.TermLocationMap{
"cat": search.Locations{
&search.Location{
Pos: 0,
Start: 0,
End: 3,
@ -37,21 +41,21 @@ func TestSimpleFragmentScorer(t *testing.T) {
score: 1,
},
{
fragment: &Fragment{
orig: []byte("cat in the hat"),
start: 0,
end: 14,
fragment: &highlight.Fragment{
Orig: []byte("cat in the hat"),
Start: 0,
End: 14,
},
tlm: TermLocationMap{
"cat": Locations{
&Location{
tlm: search.TermLocationMap{
"cat": search.Locations{
&search.Location{
Pos: 1,
Start: 0,
End: 3,
},
},
"hat": Locations{
&Location{
"hat": search.Locations{
&search.Location{
Pos: 4,
Start: 11,
End: 14,
@ -65,8 +69,8 @@ func TestSimpleFragmentScorer(t *testing.T) {
for _, test := range tests {
scorer := NewSimpleFragmentScorer(test.tlm)
scorer.Score(test.fragment)
if test.fragment.score != test.score {
t.Errorf("expected score %f, got %f", test.score, test.fragment.score)
if test.fragment.Score != test.score {
t.Errorf("expected score %f, got %f", test.score, test.fragment.Score)
}
}

View File

@ -6,43 +6,49 @@
// 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
package simple
import (
"container/heap"
"fmt"
"github.com/blevesearch/bleve/document"
"github.com/blevesearch/bleve/registry"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight"
)
const DEFAULT_SEPARATOR = "…"
const Name = "simple"
const defaultSeparator = "…"
type SimpleHighlighter struct {
fragmenter Fragmenter
formatter FragmentFormatter
fragmenter highlight.Fragmenter
formatter highlight.FragmentFormatter
sep string
}
func NewSimpleHighlighter() *SimpleHighlighter {
func NewSimpleHighlighter(fragmenter highlight.Fragmenter, formatter highlight.FragmentFormatter, separator string) *SimpleHighlighter {
return &SimpleHighlighter{
fragmenter: NewSimpleFragmenter(),
formatter: NewANSIFragmentFormatter(),
sep: DEFAULT_SEPARATOR,
fragmenter: fragmenter,
formatter: formatter,
sep: separator,
}
}
func (s *SimpleHighlighter) Fragmenter() Fragmenter {
func (s *SimpleHighlighter) Fragmenter() highlight.Fragmenter {
return s.fragmenter
}
func (s *SimpleHighlighter) SetFragmenter(f Fragmenter) {
func (s *SimpleHighlighter) SetFragmenter(f highlight.Fragmenter) {
s.fragmenter = f
}
func (s *SimpleHighlighter) FragmentFormatter() FragmentFormatter {
func (s *SimpleHighlighter) FragmentFormatter() highlight.FragmentFormatter {
return s.formatter
}
func (s *SimpleHighlighter) SetFragmentFormatter(f FragmentFormatter) {
func (s *SimpleHighlighter) SetFragmentFormatter(f highlight.FragmentFormatter) {
s.formatter = f
}
@ -54,7 +60,7 @@ func (s *SimpleHighlighter) SetSeparator(sep string) {
s.sep = sep
}
func (s *SimpleHighlighter) BestFragmentInField(dm *DocumentMatch, doc *document.Document, field string) string {
func (s *SimpleHighlighter) BestFragmentInField(dm *search.DocumentMatch, doc *document.Document, field string) string {
fragments := s.BestFragmentsInField(dm, doc, field, 1)
if len(fragments) > 0 {
return fragments[0]
@ -62,9 +68,9 @@ func (s *SimpleHighlighter) BestFragmentInField(dm *DocumentMatch, doc *document
return ""
}
func (s *SimpleHighlighter) BestFragmentsInField(dm *DocumentMatch, doc *document.Document, field string, num int) []string {
func (s *SimpleHighlighter) BestFragmentsInField(dm *search.DocumentMatch, doc *document.Document, field string, num int) []string {
tlm := dm.Locations[field]
orderedTermLocations := OrderTermLocations(tlm)
orderedTermLocations := highlight.OrderTermLocations(tlm)
scorer := NewSimpleFragmentScorer(dm.Locations[field])
// score the fragments and put them into a priority queue ordered by score
@ -85,7 +91,7 @@ func (s *SimpleHighlighter) BestFragmentsInField(dm *DocumentMatch, doc *documen
}
// now find the N best non-overlapping fragments
bestFragments := make([]*Fragment, 0)
bestFragments := make([]*highlight.Fragment, 0)
if len(fq) > 0 {
candidate := heap.Pop(&fq)
OUTER:
@ -93,7 +99,7 @@ func (s *SimpleHighlighter) BestFragmentsInField(dm *DocumentMatch, doc *documen
// see if this overlaps with any of the best already identified
if len(bestFragments) > 0 {
for _, frag := range bestFragments {
if candidate.(*Fragment).Overlaps(frag) {
if candidate.(*highlight.Fragment).Overlaps(frag) {
if len(fq) < 1 {
break OUTER
}
@ -101,9 +107,9 @@ func (s *SimpleHighlighter) BestFragmentsInField(dm *DocumentMatch, doc *documen
continue OUTER
}
}
bestFragments = append(bestFragments, candidate.(*Fragment))
bestFragments = append(bestFragments, candidate.(*highlight.Fragment))
} else {
bestFragments = append(bestFragments, candidate.(*Fragment))
bestFragments = append(bestFragments, candidate.(*highlight.Fragment))
}
if len(fq) < 1 {
@ -117,17 +123,17 @@ func (s *SimpleHighlighter) BestFragmentsInField(dm *DocumentMatch, doc *documen
formattedFragments := make([]string, len(bestFragments))
for i, fragment := range bestFragments {
formattedFragments[i] = ""
if fragment.start != 0 {
if fragment.Start != 0 {
formattedFragments[i] += s.sep
}
formattedFragments[i] += s.formatter.Format(fragment, dm.Locations[field])
if fragment.end != len(fragment.orig) {
if fragment.End != len(fragment.Orig) {
formattedFragments[i] += s.sep
}
}
if dm.Fragments == nil {
dm.Fragments = make(FieldFragmentMap, 0)
dm.Fragments = make(search.FieldFragmentMap, 0)
}
dm.Fragments[field] = formattedFragments
@ -135,25 +141,25 @@ func (s *SimpleHighlighter) BestFragmentsInField(dm *DocumentMatch, doc *documen
}
// A PriorityQueue implements heap.Interface and holds Items.
type FragmentQueue []*Fragment
type FragmentQueue []*highlight.Fragment
func (fq FragmentQueue) Len() int { return len(fq) }
func (fq FragmentQueue) Less(i, j int) bool {
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
return fq[i].score > fq[j].score
return fq[i].Score > fq[j].Score
}
func (fq FragmentQueue) Swap(i, j int) {
fq[i], fq[j] = fq[j], fq[i]
fq[i].index = i
fq[j].index = j
fq[i].Index = i
fq[j].Index = j
}
func (fq *FragmentQueue) Push(x interface{}) {
n := len(*fq)
item := x.(*Fragment)
item.index = n
item := x.(*highlight.Fragment)
item.Index = n
*fq = append(*fq, item)
}
@ -161,7 +167,39 @@ func (fq *FragmentQueue) Pop() interface{} {
old := *fq
n := len(old)
item := old[n-1]
item.index = -1 // for safety
item.Index = -1 // for safety
*fq = old[0 : n-1]
return item
}
func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.Highlighter, error) {
separator := defaultSeparator
separatorVal, ok := config["separator"].(string)
if ok {
separator = separatorVal
}
fragmenterName, ok := config["fragmenter"].(string)
if !ok {
return nil, fmt.Errorf("must specify fragmenter")
}
fragmenter, err := cache.FragmenterNamed(fragmenterName)
if err != nil {
return nil, fmt.Errorf("error building fragmenter: %v", err)
}
formatterName, ok := config["formatter"].(string)
if !ok {
return nil, fmt.Errorf("must specify formatter")
}
formatter, err := cache.FragmentFormatterNamed(formatterName)
if err != nil {
return nil, fmt.Errorf("error building fragment formatter: %v", err)
}
return NewSimpleHighlighter(fragmenter, formatter, separator), nil
}
func init() {
registry.RegisterHighlighter(Name, Constructor)
}

View File

@ -6,33 +6,43 @@
// 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
package simple
import (
"reflect"
"testing"
"github.com/blevesearch/bleve/document"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi"
sfrag "github.com/blevesearch/bleve/search/highlight/fragmenters/simple"
)
const (
reset = "\x1b[0m"
DEFAULT_ANSI_HIGHLIGHT = "\x1b[43m"
)
func TestSimpleHighlighter(t *testing.T) {
fragmenter := sfrag.NewSimpleFragmenter(100)
formatter := ansi.NewANSIFragmentFormatter()
highlighter := NewSimpleHighlighter(fragmenter, formatter, defaultSeparator)
highlighter := NewSimpleHighlighter()
docMatch := DocumentMatch{
docMatch := search.DocumentMatch{
ID: "a",
Score: 1.0,
Locations: FieldTermLocationMap{
"desc": TermLocationMap{
"quick": Locations{
&Location{
Locations: search.FieldTermLocationMap{
"desc": search.TermLocationMap{
"quick": search.Locations{
&search.Location{
Pos: 2,
Start: 4,
End: 9,
},
},
"fox": Locations{
&Location{
"fox": search.Locations{
&search.Location{
Pos: 4,
Start: 16,
End: 19,
@ -64,67 +74,67 @@ Fusce viverra eleifend iaculis. Maecenas tempor dictum cursus. Mauris faucibus,
Etiam vel augue vel nisl commodo suscipit et ac nisl. Quisque eros diam, porttitor et aliquet sed, vulputate in odio. Aenean feugiat est quis neque vehicula, eget vulputate nunc tempor. Donec quis nulla ut quam feugiat consectetur ut et justo. Nulla congue, metus auctor facilisis scelerisque, nunc risus vulputate urna, in blandit urna nibh et neque. Etiam quis tortor ut nulla dignissim dictum non sed ligula. Vivamus accumsan ligula eget ipsum ultrices, a tincidunt urna blandit. In hac habitasse platea dictumst.`)
doc := document.NewDocument("a").AddField(document.NewTextField("full", []uint64{}, fieldBytes))
docMatch := DocumentMatch{
docMatch := search.DocumentMatch{
ID: "a",
Score: 1.0,
Locations: FieldTermLocationMap{
"full": TermLocationMap{
"metus": Locations{
&Location{
Locations: search.FieldTermLocationMap{
"full": search.TermLocationMap{
"metus": search.Locations{
&search.Location{
Pos: 0,
Start: 883,
End: 888,
},
&Location{
&search.Location{
Pos: 0,
Start: 915,
End: 920,
},
&Location{
&search.Location{
Pos: 0,
Start: 2492,
End: 2497,
},
&Location{
&search.Location{
Pos: 0,
Start: 2822,
End: 2827,
},
&Location{
&search.Location{
Pos: 0,
Start: 3417,
End: 3422,
},
},
"interdum": Locations{
&Location{
"interdum": search.Locations{
&search.Location{
Pos: 0,
Start: 1891,
End: 1899,
},
&Location{
&search.Location{
Pos: 0,
Start: 2813,
End: 2821,
},
},
"venenatis": Locations{
&Location{
"venenatis": search.Locations{
&search.Location{
Pos: 0,
Start: 954,
End: 963,
},
&Location{
&search.Location{
Pos: 0,
Start: 1252,
End: 1261,
},
&Location{
&search.Location{
Pos: 0,
Start: 1795,
End: 1804,
},
&Location{
&search.Location{
Pos: 0,
Start: 2803,
End: 2812,
@ -142,8 +152,9 @@ Etiam vel augue vel nisl commodo suscipit et ac nisl. Quisque eros diam, porttit
"… accumsan. Vivamus eros felis, rhoncus vel " + DEFAULT_ANSI_HIGHLIGHT + "interdum" + reset + " bibendum, imperdiet nec diam. Etiam sed eros sed…",
}
highlighter := NewSimpleHighlighter()
highlighter.SetFragmenter(NewSimpleFragmenterWithSize(100))
fragmenter := sfrag.NewSimpleFragmenter(100)
formatter := ansi.NewANSIFragmentFormatter()
highlighter := NewSimpleHighlighter(fragmenter, formatter, defaultSeparator)
fragments := highlighter.BestFragmentsInField(&docMatch, doc, "full", 5)
if !reflect.DeepEqual(fragments, expectedFragments) {

View File

@ -6,30 +6,33 @@
// 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
package highlight
import (
"sort"
"github.com/blevesearch/bleve/search"
)
type termLocation struct {
type TermLocation struct {
Term string
Pos int
Start int
End int
}
type termLocations []*termLocation
type TermLocations []*TermLocation
func (t termLocations) Len() int { return len(t) }
func (t termLocations) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t termLocations) Less(i, j int) bool { return t[i].Start < t[j].Start }
func (t TermLocations) Len() int { return len(t) }
func (t TermLocations) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t TermLocations) Less(i, j int) bool { return t[i].Start < t[j].Start }
func OrderTermLocations(tlm TermLocationMap) termLocations {
rv := make(termLocations, 0)
func OrderTermLocations(tlm search.TermLocationMap) TermLocations {
rv := make(TermLocations, 0)
for term, locations := range tlm {
for _, location := range locations {
tl := termLocation{
tl := TermLocation{
Term: term,
Pos: int(location.Pos),
Start: int(location.Start),

View File

@ -6,9 +6,11 @@
// 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
package scorers
import ()
import (
"github.com/blevesearch/bleve/search"
)
type ConjunctionQueryScorer struct {
explain bool
@ -20,18 +22,18 @@ func NewConjunctionQueryScorer(explain bool) *ConjunctionQueryScorer {
}
}
func (s *ConjunctionQueryScorer) Score(constituents []*DocumentMatch) *DocumentMatch {
rv := DocumentMatch{
func (s *ConjunctionQueryScorer) Score(constituents []*search.DocumentMatch) *search.DocumentMatch {
rv := search.DocumentMatch{
ID: constituents[0].ID,
}
var sum float64
var childrenExplanations []*Explanation
var childrenExplanations []*search.Explanation
if s.explain {
childrenExplanations = make([]*Explanation, len(constituents))
childrenExplanations = make([]*search.Explanation, len(constituents))
}
locations := []FieldTermLocationMap{}
locations := []search.FieldTermLocationMap{}
for i, docMatch := range constituents {
sum += docMatch.Score
if s.explain {
@ -43,13 +45,13 @@ func (s *ConjunctionQueryScorer) Score(constituents []*DocumentMatch) *DocumentM
}
rv.Score = sum
if s.explain {
rv.Expl = &Explanation{Value: sum, Message: "sum of:", Children: childrenExplanations}
rv.Expl = &search.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)
rv.Locations = search.MergeLocations(locations)
}
return &rv

View File

@ -6,10 +6,12 @@
// 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
package scorers
import (
"fmt"
"github.com/blevesearch/bleve/search"
)
type ConstantScorer struct {
@ -18,7 +20,7 @@ type ConstantScorer struct {
explain bool
queryNorm float64
queryWeight float64
queryWeightExplanation *Explanation
queryWeightExplanation *search.Explanation
}
func NewConstantScorer(constant float64, boost float64, explain bool) *ConstantScorer {
@ -44,16 +46,16 @@ func (s *ConstantScorer) SetQueryNorm(qnorm float64) {
s.queryWeight = s.boost * s.queryNorm
if s.explain {
childrenExplanations := make([]*Explanation, 2)
childrenExplanations[0] = &Explanation{
childrenExplanations := make([]*search.Explanation, 2)
childrenExplanations[0] = &search.Explanation{
Value: s.boost,
Message: "boost",
}
childrenExplanations[1] = &Explanation{
childrenExplanations[1] = &search.Explanation{
Value: s.queryNorm,
Message: "queryNorm",
}
s.queryWeightExplanation = &Explanation{
s.queryWeightExplanation = &search.Explanation{
Value: s.queryWeight,
Message: fmt.Sprintf("ConstantScore()^%f, product of:", s.boost),
Children: childrenExplanations,
@ -61,13 +63,13 @@ func (s *ConstantScorer) SetQueryNorm(qnorm float64) {
}
}
func (s *ConstantScorer) Score(id string) *DocumentMatch {
var scoreExplanation *Explanation
func (s *ConstantScorer) Score(id string) *search.DocumentMatch {
var scoreExplanation *search.Explanation
score := s.constant
if s.explain {
scoreExplanation = &Explanation{
scoreExplanation = &search.Explanation{
Value: score,
Message: fmt.Sprintf("ConstantScore()"),
}
@ -77,10 +79,10 @@ func (s *ConstantScorer) Score(id string) *DocumentMatch {
if s.queryWeight != 1.0 {
score = score * s.queryWeight
if s.explain {
childExplanations := make([]*Explanation, 2)
childExplanations := make([]*search.Explanation, 2)
childExplanations[0] = s.queryWeightExplanation
childExplanations[1] = scoreExplanation
scoreExplanation = &Explanation{
scoreExplanation = &search.Explanation{
Value: score,
Message: fmt.Sprintf("weight(^%f), product of:", s.boost),
Children: childExplanations,
@ -88,7 +90,7 @@ func (s *ConstantScorer) Score(id string) *DocumentMatch {
}
}
rv := DocumentMatch{
rv := search.DocumentMatch{
ID: id,
Score: score,
}

View File

@ -6,10 +6,12 @@
// 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
package scorers
import (
"fmt"
"github.com/blevesearch/bleve/search"
)
type DisjunctionQueryScorer struct {
@ -22,18 +24,18 @@ func NewDisjunctionQueryScorer(explain bool) *DisjunctionQueryScorer {
}
}
func (s *DisjunctionQueryScorer) Score(constituents []*DocumentMatch, countMatch, countTotal int) *DocumentMatch {
rv := DocumentMatch{
func (s *DisjunctionQueryScorer) Score(constituents []*search.DocumentMatch, countMatch, countTotal int) *search.DocumentMatch {
rv := search.DocumentMatch{
ID: constituents[0].ID,
}
var sum float64
var childrenExplanations []*Explanation
var childrenExplanations []*search.Explanation
if s.explain {
childrenExplanations = make([]*Explanation, len(constituents))
childrenExplanations = make([]*search.Explanation, len(constituents))
}
locations := []FieldTermLocationMap{}
locations := []search.FieldTermLocationMap{}
for i, docMatch := range constituents {
sum += docMatch.Score
if s.explain {
@ -44,24 +46,24 @@ func (s *DisjunctionQueryScorer) Score(constituents []*DocumentMatch, countMatch
}
}
var rawExpl *Explanation
var rawExpl *search.Explanation
if s.explain {
rawExpl = &Explanation{Value: sum, Message: "sum of:", Children: childrenExplanations}
rawExpl = &search.Explanation{Value: sum, Message: "sum of:", Children: childrenExplanations}
}
coord := float64(countMatch) / float64(countTotal)
rv.Score = sum * coord
if s.explain {
ce := make([]*Explanation, 2)
ce := make([]*search.Explanation, 2)
ce[0] = rawExpl
ce[1] = &Explanation{Value: coord, Message: fmt.Sprintf("coord(%d/%d)", countMatch, countTotal)}
rv.Expl = &Explanation{Value: rv.Score, Message: "product of:", Children: ce}
ce[1] = &search.Explanation{Value: coord, Message: fmt.Sprintf("coord(%d/%d)", countMatch, countTotal)}
rv.Expl = &search.Explanation{Value: rv.Score, Message: "product of:", Children: ce}
}
if len(locations) == 1 {
rv.Locations = locations[0]
} else if len(locations) > 1 {
rv.Locations = mergeLocations(locations)
rv.Locations = search.MergeLocations(locations)
}
return &rv

View File

@ -6,13 +6,14 @@
// 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
package scorers
import (
"fmt"
"math"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
)
const MAX_SCORE_CACHE = 64
@ -25,10 +26,10 @@ type TermQueryScorer struct {
docTotal uint64
idf float64
explain bool
idfExplanation *Explanation
idfExplanation *search.Explanation
queryNorm float64
queryWeight float64
queryWeightExplanation *Explanation
queryWeightExplanation *search.Explanation
}
func NewTermQueryScorer(queryTerm string, queryField string, queryBoost float64, docTotal, docTerm uint64, explain bool) *TermQueryScorer {
@ -44,7 +45,7 @@ func NewTermQueryScorer(queryTerm string, queryField string, queryBoost float64,
}
if explain {
rv.idfExplanation = &Explanation{
rv.idfExplanation = &search.Explanation{
Value: rv.idf,
Message: fmt.Sprintf("idf(docFreq=%d, maxDocs=%d)", docTerm, docTotal),
}
@ -65,17 +66,17 @@ func (s *TermQueryScorer) SetQueryNorm(qnorm float64) {
s.queryWeight = s.queryBoost * s.idf * s.queryNorm
if s.explain {
childrenExplanations := make([]*Explanation, 3)
childrenExplanations[0] = &Explanation{
childrenExplanations := make([]*search.Explanation, 3)
childrenExplanations[0] = &search.Explanation{
Value: s.queryBoost,
Message: "boost",
}
childrenExplanations[1] = s.idfExplanation
childrenExplanations[2] = &Explanation{
childrenExplanations[2] = &search.Explanation{
Value: s.queryNorm,
Message: "queryNorm",
}
s.queryWeightExplanation = &Explanation{
s.queryWeightExplanation = &search.Explanation{
Value: s.queryWeight,
Message: fmt.Sprintf("queryWeight(%s:%s^%f), product of:", s.queryField, string(s.queryTerm), s.queryBoost),
Children: childrenExplanations,
@ -83,8 +84,8 @@ func (s *TermQueryScorer) SetQueryNorm(qnorm float64) {
}
}
func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *DocumentMatch {
var scoreExplanation *Explanation
func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *search.DocumentMatch {
var scoreExplanation *search.Explanation
// need to compute score
var tf float64
@ -96,17 +97,17 @@ func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *DocumentMatch {
score := tf * termMatch.Norm * s.idf
if s.explain {
childrenExplanations := make([]*Explanation, 3)
childrenExplanations[0] = &Explanation{
childrenExplanations := make([]*search.Explanation, 3)
childrenExplanations[0] = &search.Explanation{
Value: tf,
Message: fmt.Sprintf("tf(termFreq(%s:%s)=%d", s.queryField, string(s.queryTerm), termMatch.Freq),
}
childrenExplanations[1] = &Explanation{
childrenExplanations[1] = &search.Explanation{
Value: termMatch.Norm,
Message: fmt.Sprintf("fieldNorm(field=%s, doc=%s)", s.queryField, termMatch.ID),
}
childrenExplanations[2] = s.idfExplanation
scoreExplanation = &Explanation{
scoreExplanation = &search.Explanation{
Value: score,
Message: fmt.Sprintf("fieldWeight(%s:%s in %s), product of:", s.queryField, string(s.queryTerm), termMatch.ID),
Children: childrenExplanations,
@ -117,10 +118,10 @@ func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *DocumentMatch {
if s.queryWeight != 1.0 {
score = score * s.queryWeight
if s.explain {
childExplanations := make([]*Explanation, 2)
childExplanations := make([]*search.Explanation, 2)
childExplanations[0] = s.queryWeightExplanation
childExplanations[1] = scoreExplanation
scoreExplanation = &Explanation{
scoreExplanation = &search.Explanation{
Value: score,
Message: fmt.Sprintf("weight(%s:%s^%f in %s), product of:", s.queryField, string(s.queryTerm), s.queryBoost, termMatch.ID),
Children: childExplanations,
@ -128,7 +129,7 @@ func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *DocumentMatch {
}
}
rv := DocumentMatch{
rv := search.DocumentMatch{
ID: termMatch.ID,
Score: score,
}
@ -138,14 +139,14 @@ func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *DocumentMatch {
if termMatch.Vectors != nil && len(termMatch.Vectors) > 0 {
rv.Locations = make(FieldTermLocationMap)
rv.Locations = make(search.FieldTermLocationMap)
for _, v := range termMatch.Vectors {
tlm := rv.Locations[v.Field]
if tlm == nil {
tlm = make(TermLocationMap)
tlm = make(search.TermLocationMap)
}
loc := Location{
loc := search.Location{
Pos: float64(v.Pos),
Start: float64(v.Start),
End: float64(v.End),
@ -153,7 +154,7 @@ func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *DocumentMatch {
locations := tlm[s.queryTerm]
if locations == nil {
locations = make(Locations, 1)
locations = make(search.Locations, 1)
locations[0] = &loc
} else {
locations = append(locations, &loc)

View File

@ -6,7 +6,7 @@
// 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
package scorers
import (
"math"
@ -14,6 +14,7 @@ import (
"testing"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
)
func TestTermScorer(t *testing.T) {
@ -28,7 +29,7 @@ func TestTermScorer(t *testing.T) {
tests := []struct {
termMatch *index.TermFieldDoc
result *DocumentMatch
result *search.DocumentMatch
}{
// test some simple math
{
@ -45,31 +46,31 @@ func TestTermScorer(t *testing.T) {
},
},
},
result: &DocumentMatch{
result: &search.DocumentMatch{
ID: "one",
Score: math.Sqrt(1.0) * idf,
Expl: &Explanation{
Expl: &search.Explanation{
Value: math.Sqrt(1.0) * idf,
Message: "fieldWeight(desc:beer in one), product of:",
Children: []*Explanation{
&Explanation{
Children: []*search.Explanation{
&search.Explanation{
Value: 1,
Message: "tf(termFreq(desc:beer)=1",
},
&Explanation{
&search.Explanation{
Value: 1,
Message: "fieldNorm(field=desc, doc=one)",
},
&Explanation{
&search.Explanation{
Value: idf,
Message: "idf(docFreq=9, maxDocs=100)",
},
},
},
Locations: FieldTermLocationMap{
"desc": TermLocationMap{
"beer": Locations{
&Location{
Locations: search.FieldTermLocationMap{
"desc": search.TermLocationMap{
"beer": search.Locations{
&search.Location{
Pos: 1,
Start: 0,
End: 4,
@ -86,22 +87,22 @@ func TestTermScorer(t *testing.T) {
Freq: 1,
Norm: 1.0,
},
result: &DocumentMatch{
result: &search.DocumentMatch{
ID: "one",
Score: math.Sqrt(1.0) * idf,
Expl: &Explanation{
Expl: &search.Explanation{
Value: math.Sqrt(1.0) * idf,
Message: "fieldWeight(desc:beer in one), product of:",
Children: []*Explanation{
&Explanation{
Children: []*search.Explanation{
&search.Explanation{
Value: 1,
Message: "tf(termFreq(desc:beer)=1",
},
&Explanation{
&search.Explanation{
Value: 1,
Message: "fieldNorm(field=desc, doc=one)",
},
&Explanation{
&search.Explanation{
Value: idf,
Message: "idf(docFreq=9, maxDocs=100)",
},
@ -116,22 +117,22 @@ func TestTermScorer(t *testing.T) {
Freq: 65,
Norm: 1.0,
},
result: &DocumentMatch{
result: &search.DocumentMatch{
ID: "one",
Score: math.Sqrt(65) * idf,
Expl: &Explanation{
Expl: &search.Explanation{
Value: math.Sqrt(65) * idf,
Message: "fieldWeight(desc:beer in one), product of:",
Children: []*Explanation{
&Explanation{
Children: []*search.Explanation{
&search.Explanation{
Value: math.Sqrt(65),
Message: "tf(termFreq(desc:beer)=65",
},
&Explanation{
&search.Explanation{
Value: 1,
Message: "fieldNorm(field=desc, doc=one)",
},
&Explanation{
&search.Explanation{
Value: idf,
Message: "idf(docFreq=9, maxDocs=100)",
},
@ -171,7 +172,7 @@ func TestTermScorerWithQueryNorm(t *testing.T) {
tests := []struct {
termMatch *index.TermFieldDoc
result *DocumentMatch
result *search.DocumentMatch
}{
{
termMatch: &index.TermFieldDoc{
@ -179,44 +180,44 @@ func TestTermScorerWithQueryNorm(t *testing.T) {
Freq: 1,
Norm: 1.0,
},
result: &DocumentMatch{
result: &search.DocumentMatch{
ID: "one",
Score: math.Sqrt(1.0) * idf * 3.0 * idf * 2.0,
Expl: &Explanation{
Expl: &search.Explanation{
Value: math.Sqrt(1.0) * idf * 3.0 * idf * 2.0,
Message: "weight(desc:beer^3.000000 in one), product of:",
Children: []*Explanation{
&Explanation{
Children: []*search.Explanation{
&search.Explanation{
Value: 2.0 * idf * 3.0,
Message: "queryWeight(desc:beer^3.000000), product of:",
Children: []*Explanation{
&Explanation{
Children: []*search.Explanation{
&search.Explanation{
Value: 3,
Message: "boost",
},
&Explanation{
&search.Explanation{
Value: idf,
Message: "idf(docFreq=9, maxDocs=100)",
},
&Explanation{
&search.Explanation{
Value: 2,
Message: "queryNorm",
},
},
},
&Explanation{
&search.Explanation{
Value: math.Sqrt(1.0) * idf,
Message: "fieldWeight(desc:beer in one), product of:",
Children: []*Explanation{
&Explanation{
Children: []*search.Explanation{
&search.Explanation{
Value: 1,
Message: "tf(termFreq(desc:beer)=1",
},
&Explanation{
&search.Explanation{
Value: 1,
Message: "fieldNorm(field=desc, doc=one)",
},
&Explanation{
&search.Explanation{
Value: idf,
Message: "idf(docFreq=9, maxDocs=100)",
},

View File

@ -6,7 +6,7 @@
// 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
package scorers
import (
"math"

View File

@ -6,7 +6,7 @@
// 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
package searchers
import (
"math"

View File

@ -6,9 +6,13 @@
// 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
package searchers
type OrderedSearcherList []Searcher
import (
"github.com/blevesearch/bleve/search"
)
type OrderedSearcherList []search.Searcher
// sort.Interface

View File

@ -6,37 +6,39 @@
// 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
package searchers
import (
"math"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/scorers"
)
type BooleanSearcher struct {
initialized bool
index index.Index
mustSearcher Searcher
shouldSearcher Searcher
mustNotSearcher Searcher
mustSearcher search.Searcher
shouldSearcher search.Searcher
mustNotSearcher search.Searcher
queryNorm float64
currMust *DocumentMatch
currShould *DocumentMatch
currMustNot *DocumentMatch
currMust *search.DocumentMatch
currShould *search.DocumentMatch
currMustNot *search.DocumentMatch
currentId string
min uint64
scorer *ConjunctionQueryScorer
scorer *scorers.ConjunctionQueryScorer
}
func NewBooleanSearcher(index index.Index, mustSearcher Searcher, shouldSearcher Searcher, mustNotSearcher Searcher, explain bool) (*BooleanSearcher, error) {
func NewBooleanSearcher(index index.Index, mustSearcher search.Searcher, shouldSearcher search.Searcher, mustNotSearcher search.Searcher, explain bool) (*BooleanSearcher, error) {
// build our searcher
rv := BooleanSearcher{
index: index,
mustSearcher: mustSearcher,
shouldSearcher: shouldSearcher,
mustNotSearcher: mustNotSearcher,
scorer: NewConjunctionQueryScorer(explain),
scorer: scorers.NewConjunctionQueryScorer(explain),
}
rv.computeQueryNorm()
return &rv, nil
@ -145,7 +147,7 @@ func (s *BooleanSearcher) SetQueryNorm(qnorm float64) {
}
}
func (s *BooleanSearcher) Next() (*DocumentMatch, error) {
func (s *BooleanSearcher) Next() (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
@ -155,7 +157,7 @@ func (s *BooleanSearcher) Next() (*DocumentMatch, error) {
}
var err error
var rv *DocumentMatch
var rv *search.DocumentMatch
for s.currentId != "" {
if s.currMustNot != nil && s.currMustNot.ID < s.currentId {
@ -183,7 +185,7 @@ func (s *BooleanSearcher) Next() (*DocumentMatch, error) {
}
if s.currShould != nil && s.currShould.ID == s.currentId {
// score bonus matches should
cons := []*DocumentMatch{}
cons := []*search.DocumentMatch{}
if s.currMust != nil {
cons = append(cons, s.currMust)
}
@ -193,13 +195,13 @@ func (s *BooleanSearcher) Next() (*DocumentMatch, error) {
break
} else if s.shouldSearcher.Min() == 0 {
// match is OK anyway
rv = s.scorer.Score([]*DocumentMatch{s.currMust})
rv = s.scorer.Score([]*search.DocumentMatch{s.currMust})
s.advanceNextMust()
break
}
} else if s.currShould != nil && s.currShould.ID == s.currentId {
// score bonus matches should
cons := []*DocumentMatch{}
cons := []*search.DocumentMatch{}
if s.currMust != nil {
cons = append(cons, s.currMust)
}
@ -209,7 +211,7 @@ func (s *BooleanSearcher) Next() (*DocumentMatch, error) {
break
} else if s.shouldSearcher == nil || s.shouldSearcher.Min() == 0 {
// match is OK anyway
rv = s.scorer.Score([]*DocumentMatch{s.currMust})
rv = s.scorer.Score([]*search.DocumentMatch{s.currMust})
s.advanceNextMust()
break
}
@ -219,7 +221,7 @@ func (s *BooleanSearcher) Next() (*DocumentMatch, error) {
return rv, nil
}
func (s *BooleanSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *BooleanSearcher) Advance(ID string) (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestBooleanSearch(t *testing.T) {
@ -19,7 +21,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher}, true)
mustSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher}, true)
if err != nil {
t.Fatal(err)
}
@ -31,7 +33,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
shouldSearcher, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher, dustinTermSearcher}, 0, true)
shouldSearcher, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -39,7 +41,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustNotSearcher, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{steveTermSearcher}, 0, true)
mustNotSearcher, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{steveTermSearcher}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -57,7 +59,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
shouldSearcher2, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, true)
shouldSearcher2, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -65,7 +67,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustNotSearcher2, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{steveTermSearcher2}, 0, true)
mustNotSearcher2, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{steveTermSearcher2}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -79,7 +81,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustNotSearcher3, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{steveTermSearcher3}, 0, true)
mustNotSearcher3, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{steveTermSearcher3}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -93,7 +95,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustSearcher4, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher4}, true)
mustSearcher4, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher4}, true)
if err != nil {
t.Fatal(err)
}
@ -101,7 +103,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustNotSearcher4, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{steveTermSearcher4}, 0, true)
mustNotSearcher4, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{steveTermSearcher4}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -115,7 +117,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustSearcher5, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher5}, true)
mustSearcher5, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher5}, true)
if err != nil {
t.Fatal(err)
}
@ -127,7 +129,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustNotSearcher5, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{steveTermSearcher5, martyTermSearcher5}, 0, true)
mustNotSearcher5, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{steveTermSearcher5, martyTermSearcher5}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -141,7 +143,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustSearcher6, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher6}, true)
mustSearcher6, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher6}, true)
if err != nil {
t.Fatal(err)
}
@ -153,7 +155,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
shouldSearcher6, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher6, dustinTermSearcher6}, 2, true)
shouldSearcher6, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher6, dustinTermSearcher6}, 2, true)
if err != nil {
t.Fatal(err)
}
@ -167,7 +169,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustSearcher7, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher7}, true)
mustSearcher7, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher7}, true)
if err != nil {
t.Fatal(err)
}
@ -179,14 +181,14 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
conjunctionSearcher7, err := NewConjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher7, booleanSearcher7}, true)
conjunctionSearcher7, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher7, booleanSearcher7}, true)
// test 7
beerTermSearcher8, err := NewTermSearcher(twoDocIndex, "beer", "desc", 1.0, true)
if err != nil {
t.Fatal(err)
}
mustSearcher8, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher8}, true)
mustSearcher8, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher8}, true)
if err != nil {
t.Fatal(err)
}
@ -198,7 +200,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
shouldSearcher8, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher8, dustinTermSearcher8}, 0, true)
shouldSearcher8, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher8, dustinTermSearcher8}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -206,7 +208,7 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustNotSearcher8, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{steveTermSearcher8}, 0, true)
mustNotSearcher8, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{steveTermSearcher8}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -218,27 +220,27 @@ func TestBooleanSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
conjunctionSearcher8, err := NewConjunctionSearcher(twoDocIndex, []Searcher{booleanSearcher8, dustinTermSearcher8a}, true)
conjunctionSearcher8, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{booleanSearcher8, dustinTermSearcher8a}, true)
if err != nil {
t.Fatal(err)
}
tests := []struct {
searcher Searcher
results []*DocumentMatch
searcher search.Searcher
results []*search.DocumentMatch
}{
{
searcher: booleanSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 0.9818005051949021,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 0.808709699395535,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "4",
Score: 0.34618161159873423,
},
@ -246,12 +248,12 @@ func TestBooleanSearch(t *testing.T) {
},
{
searcher: booleanSearcher2,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 0.6775110856165737,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 0.6775110856165737,
},
@ -260,20 +262,20 @@ func TestBooleanSearch(t *testing.T) {
// no MUST or SHOULD clauses yields no results
{
searcher: booleanSearcher3,
results: []*DocumentMatch{},
results: []*search.DocumentMatch{},
},
{
searcher: booleanSearcher4,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 0.5,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "4",
Score: 1.0,
},
@ -281,12 +283,12 @@ func TestBooleanSearch(t *testing.T) {
},
{
searcher: booleanSearcher5,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 0.5,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "4",
Score: 1.0,
},
@ -294,13 +296,13 @@ func TestBooleanSearch(t *testing.T) {
},
{
searcher: booleanSearcher6,
results: []*DocumentMatch{},
results: []*search.DocumentMatch{},
},
// test a conjunction query with a nested boolean
{
searcher: conjunctionSearcher7,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 2.0097428702814377,
},
@ -308,8 +310,8 @@ func TestBooleanSearch(t *testing.T) {
},
{
searcher: conjunctionSearcher8,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 2.0681575785068107,
},

View File

@ -6,13 +6,15 @@
// 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
package searchers
import (
"math"
"sort"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/scorers"
)
type ConjunctionSearcher struct {
@ -21,12 +23,12 @@ type ConjunctionSearcher struct {
searchers OrderedSearcherList
explain bool
queryNorm float64
currs []*DocumentMatch
currs []*search.DocumentMatch
currentId string
scorer *ConjunctionQueryScorer
scorer *scorers.ConjunctionQueryScorer
}
func NewConjunctionSearcher(index index.Index, qsearchers []Searcher, explain bool) (*ConjunctionSearcher, error) {
func NewConjunctionSearcher(index index.Index, qsearchers []search.Searcher, explain bool) (*ConjunctionSearcher, error) {
// build the downstream searchres
searchers := make(OrderedSearcherList, len(qsearchers))
for i, searcher := range qsearchers {
@ -39,8 +41,8 @@ func NewConjunctionSearcher(index index.Index, qsearchers []Searcher, explain bo
index: index,
explain: explain,
searchers: searchers,
currs: make([]*DocumentMatch, len(searchers)),
scorer: NewConjunctionQueryScorer(explain),
currs: make([]*search.DocumentMatch, len(searchers)),
scorer: scorers.NewConjunctionQueryScorer(explain),
}
rv.computeQueryNorm()
return &rv, nil
@ -96,14 +98,14 @@ func (s *ConjunctionSearcher) SetQueryNorm(qnorm float64) {
}
}
func (s *ConjunctionSearcher) Next() (*DocumentMatch, error) {
func (s *ConjunctionSearcher) Next() (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
if err != nil {
return nil, err
}
}
var rv *DocumentMatch
var rv *search.DocumentMatch
var err error
OUTER:
for s.currentId != "" {
@ -148,7 +150,7 @@ OUTER:
return rv, nil
}
func (s *ConjunctionSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *ConjunctionSearcher) Advance(ID string) (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
if err != nil {

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestConjunctionSearch(t *testing.T) {
@ -23,7 +25,7 @@ func TestConjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
beerAndMartySearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher, martyTermSearcher}, true)
beerAndMartySearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher, martyTermSearcher}, true)
if err != nil {
t.Fatal(err)
}
@ -37,7 +39,7 @@ func TestConjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
angstAndBeerSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{angstTermSearcher, beerTermSearcher2}, true)
angstAndBeerSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{angstTermSearcher, beerTermSearcher2}, true)
if err != nil {
t.Fatal(err)
}
@ -51,7 +53,7 @@ func TestConjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
beerAndJackSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher3, jackTermSearcher}, true)
beerAndJackSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher3, jackTermSearcher}, true)
if err != nil {
t.Fatal(err)
}
@ -65,7 +67,7 @@ func TestConjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
beerAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher4, misterTermSearcher}, true)
beerAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher4, misterTermSearcher}, true)
if err != nil {
t.Fatal(err)
}
@ -79,7 +81,7 @@ func TestConjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
couchbaseAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{couchbaseTermSearcher, misterTermSearcher2}, true)
couchbaseAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{couchbaseTermSearcher, misterTermSearcher2}, true)
if err != nil {
t.Fatal(err)
}
@ -97,23 +99,23 @@ func TestConjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
couchbaseAndMisterSearcher2, err := NewConjunctionSearcher(twoDocIndex, []Searcher{couchbaseTermSearcher2, misterTermSearcher3}, true)
couchbaseAndMisterSearcher2, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{couchbaseTermSearcher2, misterTermSearcher3}, true)
if err != nil {
t.Fatal(err)
}
beerAndCouchbaseAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{beerTermSearcher5, couchbaseAndMisterSearcher2}, true)
beerAndCouchbaseAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{beerTermSearcher5, couchbaseAndMisterSearcher2}, true)
if err != nil {
t.Fatal(err)
}
tests := []struct {
searcher Searcher
results []*DocumentMatch
searcher search.Searcher
results []*search.DocumentMatch
}{
{
searcher: beerAndMartySearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 2.0097428702814377,
},
@ -121,8 +123,8 @@ func TestConjunctionSearch(t *testing.T) {
},
{
searcher: angstAndBeerSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.0807601687084403,
},
@ -130,16 +132,16 @@ func TestConjunctionSearch(t *testing.T) {
},
{
searcher: beerAndJackSearcher,
results: []*DocumentMatch{},
results: []*search.DocumentMatch{},
},
{
searcher: beerAndMisterSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.2877980334016337,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 1.2877980334016337,
},
@ -147,8 +149,8 @@ func TestConjunctionSearch(t *testing.T) {
},
{
searcher: couchbaseAndMisterSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.4436599157093672,
},
@ -156,8 +158,8 @@ func TestConjunctionSearch(t *testing.T) {
},
{
searcher: beerAndCouchbaseAndMisterSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.441614953806971,
},

View File

@ -6,13 +6,15 @@
// 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
package searchers
import (
"math"
"sort"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/scorers"
)
type DisjunctionSearcher struct {
@ -20,13 +22,13 @@ type DisjunctionSearcher struct {
index index.Index
searchers OrderedSearcherList
queryNorm float64
currs []*DocumentMatch
currs []*search.DocumentMatch
currentId string
scorer *DisjunctionQueryScorer
scorer *scorers.DisjunctionQueryScorer
min float64
}
func NewDisjunctionSearcher(index index.Index, qsearchers []Searcher, min float64, explain bool) (*DisjunctionSearcher, error) {
func NewDisjunctionSearcher(index index.Index, qsearchers []search.Searcher, min float64, explain bool) (*DisjunctionSearcher, error) {
// build the downstream searchres
searchers := make(OrderedSearcherList, len(qsearchers))
for i, searcher := range qsearchers {
@ -38,8 +40,8 @@ func NewDisjunctionSearcher(index index.Index, qsearchers []Searcher, min float6
rv := DisjunctionSearcher{
index: index,
searchers: searchers,
currs: make([]*DocumentMatch, len(searchers)),
scorer: NewDisjunctionQueryScorer(explain),
currs: make([]*search.DocumentMatch, len(searchers)),
scorer: scorers.NewDisjunctionQueryScorer(explain),
min: min,
}
rv.computeQueryNorm()
@ -99,7 +101,7 @@ func (s *DisjunctionSearcher) SetQueryNorm(qnorm float64) {
}
}
func (s *DisjunctionSearcher) Next() (*DocumentMatch, error) {
func (s *DisjunctionSearcher) Next() (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
if err != nil {
@ -107,8 +109,8 @@ func (s *DisjunctionSearcher) Next() (*DocumentMatch, error) {
}
}
var err error
var rv *DocumentMatch
matching := make([]*DocumentMatch, 0)
var rv *search.DocumentMatch
matching := make([]*search.DocumentMatch, 0)
found := false
for !found && s.currentId != "" {
@ -125,7 +127,7 @@ func (s *DisjunctionSearcher) Next() (*DocumentMatch, error) {
}
// reset matching
matching = make([]*DocumentMatch, 0)
matching = make([]*search.DocumentMatch, 0)
// invoke next on all the matching searchers
for i, curr := range s.currs {
if curr != nil && curr.ID == s.currentId {
@ -141,7 +143,7 @@ func (s *DisjunctionSearcher) Next() (*DocumentMatch, error) {
return rv, nil
}
func (s *DisjunctionSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *DisjunctionSearcher) Advance(ID string) (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
if err != nil {

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestDisjunctionSearch(t *testing.T) {
@ -22,7 +24,7 @@ func TestDisjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
martyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher, dustinTermSearcher}, 0, true)
martyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -35,7 +37,7 @@ func TestDisjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
martyOrDustinSearcher2, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, true)
martyOrDustinSearcher2, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, true)
if err != nil {
t.Fatal(err)
}
@ -44,23 +46,23 @@ func TestDisjunctionSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
nestedRaviOrMartyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{raviTermSearcher, martyOrDustinSearcher2}, 0, true)
nestedRaviOrMartyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{raviTermSearcher, martyOrDustinSearcher2}, 0, true)
if err != nil {
t.Fatal(err)
}
tests := []struct {
searcher Searcher
results []*DocumentMatch
searcher search.Searcher
results []*search.DocumentMatch
}{
{
searcher: martyOrDustinSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 0.6775110856165737,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 0.6775110856165737,
},
@ -69,16 +71,16 @@ func TestDisjunctionSearch(t *testing.T) {
// test a nested disjunction
{
searcher: nestedRaviOrMartyOrDustinSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 0.2765927424732821,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 0.2765927424732821,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "4",
Score: 0.5531854849465642,
},
@ -124,7 +126,7 @@ func TestDisjunctionAdvance(t *testing.T) {
if err != nil {
t.Fatal(err)
}
martyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndex, []Searcher{martyTermSearcher, dustinTermSearcher}, 0, true)
martyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndex, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, true)
if err != nil {
t.Fatal(err)
}

View File

@ -6,16 +6,18 @@
// 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
package searchers
import (
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/scorers"
)
type MatchAllSearcher struct {
index index.Index
reader index.DocIdReader
scorer *ConstantScorer
scorer *scorers.ConstantScorer
}
func NewMatchAllSearcher(index index.Index, boost float64, explain bool) (*MatchAllSearcher, error) {
@ -23,7 +25,7 @@ func NewMatchAllSearcher(index index.Index, boost float64, explain bool) (*Match
if err != nil {
return nil, err
}
scorer := NewConstantScorer(1.0, boost, explain)
scorer := scorers.NewConstantScorer(1.0, boost, explain)
return &MatchAllSearcher{
index: index,
reader: reader,
@ -43,7 +45,7 @@ func (s *MatchAllSearcher) SetQueryNorm(qnorm float64) {
s.scorer.SetQueryNorm(qnorm)
}
func (s *MatchAllSearcher) Next() (*DocumentMatch, error) {
func (s *MatchAllSearcher) Next() (*search.DocumentMatch, error) {
id, err := s.reader.Next()
if err != nil {
return nil, err
@ -60,7 +62,7 @@ func (s *MatchAllSearcher) Next() (*DocumentMatch, error) {
}
func (s *MatchAllSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *MatchAllSearcher) Advance(ID string) (*search.DocumentMatch, error) {
id, err := s.reader.Advance(ID)
if err != nil {
return nil, err

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestMatchAllSearch(t *testing.T) {
@ -25,31 +27,31 @@ func TestMatchAllSearch(t *testing.T) {
}
tests := []struct {
searcher Searcher
searcher search.Searcher
queryNorm float64
results []*DocumentMatch
results []*search.DocumentMatch
}{
{
searcher: allSearcher,
queryNorm: 1.0,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "4",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "5",
Score: 1.0,
},
@ -58,24 +60,24 @@ func TestMatchAllSearch(t *testing.T) {
{
searcher: allSearcher2,
queryNorm: 0.8333333,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "1",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "3",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "4",
Score: 1.0,
},
&DocumentMatch{
&search.DocumentMatch{
ID: "5",
Score: 1.0,
},

View File

@ -6,10 +6,11 @@
// 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
package searchers
import (
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
)
type MatchNoneSearcher struct {
@ -34,11 +35,11 @@ func (s *MatchNoneSearcher) SetQueryNorm(qnorm float64) {
}
func (s *MatchNoneSearcher) Next() (*DocumentMatch, error) {
func (s *MatchNoneSearcher) Next() (*search.DocumentMatch, error) {
return nil, nil
}
func (s *MatchNoneSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *MatchNoneSearcher) Advance(ID string) (*search.DocumentMatch, error) {
return nil, nil
}

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestMatchNoneSearch(t *testing.T) {
@ -20,12 +22,12 @@ func TestMatchNoneSearch(t *testing.T) {
}
tests := []struct {
searcher Searcher
results []*DocumentMatch
searcher search.Searcher
results []*search.DocumentMatch
}{
{
searcher: noneSearcher,
results: []*DocumentMatch{},
results: []*search.DocumentMatch{},
},
}

View File

@ -6,7 +6,7 @@
// 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
package searchers
import (
"bytes"
@ -14,6 +14,7 @@ import (
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/numeric_util"
"github.com/blevesearch/bleve/search"
)
type NumericRangeSearcher struct {
@ -56,7 +57,7 @@ func NewNumericRangeSearcher(index index.Index, min *float64, max *float64, incl
termRanges := splitInt64Range(minInt64, maxInt64, 4)
terms := termRanges.Enumerate()
// enumerate all the terms in the range
qsearchers := make([]Searcher, len(terms))
qsearchers := make([]search.Searcher, len(terms))
for i, term := range terms {
var err error
qsearchers[i], err = NewTermSearcher(index, string(term), field, 1.0, explain)
@ -91,11 +92,11 @@ func (s *NumericRangeSearcher) SetQueryNorm(qnorm float64) {
s.searcher.SetQueryNorm(qnorm)
}
func (s *NumericRangeSearcher) Next() (*DocumentMatch, error) {
func (s *NumericRangeSearcher) Next() (*search.DocumentMatch, error) {
return s.searcher.Next()
}
func (s *NumericRangeSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *NumericRangeSearcher) Advance(ID string) (*search.DocumentMatch, error) {
return s.searcher.Advance(ID)
}

View File

@ -1,4 +1,13 @@
package search
// 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 searchers
import (
"reflect"

View File

@ -6,12 +6,13 @@
// 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
package searchers
import (
"math"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
)
type PhraseSearcher struct {
@ -19,7 +20,7 @@ type PhraseSearcher struct {
index index.Index
mustSearcher *ConjunctionSearcher
queryNorm float64
currMust *DocumentMatch
currMust *search.DocumentMatch
slop int
terms []string
}
@ -89,7 +90,7 @@ func (s *PhraseSearcher) SetQueryNorm(qnorm float64) {
s.mustSearcher.SetQueryNorm(qnorm)
}
func (s *PhraseSearcher) Next() (*DocumentMatch, error) {
func (s *PhraseSearcher) Next() (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
if err != nil {
@ -97,18 +98,18 @@ func (s *PhraseSearcher) Next() (*DocumentMatch, error) {
}
}
var rv *DocumentMatch
var rv *search.DocumentMatch
for s.currMust != nil {
rvftlm := make(FieldTermLocationMap, 0)
rvftlm := make(search.FieldTermLocationMap, 0)
freq := 0
firstTerm := s.terms[0]
for field, termLocMap := range s.currMust.Locations {
rvtlm := make(TermLocationMap, 0)
rvtlm := make(search.TermLocationMap, 0)
locations, ok := termLocMap[firstTerm]
if ok {
OUTER:
for _, location := range locations {
crvtlm := make(TermLocationMap, 0)
crvtlm := make(search.TermLocationMap, 0)
INNER:
for i := 0; i < len(s.mustSearcher.searchers); i++ {
nextTerm := s.terms[i]
@ -133,7 +134,7 @@ func (s *PhraseSearcher) Next() (*DocumentMatch, error) {
}
// if we got here all the terms matched
freq += 1
mergeTermLocationMaps(rvtlm, crvtlm)
search.MergeTermLocationMaps(rvtlm, crvtlm)
rvftlm[field] = rvtlm
}
}
@ -153,7 +154,7 @@ func (s *PhraseSearcher) Next() (*DocumentMatch, error) {
return nil, nil
}
func (s *PhraseSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *PhraseSearcher) Advance(ID string) (*search.DocumentMatch, error) {
if !s.initialized {
err := s.initSearchers()
if err != nil {

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"testing"
"github.com/blevesearch/bleve/search"
)
func TestPhraseSearch(t *testing.T) {
@ -22,7 +24,7 @@ func TestPhraseSearch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mustSearcher, err := NewConjunctionSearcher(twoDocIndex, []Searcher{angstTermSearcher, beerTermSearcher}, true)
mustSearcher, err := NewConjunctionSearcher(twoDocIndex, []search.Searcher{angstTermSearcher, beerTermSearcher}, true)
if err != nil {
t.Fatal(err)
}
@ -32,13 +34,13 @@ func TestPhraseSearch(t *testing.T) {
}
tests := []struct {
searcher Searcher
results []*DocumentMatch
searcher search.Searcher
results []*search.DocumentMatch
}{
{
searcher: phraseSearcher,
results: []*DocumentMatch{
&DocumentMatch{
results: []*search.DocumentMatch{
&search.DocumentMatch{
ID: "2",
Score: 1.0807601687084403,
},

View File

@ -6,10 +6,12 @@
// 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
package searchers
import (
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
"github.com/blevesearch/bleve/search/scorers"
)
type TermSearcher struct {
@ -18,7 +20,7 @@ type TermSearcher struct {
field string
explain bool
reader index.TermFieldReader
scorer *TermQueryScorer
scorer *scorers.TermQueryScorer
}
func NewTermSearcher(index index.Index, term string, field string, boost float64, explain bool) (*TermSearcher, error) {
@ -26,7 +28,7 @@ func NewTermSearcher(index index.Index, term string, field string, boost float64
if err != nil {
return nil, err
}
scorer := NewTermQueryScorer(term, field, boost, index.DocCount(), reader.Count(), explain)
scorer := scorers.NewTermQueryScorer(term, field, boost, index.DocCount(), reader.Count(), explain)
return &TermSearcher{
index: index,
term: term,
@ -49,7 +51,7 @@ func (s *TermSearcher) SetQueryNorm(qnorm float64) {
s.scorer.SetQueryNorm(qnorm)
}
func (s *TermSearcher) Next() (*DocumentMatch, error) {
func (s *TermSearcher) Next() (*search.DocumentMatch, error) {
termMatch, err := s.reader.Next()
if err != nil {
return nil, err
@ -66,7 +68,7 @@ func (s *TermSearcher) Next() (*DocumentMatch, error) {
}
func (s *TermSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *TermSearcher) Advance(ID string) (*search.DocumentMatch, error) {
termMatch, err := s.reader.Advance(ID)
if err != nil {
return nil, err

View File

@ -6,10 +6,11 @@
// 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
package searchers
import (
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
)
type TermPrefixSearcher struct {
@ -25,7 +26,7 @@ func NewTermPrefixSearcher(index index.Index, prefix string, field string, boost
fieldReader, err := index.FieldReader(field, []byte(prefix), []byte(prefix))
// enumerate all the terms in the range
qsearchers := make([]Searcher, 0, 25)
qsearchers := make([]search.Searcher, 0, 25)
tfd, err := fieldReader.Next()
for err == nil && tfd != nil {
qsearcher, err := NewTermSearcher(index, string(tfd.Term), field, 1.0, explain)
@ -61,12 +62,12 @@ func (s *TermPrefixSearcher) SetQueryNorm(qnorm float64) {
s.searcher.SetQueryNorm(qnorm)
}
func (s *TermPrefixSearcher) Next() (*DocumentMatch, error) {
func (s *TermPrefixSearcher) Next() (*search.DocumentMatch, error) {
return s.searcher.Next()
}
func (s *TermPrefixSearcher) Advance(ID string) (*DocumentMatch, error) {
func (s *TermPrefixSearcher) Advance(ID string) (*search.DocumentMatch, error) {
return s.searcher.Next()
}

View File

@ -6,7 +6,7 @@
// 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
package searchers
import (
"math"

View File

@ -8,7 +8,7 @@
// and limitations under the License.
package search
func mergeLocations(locations []FieldTermLocationMap) FieldTermLocationMap {
func MergeLocations(locations []FieldTermLocationMap) FieldTermLocationMap {
rv := locations[0]
for i := 1; i < len(locations); i++ {
@ -16,7 +16,7 @@ func mergeLocations(locations []FieldTermLocationMap) FieldTermLocationMap {
for field, termLocationMap := range nextLocations {
rvTermLocationMap, rvHasField := rv[field]
if rvHasField {
rv[field] = mergeTermLocationMaps(rvTermLocationMap, termLocationMap)
rv[field] = MergeTermLocationMaps(rvTermLocationMap, termLocationMap)
} else {
rv[field] = termLocationMap
}
@ -26,7 +26,7 @@ func mergeLocations(locations []FieldTermLocationMap) FieldTermLocationMap {
return rv
}
func mergeTermLocationMaps(rv, other TermLocationMap) TermLocationMap {
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

View File

@ -78,7 +78,7 @@ func TestMergeLocations(t *testing.T) {
},
}
mergedLocations := mergeLocations([]FieldTermLocationMap{flm1, flm2, flm3})
mergedLocations := MergeLocations([]FieldTermLocationMap{flm1, flm2, flm3})
if !reflect.DeepEqual(expectedMerge, mergedLocations) {
t.Errorf("expected %v, got %v", expectedMerge, mergedLocations)
}