forked from forgejo/forgejo
Upgrade bleve to v1.0.10 (#12737)
* Fix bug on migration 111 * Upgrade bleve to 1.0.10 Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
parent
1b9d5074a7
commit
d17efaa114
90 changed files with 12172 additions and 489 deletions
7
vendor/github.com/blevesearch/bleve/README.md
generated
vendored
7
vendor/github.com/blevesearch/bleve/README.md
generated
vendored
|
@ -1,10 +1,13 @@
|
|||
#  bleve
|
||||
|
||||
[](https://travis-ci.org/blevesearch/bleve) [](https://coveralls.io/github/blevesearch/bleve?branch=master) [](https://godoc.org/github.com/blevesearch/bleve)
|
||||
[](https://github.com/blevesearch/bleve/actions?query=workflow%3ATests+event%3Apush+branch%3Amaster)
|
||||
[](https://coveralls.io/github/blevesearch/bleve?branch=master)
|
||||
[](https://godoc.org/github.com/blevesearch/bleve)
|
||||
[](https://gitter.im/blevesearch/bleve?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://codebeat.co/projects/github-com-blevesearch-bleve)
|
||||
[](https://goreportcard.com/report/blevesearch/bleve)
|
||||
[](https://sourcegraph.com/github.com/blevesearch/bleve?badge) [](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://sourcegraph.com/github.com/blevesearch/bleve?badge)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
modern text indexing in go - [blevesearch.com](http://www.blevesearch.com/)
|
||||
|
||||
|
|
94
vendor/github.com/blevesearch/bleve/builder.go
generated
vendored
Normal file
94
vendor/github.com/blevesearch/bleve/builder.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) 2019 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 bleve
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/blevesearch/bleve/document"
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/index/scorch"
|
||||
"github.com/blevesearch/bleve/mapping"
|
||||
)
|
||||
|
||||
type builderImpl struct {
|
||||
b index.IndexBuilder
|
||||
m mapping.IndexMapping
|
||||
}
|
||||
|
||||
func (b *builderImpl) Index(id string, data interface{}) error {
|
||||
if id == "" {
|
||||
return ErrorEmptyID
|
||||
}
|
||||
|
||||
doc := document.NewDocument(id)
|
||||
err := b.m.MapDocument(doc, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = b.b.Index(doc)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *builderImpl) Close() error {
|
||||
return b.b.Close()
|
||||
}
|
||||
|
||||
func newBuilder(path string, mapping mapping.IndexMapping, config map[string]interface{}) (Builder, error) {
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("builder requires path")
|
||||
}
|
||||
|
||||
err := mapping.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
config = map[string]interface{}{}
|
||||
}
|
||||
|
||||
// the builder does not have an API to interact with internal storage
|
||||
// however we can pass k/v pairs through the config
|
||||
mappingBytes, err := json.Marshal(mapping)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config["internal"] = map[string][]byte{
|
||||
string(mappingInternalKey): mappingBytes,
|
||||
}
|
||||
|
||||
// do not use real config, as these are options for the builder,
|
||||
// not the resulting index
|
||||
meta := newIndexMeta(scorch.Name, scorch.Name, map[string]interface{}{})
|
||||
err = meta.Save(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config["path"] = indexStorePath(path)
|
||||
|
||||
b, err := scorch.NewBuilder(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv := &builderImpl{
|
||||
b: b,
|
||||
m: mapping,
|
||||
}
|
||||
|
||||
return rv, nil
|
||||
}
|
13
vendor/github.com/blevesearch/bleve/go.mod
generated
vendored
13
vendor/github.com/blevesearch/bleve/go.mod
generated
vendored
|
@ -3,16 +3,17 @@ module github.com/blevesearch/bleve
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/RoaringBitmap/roaring v0.4.21
|
||||
github.com/RoaringBitmap/roaring v0.4.23
|
||||
github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3
|
||||
github.com/blevesearch/segment v0.9.0
|
||||
github.com/blevesearch/snowballstem v0.9.0
|
||||
github.com/blevesearch/zap/v11 v11.0.7
|
||||
github.com/blevesearch/zap/v12 v12.0.7
|
||||
github.com/couchbase/ghistogram v0.1.0 // indirect
|
||||
github.com/blevesearch/zap/v11 v11.0.10
|
||||
github.com/blevesearch/zap/v12 v12.0.10
|
||||
github.com/blevesearch/zap/v13 v13.0.2
|
||||
github.com/blevesearch/zap/v14 v14.0.1
|
||||
github.com/couchbase/moss v0.1.0
|
||||
github.com/couchbase/vellum v1.0.1
|
||||
github.com/couchbase/vellum v1.0.2
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/kljensen/snowball v0.6.0
|
||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563
|
||||
|
@ -20,6 +21,6 @@ require (
|
|||
github.com/steveyen/gtreap v0.1.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/willf/bitset v1.1.10
|
||||
go.etcd.io/bbolt v1.3.4
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
golang.org/x/text v0.3.0
|
||||
)
|
||||
|
|
14
vendor/github.com/blevesearch/bleve/index.go
generated
vendored
14
vendor/github.com/blevesearch/bleve/index.go
generated
vendored
|
@ -293,3 +293,17 @@ func Open(path string) (Index, error) {
|
|||
func OpenUsing(path string, runtimeConfig map[string]interface{}) (Index, error) {
|
||||
return openIndexUsing(path, runtimeConfig)
|
||||
}
|
||||
|
||||
// Builder is a limited interface, used to build indexes in an offline mode.
|
||||
// Items cannot be updated or deleted, and the caller MUST ensure a document is
|
||||
// indexed only once.
|
||||
type Builder interface {
|
||||
Index(id string, data interface{}) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
// NewBuilder creates a builder, which will build an index at the specified path,
|
||||
// using the specified mapping and options.
|
||||
func NewBuilder(path string, mapping mapping.IndexMapping, config map[string]interface{}) (Builder, error) {
|
||||
return newBuilder(path, mapping, config)
|
||||
}
|
||||
|
|
7
vendor/github.com/blevesearch/bleve/index/index.go
generated
vendored
7
vendor/github.com/blevesearch/bleve/index/index.go
generated
vendored
|
@ -367,3 +367,10 @@ type OptimizableContext interface {
|
|||
type DocValueReader interface {
|
||||
VisitDocValues(id IndexInternalID, visitor DocumentFieldTermVisitor) error
|
||||
}
|
||||
|
||||
// IndexBuilder is an interface supported by some index schemes
|
||||
// to allow direct write-only index building
|
||||
type IndexBuilder interface {
|
||||
Index(doc *document.Document) error
|
||||
Close() error
|
||||
}
|
||||
|
|
334
vendor/github.com/blevesearch/bleve/index/scorch/builder.go
generated
vendored
Normal file
334
vendor/github.com/blevesearch/bleve/index/scorch/builder.go
generated
vendored
Normal file
|
@ -0,0 +1,334 @@
|
|||
// Copyright (c) 2019 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 scorch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
"github.com/blevesearch/bleve/document"
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/index/scorch/segment"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
const DefaultBuilderBatchSize = 1000
|
||||
const DefaultBuilderMergeMax = 10
|
||||
|
||||
type Builder struct {
|
||||
m sync.Mutex
|
||||
segCount uint64
|
||||
path string
|
||||
buildPath string
|
||||
segPaths []string
|
||||
batchSize int
|
||||
mergeMax int
|
||||
batch *index.Batch
|
||||
internal map[string][]byte
|
||||
segPlugin segment.Plugin
|
||||
}
|
||||
|
||||
func NewBuilder(config map[string]interface{}) (*Builder, error) {
|
||||
path, ok := config["path"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("must specify path")
|
||||
}
|
||||
|
||||
buildPathPrefix, _ := config["buildPathPrefix"].(string)
|
||||
buildPath, err := ioutil.TempDir(buildPathPrefix, "scorch-offline-build")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rv := &Builder{
|
||||
path: path,
|
||||
buildPath: buildPath,
|
||||
mergeMax: DefaultBuilderMergeMax,
|
||||
batchSize: DefaultBuilderBatchSize,
|
||||
batch: index.NewBatch(),
|
||||
segPlugin: defaultSegmentPlugin,
|
||||
}
|
||||
|
||||
err = rv.parseConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing builder config: %v", err)
|
||||
}
|
||||
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (o *Builder) parseConfig(config map[string]interface{}) (err error) {
|
||||
if v, ok := config["mergeMax"]; ok {
|
||||
var t int
|
||||
if t, err = parseToInteger(v); err != nil {
|
||||
return fmt.Errorf("mergeMax parse err: %v", err)
|
||||
}
|
||||
if t > 0 {
|
||||
o.mergeMax = t
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := config["batchSize"]; ok {
|
||||
var t int
|
||||
if t, err = parseToInteger(v); err != nil {
|
||||
return fmt.Errorf("batchSize parse err: %v", err)
|
||||
}
|
||||
if t > 0 {
|
||||
o.batchSize = t
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := config["internal"]; ok {
|
||||
if vinternal, ok := v.(map[string][]byte); ok {
|
||||
o.internal = vinternal
|
||||
}
|
||||
}
|
||||
|
||||
forcedSegmentType, forcedSegmentVersion, err := configForceSegmentTypeVersion(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if forcedSegmentType != "" && forcedSegmentVersion != 0 {
|
||||
segPlugin, err := chooseSegmentPlugin(forcedSegmentType,
|
||||
uint32(forcedSegmentVersion))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.segPlugin = segPlugin
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Index will place the document into the index.
|
||||
// It is invalid to index the same document multiple times.
|
||||
func (o *Builder) Index(doc *document.Document) error {
|
||||
o.m.Lock()
|
||||
defer o.m.Unlock()
|
||||
|
||||
o.batch.Update(doc)
|
||||
|
||||
return o.maybeFlushBatchLOCKED(o.batchSize)
|
||||
}
|
||||
|
||||
func (o *Builder) maybeFlushBatchLOCKED(moreThan int) error {
|
||||
if len(o.batch.IndexOps) >= moreThan {
|
||||
defer o.batch.Reset()
|
||||
return o.executeBatchLOCKED(o.batch)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Builder) executeBatchLOCKED(batch *index.Batch) (err error) {
|
||||
analysisResults := make([]*index.AnalysisResult, 0, len(batch.IndexOps))
|
||||
for _, doc := range batch.IndexOps {
|
||||
if doc != nil {
|
||||
// insert _id field
|
||||
doc.AddField(document.NewTextFieldCustom("_id", nil, []byte(doc.ID), document.IndexField|document.StoreField, nil))
|
||||
// perform analysis directly
|
||||
analysisResult := analyze(doc)
|
||||
analysisResults = append(analysisResults, analysisResult)
|
||||
}
|
||||
}
|
||||
|
||||
seg, _, err := o.segPlugin.New(analysisResults)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error building segment base: %v", err)
|
||||
}
|
||||
|
||||
filename := zapFileName(o.segCount)
|
||||
o.segCount++
|
||||
path := o.buildPath + string(os.PathSeparator) + filename
|
||||
|
||||
if segUnpersisted, ok := seg.(segment.UnpersistedSegment); ok {
|
||||
err = segUnpersisted.Persist(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error persisting segment base to %s: %v", path, err)
|
||||
}
|
||||
|
||||
o.segPaths = append(o.segPaths, path)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("new segment does not implement unpersisted: %T", seg)
|
||||
}
|
||||
|
||||
func (o *Builder) doMerge() error {
|
||||
// as long as we have more than 1 segment, keep merging
|
||||
for len(o.segPaths) > 1 {
|
||||
|
||||
// merge the next <mergeMax> number of segments into one new one
|
||||
// or, if there are fewer than <mergeMax> remaining, merge them all
|
||||
mergeCount := o.mergeMax
|
||||
if mergeCount > len(o.segPaths) {
|
||||
mergeCount = len(o.segPaths)
|
||||
}
|
||||
|
||||
mergePaths := o.segPaths[0:mergeCount]
|
||||
o.segPaths = o.segPaths[mergeCount:]
|
||||
|
||||
// open each of the segments to be merged
|
||||
mergeSegs := make([]segment.Segment, 0, mergeCount)
|
||||
|
||||
// closeOpenedSegs attempts to close all opened
|
||||
// segments even if an error occurs, in which case
|
||||
// the first error is returned
|
||||
closeOpenedSegs := func() error {
|
||||
var err error
|
||||
for _, seg := range mergeSegs {
|
||||
clErr := seg.Close()
|
||||
if clErr != nil && err == nil {
|
||||
err = clErr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mergePath := range mergePaths {
|
||||
seg, err := o.segPlugin.Open(mergePath)
|
||||
if err != nil {
|
||||
_ = closeOpenedSegs()
|
||||
return fmt.Errorf("error opening segment (%s) for merge: %v", mergePath, err)
|
||||
}
|
||||
mergeSegs = append(mergeSegs, seg)
|
||||
}
|
||||
|
||||
// do the merge
|
||||
mergedSegPath := o.buildPath + string(os.PathSeparator) + zapFileName(o.segCount)
|
||||
drops := make([]*roaring.Bitmap, mergeCount)
|
||||
_, _, err := o.segPlugin.Merge(mergeSegs, drops, mergedSegPath, nil, nil)
|
||||
if err != nil {
|
||||
_ = closeOpenedSegs()
|
||||
return fmt.Errorf("error merging segments (%v): %v", mergePaths, err)
|
||||
}
|
||||
o.segCount++
|
||||
o.segPaths = append(o.segPaths, mergedSegPath)
|
||||
|
||||
// close segments opened for merge
|
||||
err = closeOpenedSegs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error closing opened segments: %v", err)
|
||||
}
|
||||
|
||||
// remove merged segments
|
||||
for _, mergePath := range mergePaths {
|
||||
err = os.RemoveAll(mergePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing segment %s after merge: %v", mergePath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Builder) Close() error {
|
||||
o.m.Lock()
|
||||
defer o.m.Unlock()
|
||||
|
||||
// see if there is a partial batch
|
||||
err := o.maybeFlushBatchLOCKED(1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error flushing batch before close: %v", err)
|
||||
}
|
||||
|
||||
// perform all the merging
|
||||
err = o.doMerge()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while merging: %v", err)
|
||||
}
|
||||
|
||||
// ensure the store path exists
|
||||
err = os.MkdirAll(o.path, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// move final segment into place
|
||||
// segment id 2 is chosen to match the behavior of a scorch
|
||||
// index which indexes a single batch of data
|
||||
finalSegPath := o.path + string(os.PathSeparator) + zapFileName(2)
|
||||
err = os.Rename(o.segPaths[0], finalSegPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error moving final segment into place: %v", err)
|
||||
}
|
||||
|
||||
// remove the buildPath, as it is no longer needed
|
||||
err = os.RemoveAll(o.buildPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing build path: %v", err)
|
||||
}
|
||||
|
||||
// prepare wrapping
|
||||
seg, err := o.segPlugin.Open(finalSegPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening final segment")
|
||||
}
|
||||
|
||||
// create a segment snapshot for this segment
|
||||
ss := &SegmentSnapshot{
|
||||
segment: seg,
|
||||
}
|
||||
is := &IndexSnapshot{
|
||||
epoch: 3, // chosen to match scorch behavior when indexing a single batch
|
||||
segment: []*SegmentSnapshot{ss},
|
||||
creator: "scorch-builder",
|
||||
internal: o.internal,
|
||||
}
|
||||
|
||||
// create the root bolt
|
||||
rootBoltPath := o.path + string(os.PathSeparator) + "root.bolt"
|
||||
rootBolt, err := bolt.Open(rootBoltPath, 0600, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start a write transaction
|
||||
tx, err := rootBolt.Begin(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// fill the root bolt with this fake index snapshot
|
||||
_, _, err = prepareBoltSnapshot(is, tx, o.path, o.segPlugin)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
_ = rootBolt.Close()
|
||||
return fmt.Errorf("error preparing bolt snapshot in root.bolt: %v", err)
|
||||
}
|
||||
|
||||
// commit bolt data
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
_ = rootBolt.Close()
|
||||
return fmt.Errorf("error committing bolt tx in root.bolt: %v", err)
|
||||
}
|
||||
|
||||
// close bolt
|
||||
err = rootBolt.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error closing root.bolt: %v", err)
|
||||
}
|
||||
|
||||
// close final segment
|
||||
err = seg.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error closing final segment: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
8
vendor/github.com/blevesearch/bleve/index/scorch/event.go
generated
vendored
8
vendor/github.com/blevesearch/bleve/index/scorch/event.go
generated
vendored
|
@ -54,3 +54,11 @@ var EventKindBatchIntroductionStart = EventKind(5)
|
|||
|
||||
// EventKindBatchIntroduction is fired when Batch() completes.
|
||||
var EventKindBatchIntroduction = EventKind(6)
|
||||
|
||||
// EventKindMergeTaskIntroductionStart is fired when the merger is about to
|
||||
// start the introduction of merged segment from a single merge task.
|
||||
var EventKindMergeTaskIntroductionStart = EventKind(7)
|
||||
|
||||
// EventKindMergeTaskIntroduction is fired when the merger has completed
|
||||
// the introduction of merged segment from a single merge task.
|
||||
var EventKindMergeTaskIntroduction = EventKind(8)
|
||||
|
|
18
vendor/github.com/blevesearch/bleve/index/scorch/introducer.go
generated
vendored
18
vendor/github.com/blevesearch/bleve/index/scorch/introducer.go
generated
vendored
|
@ -45,13 +45,7 @@ type epochWatcher struct {
|
|||
notifyCh notificationChan
|
||||
}
|
||||
|
||||
type snapshotReversion struct {
|
||||
snapshot *IndexSnapshot
|
||||
applied chan error
|
||||
persisted chan error
|
||||
}
|
||||
|
||||
func (s *Scorch) mainLoop() {
|
||||
func (s *Scorch) introducerLoop() {
|
||||
var epochWatchers []*epochWatcher
|
||||
OUTER:
|
||||
for {
|
||||
|
@ -389,6 +383,7 @@ func (s *Scorch) introduceMerge(nextMerge *segmentMerge) {
|
|||
}
|
||||
}
|
||||
}
|
||||
var skipped bool
|
||||
// In case where all the docs in the newly merged segment getting
|
||||
// deleted by the time we reach here, can skip the introduction.
|
||||
if nextMerge.new != nil &&
|
||||
|
@ -411,6 +406,9 @@ func (s *Scorch) introduceMerge(nextMerge *segmentMerge) {
|
|||
docsToPersistCount += nextMerge.new.Count() - newSegmentDeleted.GetCardinality()
|
||||
memSegments++
|
||||
}
|
||||
} else {
|
||||
skipped = true
|
||||
atomic.AddUint64(&s.stats.TotFileMergeIntroductionsObsoleted, 1)
|
||||
}
|
||||
|
||||
atomic.StoreUint64(&s.stats.TotItemsToPersist, docsToPersistCount)
|
||||
|
@ -435,8 +433,10 @@ func (s *Scorch) introduceMerge(nextMerge *segmentMerge) {
|
|||
}
|
||||
|
||||
// notify requester that we incorporated this
|
||||
nextMerge.notify <- newSnapshot
|
||||
close(nextMerge.notify)
|
||||
nextMerge.notifyCh <- &mergeTaskIntroStatus{
|
||||
indexSnapshot: newSnapshot,
|
||||
skipped: skipped}
|
||||
close(nextMerge.notifyCh)
|
||||
}
|
||||
|
||||
func isMemorySegment(s *SegmentSnapshot) bool {
|
||||
|
|
168
vendor/github.com/blevesearch/bleve/index/scorch/merge.go
generated
vendored
168
vendor/github.com/blevesearch/bleve/index/scorch/merge.go
generated
vendored
|
@ -15,6 +15,7 @@
|
|||
package scorch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -29,12 +30,16 @@ import (
|
|||
|
||||
func (s *Scorch) mergerLoop() {
|
||||
var lastEpochMergePlanned uint64
|
||||
var ctrlMsg *mergerCtrl
|
||||
mergePlannerOptions, err := s.parseMergePlannerOptions()
|
||||
if err != nil {
|
||||
s.fireAsyncError(fmt.Errorf("mergePlannerOption json parsing err: %v", err))
|
||||
s.asyncTasks.Done()
|
||||
return
|
||||
}
|
||||
ctrlMsgDflt := &mergerCtrl{ctx: context.Background(),
|
||||
options: mergePlannerOptions,
|
||||
doneCh: nil}
|
||||
|
||||
OUTER:
|
||||
for {
|
||||
|
@ -53,16 +58,30 @@ OUTER:
|
|||
atomic.StoreUint64(&s.iStats.mergeEpoch, ourSnapshot.epoch)
|
||||
s.rootLock.Unlock()
|
||||
|
||||
if ourSnapshot.epoch != lastEpochMergePlanned {
|
||||
if ctrlMsg == nil && ourSnapshot.epoch != lastEpochMergePlanned {
|
||||
ctrlMsg = ctrlMsgDflt
|
||||
}
|
||||
if ctrlMsg != nil {
|
||||
startTime := time.Now()
|
||||
|
||||
// lets get started
|
||||
err := s.planMergeAtSnapshot(ourSnapshot, mergePlannerOptions)
|
||||
err := s.planMergeAtSnapshot(ctrlMsg.ctx, ctrlMsg.options,
|
||||
ourSnapshot)
|
||||
if err != nil {
|
||||
atomic.StoreUint64(&s.iStats.mergeEpoch, 0)
|
||||
if err == segment.ErrClosed {
|
||||
// index has been closed
|
||||
_ = ourSnapshot.DecRef()
|
||||
|
||||
// continue the workloop on a user triggered cancel
|
||||
if ctrlMsg.doneCh != nil {
|
||||
close(ctrlMsg.doneCh)
|
||||
ctrlMsg = nil
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
// exit the workloop on index closure
|
||||
ctrlMsg = nil
|
||||
break OUTER
|
||||
}
|
||||
s.fireAsyncError(fmt.Errorf("merging err: %v", err))
|
||||
|
@ -70,6 +89,12 @@ OUTER:
|
|||
atomic.AddUint64(&s.stats.TotFileMergeLoopErr, 1)
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
if ctrlMsg.doneCh != nil {
|
||||
close(ctrlMsg.doneCh)
|
||||
}
|
||||
ctrlMsg = nil
|
||||
|
||||
lastEpochMergePlanned = ourSnapshot.epoch
|
||||
|
||||
atomic.StoreUint64(&s.stats.LastMergedEpoch, ourSnapshot.epoch)
|
||||
|
@ -90,6 +115,8 @@ OUTER:
|
|||
case <-s.closeCh:
|
||||
break OUTER
|
||||
case s.persisterNotifier <- ew:
|
||||
case ctrlMsg = <-s.forceMergeRequestCh:
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
// now wait for persister (but also detect close)
|
||||
|
@ -97,6 +124,7 @@ OUTER:
|
|||
case <-s.closeCh:
|
||||
break OUTER
|
||||
case <-ew.notifyCh:
|
||||
case ctrlMsg = <-s.forceMergeRequestCh:
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,6 +134,58 @@ OUTER:
|
|||
s.asyncTasks.Done()
|
||||
}
|
||||
|
||||
type mergerCtrl struct {
|
||||
ctx context.Context
|
||||
options *mergeplan.MergePlanOptions
|
||||
doneCh chan struct{}
|
||||
}
|
||||
|
||||
// ForceMerge helps users trigger a merge operation on
|
||||
// an online scorch index.
|
||||
func (s *Scorch) ForceMerge(ctx context.Context,
|
||||
mo *mergeplan.MergePlanOptions) error {
|
||||
// check whether force merge is already under processing
|
||||
s.rootLock.Lock()
|
||||
if s.stats.TotFileMergeForceOpsStarted >
|
||||
s.stats.TotFileMergeForceOpsCompleted {
|
||||
s.rootLock.Unlock()
|
||||
return fmt.Errorf("force merge already in progress")
|
||||
}
|
||||
|
||||
s.stats.TotFileMergeForceOpsStarted++
|
||||
s.rootLock.Unlock()
|
||||
|
||||
if mo != nil {
|
||||
err := mergeplan.ValidateMergePlannerOptions(mo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// assume the default single segment merge policy
|
||||
mo = &mergeplan.SingleSegmentMergePlanOptions
|
||||
}
|
||||
msg := &mergerCtrl{options: mo,
|
||||
doneCh: make(chan struct{}),
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
// request the merger perform a force merge
|
||||
select {
|
||||
case s.forceMergeRequestCh <- msg:
|
||||
case <-s.closeCh:
|
||||
return nil
|
||||
}
|
||||
|
||||
// wait for the force merge operation completion
|
||||
select {
|
||||
case <-msg.doneCh:
|
||||
atomic.AddUint64(&s.stats.TotFileMergeForceOpsCompleted, 1)
|
||||
case <-s.closeCh:
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Scorch) parseMergePlannerOptions() (*mergeplan.MergePlanOptions,
|
||||
error) {
|
||||
mergePlannerOptions := mergeplan.DefaultMergePlanOptions
|
||||
|
@ -128,8 +208,39 @@ func (s *Scorch) parseMergePlannerOptions() (*mergeplan.MergePlanOptions,
|
|||
return &mergePlannerOptions, nil
|
||||
}
|
||||
|
||||
func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
||||
options *mergeplan.MergePlanOptions) error {
|
||||
type closeChWrapper struct {
|
||||
ch1 chan struct{}
|
||||
ctx context.Context
|
||||
closeCh chan struct{}
|
||||
}
|
||||
|
||||
func newCloseChWrapper(ch1 chan struct{},
|
||||
ctx context.Context) *closeChWrapper {
|
||||
return &closeChWrapper{ch1: ch1,
|
||||
ctx: ctx,
|
||||
closeCh: make(chan struct{})}
|
||||
}
|
||||
|
||||
func (w *closeChWrapper) close() {
|
||||
select {
|
||||
case <-w.closeCh:
|
||||
default:
|
||||
close(w.closeCh)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *closeChWrapper) listen() {
|
||||
select {
|
||||
case <-w.ch1:
|
||||
w.close()
|
||||
case <-w.ctx.Done():
|
||||
w.close()
|
||||
case <-w.closeCh:
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scorch) planMergeAtSnapshot(ctx context.Context,
|
||||
options *mergeplan.MergePlanOptions, ourSnapshot *IndexSnapshot) error {
|
||||
// build list of persisted segments in this snapshot
|
||||
var onlyPersistedSnapshots []mergeplan.Segment
|
||||
for _, segmentSnapshot := range ourSnapshot.segment {
|
||||
|
@ -158,6 +269,11 @@ func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
|||
// process tasks in serial for now
|
||||
var filenames []string
|
||||
|
||||
cw := newCloseChWrapper(s.closeCh, ctx)
|
||||
defer cw.close()
|
||||
|
||||
go cw.listen()
|
||||
|
||||
for _, task := range resultMergePlan.Tasks {
|
||||
if len(task.Segments) == 0 {
|
||||
atomic.AddUint64(&s.stats.TotFileMergePlanTasksSegmentsEmpty, 1)
|
||||
|
@ -194,8 +310,9 @@ func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
|||
|
||||
var oldNewDocNums map[uint64][]uint64
|
||||
var seg segment.Segment
|
||||
var filename string
|
||||
if len(segmentsToMerge) > 0 {
|
||||
filename := zapFileName(newSegmentID)
|
||||
filename = zapFileName(newSegmentID)
|
||||
s.markIneligibleForRemoval(filename)
|
||||
path := s.path + string(os.PathSeparator) + filename
|
||||
|
||||
|
@ -203,7 +320,7 @@ func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
|||
|
||||
atomic.AddUint64(&s.stats.TotFileMergeZapBeg, 1)
|
||||
newDocNums, _, err := s.segPlugin.Merge(segmentsToMerge, docsToDrop, path,
|
||||
s.closeCh, s)
|
||||
cw.closeCh, s)
|
||||
atomic.AddUint64(&s.stats.TotFileMergeZapEnd, 1)
|
||||
|
||||
fileMergeZapTime := uint64(time.Since(fileMergeZapStartTime))
|
||||
|
@ -240,9 +357,11 @@ func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
|||
old: oldMap,
|
||||
oldNewDocNums: oldNewDocNums,
|
||||
new: seg,
|
||||
notify: make(chan *IndexSnapshot),
|
||||
notifyCh: make(chan *mergeTaskIntroStatus),
|
||||
}
|
||||
|
||||
s.fireEvent(EventKindMergeTaskIntroductionStart, 0)
|
||||
|
||||
// give it to the introducer
|
||||
select {
|
||||
case <-s.closeCh:
|
||||
|
@ -255,18 +374,25 @@ func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
|||
introStartTime := time.Now()
|
||||
// it is safe to blockingly wait for the merge introduction
|
||||
// here as the introducer is bound to handle the notify channel.
|
||||
newSnapshot := <-sm.notify
|
||||
introStatus := <-sm.notifyCh
|
||||
introTime := uint64(time.Since(introStartTime))
|
||||
atomic.AddUint64(&s.stats.TotFileMergeZapIntroductionTime, introTime)
|
||||
if atomic.LoadUint64(&s.stats.MaxFileMergeZapIntroductionTime) < introTime {
|
||||
atomic.StoreUint64(&s.stats.MaxFileMergeZapIntroductionTime, introTime)
|
||||
}
|
||||
atomic.AddUint64(&s.stats.TotFileMergeIntroductionsDone, 1)
|
||||
if newSnapshot != nil {
|
||||
_ = newSnapshot.DecRef()
|
||||
if introStatus != nil && introStatus.indexSnapshot != nil {
|
||||
_ = introStatus.indexSnapshot.DecRef()
|
||||
if introStatus.skipped {
|
||||
// close the segment on skipping introduction.
|
||||
s.unmarkIneligibleForRemoval(filename)
|
||||
_ = seg.Close()
|
||||
}
|
||||
}
|
||||
|
||||
atomic.AddUint64(&s.stats.TotFileMergePlanTasksDone, 1)
|
||||
|
||||
s.fireEvent(EventKindMergeTaskIntroduction, 0)
|
||||
}
|
||||
|
||||
// once all the newly merged segment introductions are done,
|
||||
|
@ -279,12 +405,17 @@ func (s *Scorch) planMergeAtSnapshot(ourSnapshot *IndexSnapshot,
|
|||
return nil
|
||||
}
|
||||
|
||||
type mergeTaskIntroStatus struct {
|
||||
indexSnapshot *IndexSnapshot
|
||||
skipped bool
|
||||
}
|
||||
|
||||
type segmentMerge struct {
|
||||
id uint64
|
||||
old map[uint64]*SegmentSnapshot
|
||||
oldNewDocNums map[uint64][]uint64
|
||||
new segment.Segment
|
||||
notify chan *IndexSnapshot
|
||||
notifyCh chan *mergeTaskIntroStatus
|
||||
}
|
||||
|
||||
// perform a merging of the given SegmentBase instances into a new,
|
||||
|
@ -334,7 +465,7 @@ func (s *Scorch) mergeSegmentBases(snapshot *IndexSnapshot,
|
|||
old: make(map[uint64]*SegmentSnapshot),
|
||||
oldNewDocNums: make(map[uint64][]uint64),
|
||||
new: seg,
|
||||
notify: make(chan *IndexSnapshot),
|
||||
notifyCh: make(chan *mergeTaskIntroStatus),
|
||||
}
|
||||
|
||||
for i, idx := range sbsIndexes {
|
||||
|
@ -351,11 +482,20 @@ func (s *Scorch) mergeSegmentBases(snapshot *IndexSnapshot,
|
|||
}
|
||||
|
||||
// blockingly wait for the introduction to complete
|
||||
newSnapshot := <-sm.notify
|
||||
if newSnapshot != nil {
|
||||
var newSnapshot *IndexSnapshot
|
||||
introStatus := <-sm.notifyCh
|
||||
if introStatus != nil && introStatus.indexSnapshot != nil {
|
||||
newSnapshot = introStatus.indexSnapshot
|
||||
atomic.AddUint64(&s.stats.TotMemMergeSegments, uint64(len(sbs)))
|
||||
atomic.AddUint64(&s.stats.TotMemMergeDone, 1)
|
||||
if introStatus.skipped {
|
||||
// close the segment on skipping introduction.
|
||||
_ = newSnapshot.DecRef()
|
||||
_ = seg.Close()
|
||||
newSnapshot = nil
|
||||
}
|
||||
}
|
||||
|
||||
return newSnapshot, newSegmentID, nil
|
||||
}
|
||||
|
||||
|
|
13
vendor/github.com/blevesearch/bleve/index/scorch/mergeplan/merge_plan.go
generated
vendored
13
vendor/github.com/blevesearch/bleve/index/scorch/mergeplan/merge_plan.go
generated
vendored
|
@ -134,6 +134,17 @@ var DefaultMergePlanOptions = MergePlanOptions{
|
|||
ReclaimDeletesWeight: 2.0,
|
||||
}
|
||||
|
||||
// SingleSegmentMergePlanOptions helps in creating a
|
||||
// single segment index.
|
||||
var SingleSegmentMergePlanOptions = MergePlanOptions{
|
||||
MaxSegmentsPerTier: 1,
|
||||
MaxSegmentSize: 1 << 30,
|
||||
TierGrowth: 1.0,
|
||||
SegmentsPerMergeTask: 10,
|
||||
FloorSegmentSize: 1 << 30,
|
||||
ReclaimDeletesWeight: 2.0,
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
func plan(segmentsIn []Segment, o *MergePlanOptions) (*MergePlan, error) {
|
||||
|
@ -173,7 +184,7 @@ func plan(segmentsIn []Segment, o *MergePlanOptions) (*MergePlan, error) {
|
|||
calcBudget = CalcBudget
|
||||
}
|
||||
|
||||
budgetNumSegments := CalcBudget(eligiblesLiveSize, minLiveSize, o)
|
||||
budgetNumSegments := calcBudget(eligiblesLiveSize, minLiveSize, o)
|
||||
|
||||
scoreSegments := o.ScoreSegments
|
||||
if scoreSegments == nil {
|
||||
|
|
60
vendor/github.com/blevesearch/bleve/index/scorch/optimize.go
generated
vendored
60
vendor/github.com/blevesearch/bleve/index/scorch/optimize.go
generated
vendored
|
@ -16,10 +16,10 @@ package scorch
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/index/scorch/segment"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var OptimizeConjunction = true
|
||||
|
@ -40,7 +40,7 @@ func (s *IndexSnapshotTermFieldReader) Optimize(kind string,
|
|||
return s.optimizeDisjunctionUnadorned(octx)
|
||||
}
|
||||
|
||||
return octx, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var OptimizeDisjunctionUnadornedMinChildCardinality = uint64(256)
|
||||
|
@ -161,16 +161,8 @@ func (o *OptimizeTFRConjunctionUnadorned) Finish() (rv index.Optimized, err erro
|
|||
|
||||
// We use an artificial term and field because the optimized
|
||||
// termFieldReader can represent multiple terms and fields.
|
||||
oTFR := &IndexSnapshotTermFieldReader{
|
||||
term: OptimizeTFRConjunctionUnadornedTerm,
|
||||
field: OptimizeTFRConjunctionUnadornedField,
|
||||
snapshot: o.snapshot,
|
||||
iterators: make([]segment.PostingsIterator, len(o.snapshot.segment)),
|
||||
segmentOffset: 0,
|
||||
includeFreq: false,
|
||||
includeNorm: false,
|
||||
includeTermVectors: false,
|
||||
}
|
||||
oTFR := o.snapshot.unadornedTermFieldReader(
|
||||
OptimizeTFRConjunctionUnadornedTerm, OptimizeTFRConjunctionUnadornedField)
|
||||
|
||||
var actualBMs []*roaring.Bitmap // Collected from regular posting lists.
|
||||
|
||||
|
@ -265,6 +257,7 @@ OUTER:
|
|||
oTFR.iterators[i] = segment.NewUnadornedPostingsIteratorFromBitmap(bm)
|
||||
}
|
||||
|
||||
atomic.AddUint64(&o.snapshot.parent.stats.TotTermSearchersStarted, uint64(1))
|
||||
return oTFR, nil
|
||||
}
|
||||
|
||||
|
@ -277,7 +270,9 @@ OUTER:
|
|||
func (s *IndexSnapshotTermFieldReader) optimizeDisjunctionUnadorned(
|
||||
octx index.OptimizableContext) (index.OptimizableContext, error) {
|
||||
if octx == nil {
|
||||
octx = &OptimizeTFRDisjunctionUnadorned{snapshot: s.snapshot}
|
||||
octx = &OptimizeTFRDisjunctionUnadorned{
|
||||
snapshot: s.snapshot,
|
||||
}
|
||||
}
|
||||
|
||||
o, ok := octx.(*OptimizeTFRDisjunctionUnadorned)
|
||||
|
@ -328,27 +323,12 @@ func (o *OptimizeTFRDisjunctionUnadorned) Finish() (rv index.Optimized, err erro
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Heuristic to skip the optimization if all the constituent
|
||||
// bitmaps are too small, where the processing & resource
|
||||
// overhead to create the OR'ed bitmap outweighs the benefit.
|
||||
if cMax < OptimizeDisjunctionUnadornedMinChildCardinality {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// We use an artificial term and field because the optimized
|
||||
// termFieldReader can represent multiple terms and fields.
|
||||
oTFR := &IndexSnapshotTermFieldReader{
|
||||
term: OptimizeTFRDisjunctionUnadornedTerm,
|
||||
field: OptimizeTFRDisjunctionUnadornedField,
|
||||
snapshot: o.snapshot,
|
||||
iterators: make([]segment.PostingsIterator, len(o.snapshot.segment)),
|
||||
segmentOffset: 0,
|
||||
includeFreq: false,
|
||||
includeNorm: false,
|
||||
includeTermVectors: false,
|
||||
}
|
||||
oTFR := o.snapshot.unadornedTermFieldReader(
|
||||
OptimizeTFRDisjunctionUnadornedTerm, OptimizeTFRDisjunctionUnadornedField)
|
||||
|
||||
var docNums []uint32 // Collected docNum's from 1-hit posting lists.
|
||||
var actualBMs []*roaring.Bitmap // Collected from regular posting lists.
|
||||
|
@ -392,5 +372,25 @@ func (o *OptimizeTFRDisjunctionUnadorned) Finish() (rv index.Optimized, err erro
|
|||
oTFR.iterators[i] = segment.NewUnadornedPostingsIteratorFromBitmap(bm)
|
||||
}
|
||||
|
||||
atomic.AddUint64(&o.snapshot.parent.stats.TotTermSearchersStarted, uint64(1))
|
||||
return oTFR, nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
func (i *IndexSnapshot) unadornedTermFieldReader(
|
||||
term []byte, field string) *IndexSnapshotTermFieldReader {
|
||||
// This IndexSnapshotTermFieldReader will not be recycled, more
|
||||
// conversation here: https://github.com/blevesearch/bleve/pull/1438
|
||||
return &IndexSnapshotTermFieldReader{
|
||||
term: term,
|
||||
field: field,
|
||||
snapshot: i,
|
||||
iterators: make([]segment.PostingsIterator, len(i.segment)),
|
||||
segmentOffset: 0,
|
||||
includeFreq: false,
|
||||
includeNorm: false,
|
||||
includeTermVectors: false,
|
||||
recycle: false,
|
||||
}
|
||||
}
|
||||
|
|
191
vendor/github.com/blevesearch/bleve/index/scorch/persister.go
generated
vendored
191
vendor/github.com/blevesearch/bleve/index/scorch/persister.go
generated
vendored
|
@ -256,7 +256,7 @@ func (s *Scorch) pausePersisterForMergerCatchUp(lastPersistedEpoch uint64,
|
|||
// for sufficient in-memory segments to pile up for the next
|
||||
// memory merge cum persist loop.
|
||||
if numFilesOnDisk < uint64(po.PersisterNapUnderNumFiles) &&
|
||||
po.PersisterNapTimeMSec > 0 && s.paused() == 0 {
|
||||
po.PersisterNapTimeMSec > 0 && s.NumEventsBlocking() == 0 {
|
||||
select {
|
||||
case <-s.closeCh:
|
||||
case <-time.After(time.Millisecond * time.Duration(po.PersisterNapTimeMSec)):
|
||||
|
@ -333,7 +333,7 @@ func (s *Scorch) persistSnapshot(snapshot *IndexSnapshot,
|
|||
// Perform in-memory segment merging only when the memory pressure is
|
||||
// below the configured threshold, else the persister performs the
|
||||
// direct persistence of segments.
|
||||
if s.paused() < po.MemoryPressurePauseThreshold {
|
||||
if s.NumEventsBlocking() < po.MemoryPressurePauseThreshold {
|
||||
persisted, err := s.persistSnapshotMaybeMerge(snapshot)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -428,6 +428,100 @@ func (s *Scorch) persistSnapshotMaybeMerge(snapshot *IndexSnapshot) (
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func prepareBoltSnapshot(snapshot *IndexSnapshot, tx *bolt.Tx, path string,
|
||||
segPlugin segment.Plugin) ([]string, map[uint64]string, error) {
|
||||
snapshotsBucket, err := tx.CreateBucketIfNotExists(boltSnapshotsBucket)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
newSnapshotKey := segment.EncodeUvarintAscending(nil, snapshot.epoch)
|
||||
snapshotBucket, err := snapshotsBucket.CreateBucketIfNotExists(newSnapshotKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// persist meta values
|
||||
metaBucket, err := snapshotBucket.CreateBucketIfNotExists(boltMetaDataKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
err = metaBucket.Put(boltMetaDataSegmentTypeKey, []byte(segPlugin.Type()))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
buf := make([]byte, binary.MaxVarintLen32)
|
||||
binary.BigEndian.PutUint32(buf, segPlugin.Version())
|
||||
err = metaBucket.Put(boltMetaDataSegmentVersionKey, buf)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// persist internal values
|
||||
internalBucket, err := snapshotBucket.CreateBucketIfNotExists(boltInternalKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// TODO optimize writing these in order?
|
||||
for k, v := range snapshot.internal {
|
||||
err = internalBucket.Put([]byte(k), v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var filenames []string
|
||||
newSegmentPaths := make(map[uint64]string)
|
||||
|
||||
// first ensure that each segment in this snapshot has been persisted
|
||||
for _, segmentSnapshot := range snapshot.segment {
|
||||
snapshotSegmentKey := segment.EncodeUvarintAscending(nil, segmentSnapshot.id)
|
||||
snapshotSegmentBucket, err := snapshotBucket.CreateBucketIfNotExists(snapshotSegmentKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
switch seg := segmentSnapshot.segment.(type) {
|
||||
case segment.PersistedSegment:
|
||||
segPath := seg.Path()
|
||||
filename := strings.TrimPrefix(segPath, path+string(os.PathSeparator))
|
||||
err = snapshotSegmentBucket.Put(boltPathKey, []byte(filename))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
filenames = append(filenames, filename)
|
||||
case segment.UnpersistedSegment:
|
||||
// need to persist this to disk
|
||||
filename := zapFileName(segmentSnapshot.id)
|
||||
path := path + string(os.PathSeparator) + filename
|
||||
err = seg.Persist(path)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error persisting segment: %v", err)
|
||||
}
|
||||
newSegmentPaths[segmentSnapshot.id] = path
|
||||
err = snapshotSegmentBucket.Put(boltPathKey, []byte(filename))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
filenames = append(filenames, filename)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unknown segment type: %T", seg)
|
||||
}
|
||||
// store current deleted bits
|
||||
var roaringBuf bytes.Buffer
|
||||
if segmentSnapshot.deleted != nil {
|
||||
_, err = segmentSnapshot.deleted.WriteTo(&roaringBuf)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error persisting roaring bytes: %v", err)
|
||||
}
|
||||
err = snapshotSegmentBucket.Put(boltDeletedKey, roaringBuf.Bytes())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filenames, newSegmentPaths, nil
|
||||
}
|
||||
|
||||
func (s *Scorch) persistSnapshotDirect(snapshot *IndexSnapshot) (err error) {
|
||||
// start a write transaction
|
||||
tx, err := s.rootBolt.Begin(true)
|
||||
|
@ -441,95 +535,10 @@ func (s *Scorch) persistSnapshotDirect(snapshot *IndexSnapshot) (err error) {
|
|||
}
|
||||
}()
|
||||
|
||||
snapshotsBucket, err := tx.CreateBucketIfNotExists(boltSnapshotsBucket)
|
||||
filenames, newSegmentPaths, err := prepareBoltSnapshot(snapshot, tx, s.path, s.segPlugin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newSnapshotKey := segment.EncodeUvarintAscending(nil, snapshot.epoch)
|
||||
snapshotBucket, err := snapshotsBucket.CreateBucketIfNotExists(newSnapshotKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// persist meta values
|
||||
metaBucket, err := snapshotBucket.CreateBucketIfNotExists(boltMetaDataKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = metaBucket.Put(boltMetaDataSegmentTypeKey, []byte(s.segPlugin.Type()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := make([]byte, binary.MaxVarintLen32)
|
||||
binary.BigEndian.PutUint32(buf, s.segPlugin.Version())
|
||||
err = metaBucket.Put(boltMetaDataSegmentVersionKey, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// persist internal values
|
||||
internalBucket, err := snapshotBucket.CreateBucketIfNotExists(boltInternalKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO optimize writing these in order?
|
||||
for k, v := range snapshot.internal {
|
||||
err = internalBucket.Put([]byte(k), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var filenames []string
|
||||
newSegmentPaths := make(map[uint64]string)
|
||||
|
||||
// first ensure that each segment in this snapshot has been persisted
|
||||
for _, segmentSnapshot := range snapshot.segment {
|
||||
snapshotSegmentKey := segment.EncodeUvarintAscending(nil, segmentSnapshot.id)
|
||||
snapshotSegmentBucket, err := snapshotBucket.CreateBucketIfNotExists(snapshotSegmentKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch seg := segmentSnapshot.segment.(type) {
|
||||
case segment.PersistedSegment:
|
||||
path := seg.Path()
|
||||
filename := strings.TrimPrefix(path, s.path+string(os.PathSeparator))
|
||||
err = snapshotSegmentBucket.Put(boltPathKey, []byte(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filenames = append(filenames, filename)
|
||||
case segment.UnpersistedSegment:
|
||||
// need to persist this to disk
|
||||
filename := zapFileName(segmentSnapshot.id)
|
||||
path := s.path + string(os.PathSeparator) + filename
|
||||
err = seg.Persist(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error persisting segment: %v", err)
|
||||
}
|
||||
newSegmentPaths[segmentSnapshot.id] = path
|
||||
err = snapshotSegmentBucket.Put(boltPathKey, []byte(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filenames = append(filenames, filename)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown segment type: %T", seg)
|
||||
}
|
||||
// store current deleted bits
|
||||
var roaringBuf bytes.Buffer
|
||||
if segmentSnapshot.deleted != nil {
|
||||
_, err = segmentSnapshot.deleted.WriteTo(&roaringBuf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error persisting roaring bytes: %v", err)
|
||||
}
|
||||
err = snapshotSegmentBucket.Put(boltDeletedKey, roaringBuf.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we need to swap in a new root only when we've persisted 1 or
|
||||
// more segments -- whereby the new root would have 1-for-1
|
||||
|
@ -780,12 +789,6 @@ func (s *Scorch) loadSegment(segmentBucket *bolt.Bucket) (*SegmentSnapshot, erro
|
|||
return rv, nil
|
||||
}
|
||||
|
||||
type uint64Descending []uint64
|
||||
|
||||
func (p uint64Descending) Len() int { return len(p) }
|
||||
func (p uint64Descending) Less(i, j int) bool { return p[i] > p[j] }
|
||||
func (p uint64Descending) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
|
||||
func (s *Scorch) removeOldData() {
|
||||
removed, err := s.removeOldBoltSnapshots()
|
||||
if err != nil {
|
||||
|
|
64
vendor/github.com/blevesearch/bleve/index/scorch/scorch.go
generated
vendored
64
vendor/github.com/blevesearch/bleve/index/scorch/scorch.go
generated
vendored
|
@ -73,9 +73,7 @@ type Scorch struct {
|
|||
onEvent func(event Event)
|
||||
onAsyncError func(err error)
|
||||
|
||||
pauseLock sync.RWMutex
|
||||
|
||||
pauseCount uint64
|
||||
forceMergeRequestCh chan *mergerCtrl
|
||||
|
||||
segPlugin segment.Plugin
|
||||
}
|
||||
|
@ -101,18 +99,15 @@ func NewScorch(storeName string,
|
|||
nextSnapshotEpoch: 1,
|
||||
closeCh: make(chan struct{}),
|
||||
ineligibleForRemoval: map[string]bool{},
|
||||
forceMergeRequestCh: make(chan *mergerCtrl, 1),
|
||||
segPlugin: defaultSegmentPlugin,
|
||||
}
|
||||
|
||||
// check if the caller has requested a specific segment type/version
|
||||
forcedSegmentVersion, ok := config["forceSegmentVersion"].(int)
|
||||
if ok {
|
||||
forcedSegmentType, ok2 := config["forceSegmentType"].(string)
|
||||
if !ok2 {
|
||||
return nil, fmt.Errorf(
|
||||
"forceSegmentVersion set to %d, must also specify forceSegmentType", forcedSegmentVersion)
|
||||
}
|
||||
|
||||
forcedSegmentType, forcedSegmentVersion, err := configForceSegmentTypeVersion(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if forcedSegmentType != "" && forcedSegmentVersion != 0 {
|
||||
err := rv.loadSegmentPlugin(forcedSegmentType,
|
||||
uint32(forcedSegmentVersion))
|
||||
if err != nil {
|
||||
|
@ -140,30 +135,34 @@ func NewScorch(storeName string,
|
|||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *Scorch) paused() uint64 {
|
||||
s.pauseLock.Lock()
|
||||
pc := s.pauseCount
|
||||
s.pauseLock.Unlock()
|
||||
return pc
|
||||
// configForceSegmentTypeVersion checks if the caller has requested a
|
||||
// specific segment type/version
|
||||
func configForceSegmentTypeVersion(config map[string]interface{}) (string, uint32, error) {
|
||||
forcedSegmentVersion, err := parseToInteger(config["forceSegmentVersion"])
|
||||
if err != nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
|
||||
forcedSegmentType, ok := config["forceSegmentType"].(string)
|
||||
if !ok {
|
||||
return "", 0, fmt.Errorf(
|
||||
"forceSegmentVersion set to %d, must also specify forceSegmentType", forcedSegmentVersion)
|
||||
}
|
||||
|
||||
return forcedSegmentType, uint32(forcedSegmentVersion), nil
|
||||
}
|
||||
|
||||
func (s *Scorch) incrPause() {
|
||||
s.pauseLock.Lock()
|
||||
s.pauseCount++
|
||||
s.pauseLock.Unlock()
|
||||
}
|
||||
|
||||
func (s *Scorch) decrPause() {
|
||||
s.pauseLock.Lock()
|
||||
s.pauseCount--
|
||||
s.pauseLock.Unlock()
|
||||
func (s *Scorch) NumEventsBlocking() uint64 {
|
||||
eventsCompleted := atomic.LoadUint64(&s.stats.TotEventTriggerCompleted)
|
||||
eventsStarted := atomic.LoadUint64(&s.stats.TotEventTriggerStarted)
|
||||
return eventsStarted - eventsCompleted
|
||||
}
|
||||
|
||||
func (s *Scorch) fireEvent(kind EventKind, dur time.Duration) {
|
||||
if s.onEvent != nil {
|
||||
s.incrPause()
|
||||
atomic.AddUint64(&s.stats.TotEventTriggerStarted, 1)
|
||||
s.onEvent(Event{Kind: kind, Scorch: s, Duration: dur})
|
||||
s.decrPause()
|
||||
atomic.AddUint64(&s.stats.TotEventTriggerCompleted, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +180,7 @@ func (s *Scorch) Open() error {
|
|||
}
|
||||
|
||||
s.asyncTasks.Add(1)
|
||||
go s.mainLoop()
|
||||
go s.introducerLoop()
|
||||
|
||||
if !s.readOnly && s.path != "" {
|
||||
s.asyncTasks.Add(1)
|
||||
|
@ -241,6 +240,7 @@ func (s *Scorch) openBolt() error {
|
|||
s.introducerNotifier = make(chan *epochWatcher, 1)
|
||||
s.persisterNotifier = make(chan *epochWatcher, 1)
|
||||
s.closeCh = make(chan struct{})
|
||||
s.forceMergeRequestCh = make(chan *mergerCtrl, 1)
|
||||
|
||||
if !s.readOnly && s.path != "" {
|
||||
err := s.removeOldZapFiles() // Before persister or merger create any new files.
|
||||
|
@ -567,6 +567,10 @@ func (s *Scorch) StatsMap() map[string]interface{} {
|
|||
}
|
||||
|
||||
func (s *Scorch) Analyze(d *document.Document) *index.AnalysisResult {
|
||||
return analyze(d)
|
||||
}
|
||||
|
||||
func analyze(d *document.Document) *index.AnalysisResult {
|
||||
rv := &index.AnalysisResult{
|
||||
Document: d,
|
||||
Analyzed: make([]analysis.TokenFrequencies, len(d.Fields)+len(d.CompositeFields)),
|
||||
|
|
22
vendor/github.com/blevesearch/bleve/index/scorch/segment/unadorned.go
generated
vendored
22
vendor/github.com/blevesearch/bleve/index/scorch/segment/unadorned.go
generated
vendored
|
@ -24,7 +24,6 @@ var reflectStaticSizeUnadornedPostingsIteratorBitmap int
|
|||
var reflectStaticSizeUnadornedPostingsIterator1Hit int
|
||||
var reflectStaticSizeUnadornedPosting int
|
||||
|
||||
|
||||
func init() {
|
||||
var pib UnadornedPostingsIteratorBitmap
|
||||
reflectStaticSizeUnadornedPostingsIteratorBitmap = int(reflect.TypeOf(pib).Size())
|
||||
|
@ -34,7 +33,7 @@ func init() {
|
|||
reflectStaticSizeUnadornedPosting = int(reflect.TypeOf(up).Size())
|
||||
}
|
||||
|
||||
type UnadornedPostingsIteratorBitmap struct{
|
||||
type UnadornedPostingsIteratorBitmap struct {
|
||||
actual roaring.IntPeekable
|
||||
actualBM *roaring.Bitmap
|
||||
}
|
||||
|
@ -72,16 +71,29 @@ func (i *UnadornedPostingsIteratorBitmap) Size() int {
|
|||
return reflectStaticSizeUnadornedPostingsIteratorBitmap
|
||||
}
|
||||
|
||||
func (i *UnadornedPostingsIteratorBitmap) ActualBitmap() *roaring.Bitmap {
|
||||
return i.actualBM
|
||||
}
|
||||
|
||||
func (i *UnadornedPostingsIteratorBitmap) DocNum1Hit() (uint64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (i *UnadornedPostingsIteratorBitmap) ReplaceActual(actual *roaring.Bitmap) {
|
||||
i.actualBM = actual
|
||||
i.actual = actual.Iterator()
|
||||
}
|
||||
|
||||
func NewUnadornedPostingsIteratorFromBitmap(bm *roaring.Bitmap) PostingsIterator {
|
||||
return &UnadornedPostingsIteratorBitmap{
|
||||
actualBM: bm,
|
||||
actual: bm.Iterator(),
|
||||
actual: bm.Iterator(),
|
||||
}
|
||||
}
|
||||
|
||||
const docNum1HitFinished = math.MaxUint64
|
||||
|
||||
type UnadornedPostingsIterator1Hit struct{
|
||||
type UnadornedPostingsIterator1Hit struct {
|
||||
docNum uint64
|
||||
}
|
||||
|
||||
|
@ -145,4 +157,4 @@ func (p UnadornedPosting) Locations() []Location {
|
|||
|
||||
func (p UnadornedPosting) Size() int {
|
||||
return reflectStaticSizeUnadornedPosting
|
||||
}
|
||||
}
|
||||
|
|
26
vendor/github.com/blevesearch/bleve/index/scorch/segment_plugin.go
generated
vendored
26
vendor/github.com/blevesearch/bleve/index/scorch/segment_plugin.go
generated
vendored
|
@ -21,6 +21,8 @@ import (
|
|||
|
||||
zapv11 "github.com/blevesearch/zap/v11"
|
||||
zapv12 "github.com/blevesearch/zap/v12"
|
||||
zapv13 "github.com/blevesearch/zap/v13"
|
||||
zapv14 "github.com/blevesearch/zap/v14"
|
||||
)
|
||||
|
||||
var supportedSegmentPlugins map[string]map[uint32]segment.Plugin
|
||||
|
@ -28,6 +30,8 @@ var defaultSegmentPlugin segment.Plugin
|
|||
|
||||
func init() {
|
||||
ResetPlugins()
|
||||
RegisterPlugin(zapv14.Plugin(), false)
|
||||
RegisterPlugin(zapv13.Plugin(), false)
|
||||
RegisterPlugin(zapv12.Plugin(), false)
|
||||
RegisterPlugin(zapv11.Plugin(), true)
|
||||
}
|
||||
|
@ -60,18 +64,28 @@ func SupportedSegmentTypeVersions(typ string) (rv []uint32) {
|
|||
return rv
|
||||
}
|
||||
|
||||
func (s *Scorch) loadSegmentPlugin(forcedSegmentType string,
|
||||
forcedSegmentVersion uint32) error {
|
||||
func chooseSegmentPlugin(forcedSegmentType string,
|
||||
forcedSegmentVersion uint32) (segment.Plugin, error) {
|
||||
if versions, ok := supportedSegmentPlugins[forcedSegmentType]; ok {
|
||||
if segPlugin, ok := versions[uint32(forcedSegmentVersion)]; ok {
|
||||
s.segPlugin = segPlugin
|
||||
return nil
|
||||
return segPlugin, nil
|
||||
}
|
||||
return fmt.Errorf(
|
||||
return nil, fmt.Errorf(
|
||||
"unsupported version %d for segment type: %s, supported: %v",
|
||||
forcedSegmentVersion, forcedSegmentType,
|
||||
SupportedSegmentTypeVersions(forcedSegmentType))
|
||||
}
|
||||
return fmt.Errorf("unsupported segment type: %s, supported: %v",
|
||||
return nil, fmt.Errorf("unsupported segment type: %s, supported: %v",
|
||||
forcedSegmentType, SupportedSegmentTypes())
|
||||
}
|
||||
|
||||
func (s *Scorch) loadSegmentPlugin(forcedSegmentType string,
|
||||
forcedSegmentVersion uint32) error {
|
||||
segPlugin, err := chooseSegmentPlugin(forcedSegmentType,
|
||||
forcedSegmentVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.segPlugin = segPlugin
|
||||
return nil
|
||||
}
|
||||
|
|
21
vendor/github.com/blevesearch/bleve/index/scorch/snapshot_index.go
generated
vendored
21
vendor/github.com/blevesearch/bleve/index/scorch/snapshot_index.go
generated
vendored
|
@ -303,9 +303,12 @@ func (i *IndexSnapshot) newDocIDReader(results chan *asynchSegmentResult) (index
|
|||
var err error
|
||||
for count := 0; count < len(i.segment); count++ {
|
||||
asr := <-results
|
||||
if asr.err != nil && err != nil {
|
||||
err = asr.err
|
||||
} else {
|
||||
if asr.err != nil {
|
||||
if err == nil {
|
||||
// returns the first error encountered
|
||||
err = asr.err
|
||||
}
|
||||
} else if err == nil {
|
||||
rv.iterators[asr.index] = asr.docs.Iterator()
|
||||
}
|
||||
}
|
||||
|
@ -511,10 +514,20 @@ func (i *IndexSnapshot) allocTermFieldReaderDicts(field string) (tfr *IndexSnaps
|
|||
}
|
||||
}
|
||||
i.m2.Unlock()
|
||||
return &IndexSnapshotTermFieldReader{}
|
||||
return &IndexSnapshotTermFieldReader{
|
||||
recycle: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IndexSnapshot) recycleTermFieldReader(tfr *IndexSnapshotTermFieldReader) {
|
||||
if !tfr.recycle {
|
||||
// Do not recycle an optimized unadorned term field reader (used for
|
||||
// ConjunctionUnadorned or DisjunctionUnadorned), during when a fresh
|
||||
// roaring.Bitmap is built by AND-ing or OR-ing individual bitmaps,
|
||||
// and we'll need to release them for GC. (See MB-40916)
|
||||
return
|
||||
}
|
||||
|
||||
i.parent.rootLock.RLock()
|
||||
obsolete := i.parent.root != i
|
||||
i.parent.rootLock.RUnlock()
|
||||
|
|
3
vendor/github.com/blevesearch/bleve/index/scorch/snapshot_index_tfr.go
generated
vendored
3
vendor/github.com/blevesearch/bleve/index/scorch/snapshot_index_tfr.go
generated
vendored
|
@ -45,6 +45,7 @@ type IndexSnapshotTermFieldReader struct {
|
|||
includeTermVectors bool
|
||||
currPosting segment.Posting
|
||||
currID index.IndexInternalID
|
||||
recycle bool
|
||||
}
|
||||
|
||||
func (i *IndexSnapshotTermFieldReader) Size() int {
|
||||
|
@ -133,6 +134,8 @@ func (i *IndexSnapshotTermFieldReader) Advance(ID index.IndexInternalID, preAllo
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// close the current term field reader before replacing it with a new one
|
||||
_ = i.Close()
|
||||
*i = *(i2.(*IndexSnapshotTermFieldReader))
|
||||
}
|
||||
num, err := docInternalToNumber(ID)
|
||||
|
|
13
vendor/github.com/blevesearch/bleve/index/scorch/stats.go
generated
vendored
13
vendor/github.com/blevesearch/bleve/index/scorch/stats.go
generated
vendored
|
@ -47,6 +47,9 @@ type Stats struct {
|
|||
TotTermSearchersStarted uint64
|
||||
TotTermSearchersFinished uint64
|
||||
|
||||
TotEventTriggerStarted uint64
|
||||
TotEventTriggerCompleted uint64
|
||||
|
||||
TotIntroduceLoop uint64
|
||||
TotIntroduceSegmentBeg uint64
|
||||
TotIntroduceSegmentEnd uint64
|
||||
|
@ -82,6 +85,9 @@ type Stats struct {
|
|||
TotFileMergeLoopErr uint64
|
||||
TotFileMergeLoopEnd uint64
|
||||
|
||||
TotFileMergeForceOpsStarted uint64
|
||||
TotFileMergeForceOpsCompleted uint64
|
||||
|
||||
TotFileMergePlan uint64
|
||||
TotFileMergePlanErr uint64
|
||||
TotFileMergePlanNone uint64
|
||||
|
@ -105,9 +111,10 @@ type Stats struct {
|
|||
TotFileMergeZapIntroductionTime uint64
|
||||
MaxFileMergeZapIntroductionTime uint64
|
||||
|
||||
TotFileMergeIntroductions uint64
|
||||
TotFileMergeIntroductionsDone uint64
|
||||
TotFileMergeIntroductionsSkipped uint64
|
||||
TotFileMergeIntroductions uint64
|
||||
TotFileMergeIntroductionsDone uint64
|
||||
TotFileMergeIntroductionsSkipped uint64
|
||||
TotFileMergeIntroductionsObsoleted uint64
|
||||
|
||||
CurFilesIneligibleForRemoval uint64
|
||||
TotSnapshotsRemovedFromMetaStore uint64
|
||||
|
|
16
vendor/github.com/blevesearch/bleve/index_alias_impl.go
generated
vendored
16
vendor/github.com/blevesearch/bleve/index_alias_impl.go
generated
vendored
|
@ -16,7 +16,6 @@ package bleve
|
|||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -44,6 +43,16 @@ func NewIndexAlias(indexes ...Index) *indexAliasImpl {
|
|||
}
|
||||
}
|
||||
|
||||
// VisitIndexes invokes the visit callback on every
|
||||
// indexes included in the index alias.
|
||||
func (i *indexAliasImpl) VisitIndexes(visit func(Index)) {
|
||||
i.mutex.RLock()
|
||||
for _, idx := range i.indexes {
|
||||
visit(idx)
|
||||
}
|
||||
i.mutex.RUnlock()
|
||||
}
|
||||
|
||||
func (i *indexAliasImpl) isAliasToSingleIndex() error {
|
||||
if len(i.indexes) < 1 {
|
||||
return ErrorAliasEmpty
|
||||
|
@ -511,10 +520,11 @@ func MultiSearch(ctx context.Context, req *SearchRequest, indexes ...Index) (*Se
|
|||
}
|
||||
}
|
||||
|
||||
sortFunc := req.SortFunc()
|
||||
// sort all hits with the requested order
|
||||
if len(req.Sort) > 0 {
|
||||
sorter := newSearchHitSorter(req.Sort, sr.Hits)
|
||||
sort.Sort(sorter)
|
||||
sortFunc(sorter)
|
||||
}
|
||||
|
||||
// now skip over the correct From
|
||||
|
@ -539,7 +549,7 @@ func MultiSearch(ctx context.Context, req *SearchRequest, indexes ...Index) (*Se
|
|||
req.Sort.Reverse()
|
||||
// resort using the original order
|
||||
mhs := newSearchHitSorter(req.Sort, sr.Hits)
|
||||
sort.Sort(mhs)
|
||||
sortFunc(mhs)
|
||||
// reset request
|
||||
req.SearchBefore = req.SearchAfter
|
||||
req.SearchAfter = nil
|
||||
|
|
3
vendor/github.com/blevesearch/bleve/index_impl.go
generated
vendored
3
vendor/github.com/blevesearch/bleve/index_impl.go
generated
vendored
|
@ -19,7 +19,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -579,7 +578,7 @@ func (i *indexImpl) SearchInContext(ctx context.Context, req *SearchRequest) (sr
|
|||
req.Sort.Reverse()
|
||||
// resort using the original order
|
||||
mhs := newSearchHitSorter(req.Sort, hits)
|
||||
sort.Sort(mhs)
|
||||
req.SortFunc()(mhs)
|
||||
// reset request
|
||||
req.SearchBefore = req.SearchAfter
|
||||
req.SearchAfter = nil
|
||||
|
|
3
vendor/github.com/blevesearch/bleve/mapping/document.go
generated
vendored
3
vendor/github.com/blevesearch/bleve/mapping/document.go
generated
vendored
|
@ -251,7 +251,6 @@ func (dm *DocumentMapping) AddFieldMapping(fm *FieldMapping) {
|
|||
|
||||
// UnmarshalJSON offers custom unmarshaling with optional strict validation
|
||||
func (dm *DocumentMapping) UnmarshalJSON(data []byte) error {
|
||||
|
||||
var tmp map[string]json.RawMessage
|
||||
err := json.Unmarshal(data, &tmp)
|
||||
if err != nil {
|
||||
|
@ -308,8 +307,8 @@ func (dm *DocumentMapping) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
|
||||
func (dm *DocumentMapping) defaultAnalyzerName(path []string) string {
|
||||
rv := ""
|
||||
current := dm
|
||||
rv := current.DefaultAnalyzer
|
||||
for _, pathElement := range path {
|
||||
var ok bool
|
||||
current, ok = current.Properties[pathElement]
|
||||
|
|
16
vendor/github.com/blevesearch/bleve/mapping/index.go
generated
vendored
16
vendor/github.com/blevesearch/bleve/mapping/index.go
generated
vendored
|
@ -101,26 +101,26 @@ func (im *IndexMappingImpl) AddCustomTokenFilter(name string, config map[string]
|
|||
// returned analyzer is registered in the IndexMapping.
|
||||
//
|
||||
// bleve comes with predefined analyzers, like
|
||||
// github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer. They are
|
||||
// github.com/blevesearch/bleve/analysis/analyzer/custom. They are
|
||||
// available only if their package is imported by client code. To achieve this,
|
||||
// use their metadata to fill configuration entries:
|
||||
//
|
||||
// import (
|
||||
// "github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer"
|
||||
// "github.com/blevesearch/bleve/analysis/char_filters/html_char_filter"
|
||||
// "github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter"
|
||||
// "github.com/blevesearch/bleve/analysis/tokenizers/unicode"
|
||||
// "github.com/blevesearch/bleve/analysis/analyzer/custom"
|
||||
// "github.com/blevesearch/bleve/analysis/char/html"
|
||||
// "github.com/blevesearch/bleve/analysis/token/lowercase"
|
||||
// "github.com/blevesearch/bleve/analysis/tokenizer/unicode"
|
||||
// )
|
||||
//
|
||||
// m := bleve.NewIndexMapping()
|
||||
// err := m.AddCustomAnalyzer("html", map[string]interface{}{
|
||||
// "type": custom_analyzer.Name,
|
||||
// "type": custom.Name,
|
||||
// "char_filters": []string{
|
||||
// html_char_filter.Name,
|
||||
// html.Name,
|
||||
// },
|
||||
// "tokenizer": unicode.Name,
|
||||
// "token_filters": []string{
|
||||
// lower_case_filter.Name,
|
||||
// lowercase.Name,
|
||||
// ...
|
||||
// },
|
||||
// })
|
||||
|
|
23
vendor/github.com/blevesearch/bleve/search.go
generated
vendored
23
vendor/github.com/blevesearch/bleve/search.go
generated
vendored
|
@ -18,6 +18,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/blevesearch/bleve/analysis"
|
||||
|
@ -264,6 +265,7 @@ func (h *HighlightRequest) AddField(field string) {
|
|||
// Score controls the kind of scoring performed
|
||||
// SearchAfter supports deep paging by providing a minimum sort key
|
||||
// SearchBefore supports deep paging by providing a maximum sort key
|
||||
// sortFunc specifies the sort implementation to use for sorting results.
|
||||
//
|
||||
// A special field named "*" can be used to return all fields.
|
||||
type SearchRequest struct {
|
||||
|
@ -279,6 +281,8 @@ type SearchRequest struct {
|
|||
Score string `json:"score,omitempty"`
|
||||
SearchAfter []string `json:"search_after"`
|
||||
SearchBefore []string `json:"search_before"`
|
||||
|
||||
sortFunc func(sort.Interface)
|
||||
}
|
||||
|
||||
func (r *SearchRequest) Validate() error {
|
||||
|
@ -606,3 +610,22 @@ func MemoryNeededForSearchResult(req *SearchRequest) uint64 {
|
|||
|
||||
return uint64(estimate)
|
||||
}
|
||||
|
||||
// SetSortFunc sets the sort implementation to use when sorting hits.
|
||||
//
|
||||
// SearchRequests can specify a custom sort implementation to meet
|
||||
// their needs. For instance, by specifying a parallel sort
|
||||
// that uses all available cores.
|
||||
func (r *SearchRequest) SetSortFunc(s func(sort.Interface)) {
|
||||
r.sortFunc = s
|
||||
}
|
||||
|
||||
// SortFunc returns the sort implementation to use when sorting hits.
|
||||
// Defaults to sort.Sort.
|
||||
func (r *SearchRequest) SortFunc() func(data sort.Interface) {
|
||||
if r.sortFunc != nil {
|
||||
return r.sortFunc
|
||||
}
|
||||
|
||||
return sort.Sort
|
||||
}
|
||||
|
|
14
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction.go
generated
vendored
14
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction.go
generated
vendored
|
@ -16,7 +16,6 @@ package searcher
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
@ -37,6 +36,11 @@ func NewDisjunctionSearcher(indexReader index.IndexReader,
|
|||
return newDisjunctionSearcher(indexReader, qsearchers, min, options, true)
|
||||
}
|
||||
|
||||
func optionsDisjunctionOptimizable(options search.SearcherOptions) bool {
|
||||
rv := options.Score == "none" && !options.IncludeTermVectors
|
||||
return rv
|
||||
}
|
||||
|
||||
func newDisjunctionSearcher(indexReader index.IndexReader,
|
||||
qsearchers []search.Searcher, min float64, options search.SearcherOptions,
|
||||
limit bool) (search.Searcher, error) {
|
||||
|
@ -44,7 +48,7 @@ func newDisjunctionSearcher(indexReader index.IndexReader,
|
|||
// do not need extra information like freq-norm's or term vectors
|
||||
// and the requested min is simple
|
||||
if len(qsearchers) > 1 && min <= 1 &&
|
||||
options.Score == "none" && !options.IncludeTermVectors {
|
||||
optionsDisjunctionOptimizable(options) {
|
||||
rv, err := optimizeCompositeSearcher("disjunction:unadorned",
|
||||
indexReader, qsearchers, options)
|
||||
if err != nil || rv != nil {
|
||||
|
@ -103,7 +107,7 @@ func tooManyClauses(count int) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func tooManyClausesErr(count int) error {
|
||||
return fmt.Errorf("TooManyClauses[%d > maxClauseCount, which is set to %d]",
|
||||
count, DisjunctionMaxClauseCount)
|
||||
func tooManyClausesErr(field string, count int) error {
|
||||
return fmt.Errorf("TooManyClauses over field: `%s` [%d > maxClauseCount,"+
|
||||
" which is set to %d]", field, count, DisjunctionMaxClauseCount)
|
||||
}
|
||||
|
|
4
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction_heap.go
generated
vendored
4
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction_heap.go
generated
vendored
|
@ -62,7 +62,7 @@ func newDisjunctionHeapSearcher(indexReader index.IndexReader,
|
|||
limit bool) (
|
||||
*DisjunctionHeapSearcher, error) {
|
||||
if limit && tooManyClauses(len(searchers)) {
|
||||
return nil, tooManyClausesErr(len(searchers))
|
||||
return nil, tooManyClausesErr("", len(searchers))
|
||||
}
|
||||
|
||||
// build our searcher
|
||||
|
@ -310,7 +310,7 @@ func (s *DisjunctionHeapSearcher) Optimize(kind string, octx index.OptimizableCo
|
|||
}
|
||||
}
|
||||
|
||||
return octx, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// heap impl
|
||||
|
|
4
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction_slice.go
generated
vendored
4
vendor/github.com/blevesearch/bleve/search/searcher/search_disjunction_slice.go
generated
vendored
|
@ -50,7 +50,7 @@ func newDisjunctionSliceSearcher(indexReader index.IndexReader,
|
|||
limit bool) (
|
||||
*DisjunctionSliceSearcher, error) {
|
||||
if limit && tooManyClauses(len(qsearchers)) {
|
||||
return nil, tooManyClausesErr(len(qsearchers))
|
||||
return nil, tooManyClausesErr("", len(qsearchers))
|
||||
}
|
||||
// build the downstream searchers
|
||||
searchers := make(OrderedSearcherList, len(qsearchers))
|
||||
|
@ -294,5 +294,5 @@ func (s *DisjunctionSliceSearcher) Optimize(kind string, octx index.OptimizableC
|
|||
}
|
||||
}
|
||||
|
||||
return octx, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
4
vendor/github.com/blevesearch/bleve/search/searcher/search_fuzzy.go
generated
vendored
4
vendor/github.com/blevesearch/bleve/search/searcher/search_fuzzy.go
generated
vendored
|
@ -75,7 +75,7 @@ func findFuzzyCandidateTerms(indexReader index.IndexReader, term string,
|
|||
for err == nil && tfd != nil {
|
||||
rv = append(rv, tfd.Term)
|
||||
if tooManyClauses(len(rv)) {
|
||||
return nil, tooManyClausesErr(len(rv))
|
||||
return nil, tooManyClausesErr(field, len(rv))
|
||||
}
|
||||
tfd, err = fieldDict.Next()
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ func findFuzzyCandidateTerms(indexReader index.IndexReader, term string,
|
|||
if !exceeded && ld <= fuzziness {
|
||||
rv = append(rv, tfd.Term)
|
||||
if tooManyClauses(len(rv)) {
|
||||
return nil, tooManyClausesErr(len(rv))
|
||||
return nil, tooManyClausesErr(field, len(rv))
|
||||
}
|
||||
}
|
||||
tfd, err = fieldDict.Next()
|
||||
|
|
188
vendor/github.com/blevesearch/bleve/search/searcher/search_geoboundingbox.go
generated
vendored
188
vendor/github.com/blevesearch/bleve/search/searcher/search_geoboundingbox.go
generated
vendored
|
@ -24,7 +24,7 @@ import (
|
|||
|
||||
type filterFunc func(key []byte) bool
|
||||
|
||||
var GeoBitsShift1 = (geo.GeoBits << 1)
|
||||
var GeoBitsShift1 = geo.GeoBits << 1
|
||||
var GeoBitsShift1Minus1 = GeoBitsShift1 - 1
|
||||
|
||||
func NewGeoBoundingBoxSearcher(indexReader index.IndexReader, minLon, minLat,
|
||||
|
@ -100,30 +100,42 @@ func NewGeoBoundingBoxSearcher(indexReader index.IndexReader, minLon, minLat,
|
|||
|
||||
var geoMaxShift = document.GeoPrecisionStep * 4
|
||||
var geoDetailLevel = ((geo.GeoBits << 1) - geoMaxShift) / 2
|
||||
type closeFunc func() error
|
||||
|
||||
func ComputeGeoRange(term uint64, shift uint,
|
||||
sminLon, sminLat, smaxLon, smaxLat float64, checkBoundaries bool,
|
||||
indexReader index.IndexReader, field string) (
|
||||
onBoundary [][]byte, notOnBoundary [][]byte, err error) {
|
||||
preallocBytesLen := 32
|
||||
preallocBytes := make([]byte, preallocBytesLen)
|
||||
|
||||
makePrefixCoded := func(in int64, shift uint) (rv numeric.PrefixCoded) {
|
||||
if len(preallocBytes) <= 0 {
|
||||
preallocBytesLen = preallocBytesLen * 2
|
||||
preallocBytes = make([]byte, preallocBytesLen)
|
||||
}
|
||||
|
||||
rv, preallocBytes, err =
|
||||
numeric.NewPrefixCodedInt64Prealloc(in, shift, preallocBytes)
|
||||
|
||||
return rv
|
||||
isIndexed, closeF, err := buildIsIndexedFunc(indexReader, field)
|
||||
if closeF != nil {
|
||||
defer func() {
|
||||
cerr := closeF()
|
||||
if cerr != nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var fieldDict index.FieldDictContains
|
||||
var isIndexed filterFunc
|
||||
grc := &geoRangeCompute{
|
||||
preallocBytesLen: 32,
|
||||
preallocBytes: make([]byte, 32),
|
||||
sminLon: sminLon,
|
||||
sminLat: sminLat,
|
||||
smaxLon: smaxLon,
|
||||
smaxLat: smaxLat,
|
||||
checkBoundaries: checkBoundaries,
|
||||
isIndexed: isIndexed,
|
||||
}
|
||||
|
||||
grc.computeGeoRange(term, shift)
|
||||
|
||||
return grc.onBoundary, grc.notOnBoundary, nil
|
||||
}
|
||||
|
||||
func buildIsIndexedFunc(indexReader index.IndexReader, field string) (isIndexed filterFunc, closeF closeFunc, err error) {
|
||||
if irr, ok := indexReader.(index.IndexReaderContains); ok {
|
||||
fieldDict, err = irr.FieldDictContains(field)
|
||||
fieldDict, err := irr.FieldDictContains(field)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -132,22 +144,18 @@ func ComputeGeoRange(term uint64, shift uint,
|
|||
found, err := fieldDict.Contains(term)
|
||||
return err == nil && found
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if fieldDict != nil {
|
||||
closeF = func() error {
|
||||
if fd, ok := fieldDict.(index.FieldDict); ok {
|
||||
cerr := fd.Close()
|
||||
if cerr != nil {
|
||||
err = cerr
|
||||
err := fd.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
if isIndexed == nil {
|
||||
} else if indexReader != nil {
|
||||
isIndexed = func(term []byte) bool {
|
||||
if indexReader != nil {
|
||||
reader, err := indexReader.TermFieldReader(term, field, false, false, false)
|
||||
if err != nil || reader == nil {
|
||||
return false
|
||||
|
@ -157,68 +165,15 @@ func ComputeGeoRange(term uint64, shift uint,
|
|||
return false
|
||||
}
|
||||
_ = reader.Close()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
} else {
|
||||
isIndexed = func([]byte) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var computeGeoRange func(term uint64, shift uint) // declare for recursion
|
||||
|
||||
relateAndRecurse := func(start, end uint64, res, level uint) {
|
||||
minLon := geo.MortonUnhashLon(start)
|
||||
minLat := geo.MortonUnhashLat(start)
|
||||
maxLon := geo.MortonUnhashLon(end)
|
||||
maxLat := geo.MortonUnhashLat(end)
|
||||
|
||||
within := res%document.GeoPrecisionStep == 0 &&
|
||||
geo.RectWithin(minLon, minLat, maxLon, maxLat,
|
||||
sminLon, sminLat, smaxLon, smaxLat)
|
||||
if within || (level == geoDetailLevel &&
|
||||
geo.RectIntersects(minLon, minLat, maxLon, maxLat,
|
||||
sminLon, sminLat, smaxLon, smaxLat)) {
|
||||
codedTerm := makePrefixCoded(int64(start), res)
|
||||
if isIndexed(codedTerm) {
|
||||
if !within && checkBoundaries {
|
||||
onBoundary = append(onBoundary, codedTerm)
|
||||
} else {
|
||||
notOnBoundary = append(notOnBoundary, codedTerm)
|
||||
}
|
||||
}
|
||||
} else if level < geoDetailLevel &&
|
||||
geo.RectIntersects(minLon, minLat, maxLon, maxLat,
|
||||
sminLon, sminLat, smaxLon, smaxLat) {
|
||||
computeGeoRange(start, res-1)
|
||||
}
|
||||
}
|
||||
|
||||
computeGeoRange = func(term uint64, shift uint) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
split := term | uint64(0x1)<<shift
|
||||
var upperMax uint64
|
||||
if shift < 63 {
|
||||
upperMax = term | ((uint64(1) << (shift + 1)) - 1)
|
||||
} else {
|
||||
upperMax = 0xffffffffffffffff
|
||||
}
|
||||
|
||||
lowerMax := split - 1
|
||||
|
||||
level := (GeoBitsShift1 - shift) >> 1
|
||||
|
||||
relateAndRecurse(term, lowerMax, shift, level)
|
||||
relateAndRecurse(split, upperMax, shift, level)
|
||||
}
|
||||
|
||||
computeGeoRange(term, shift)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return onBoundary, notOnBoundary, err
|
||||
return isIndexed, closeF, err
|
||||
}
|
||||
|
||||
func buildRectFilter(dvReader index.DocValueReader, field string,
|
||||
|
@ -252,3 +207,66 @@ func buildRectFilter(dvReader index.DocValueReader, field string,
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type geoRangeCompute struct {
|
||||
preallocBytesLen int
|
||||
preallocBytes []byte
|
||||
sminLon, sminLat, smaxLon, smaxLat float64
|
||||
checkBoundaries bool
|
||||
onBoundary, notOnBoundary [][]byte
|
||||
isIndexed func(term []byte) bool
|
||||
}
|
||||
|
||||
func (grc *geoRangeCompute) makePrefixCoded(in int64, shift uint) (rv numeric.PrefixCoded) {
|
||||
if len(grc.preallocBytes) <= 0 {
|
||||
grc.preallocBytesLen = grc.preallocBytesLen * 2
|
||||
grc.preallocBytes = make([]byte, grc.preallocBytesLen)
|
||||
}
|
||||
|
||||
rv, grc.preallocBytes, _ =
|
||||
numeric.NewPrefixCodedInt64Prealloc(in, shift, grc.preallocBytes)
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
func (grc *geoRangeCompute) computeGeoRange(term uint64, shift uint) {
|
||||
split := term | uint64(0x1)<<shift
|
||||
var upperMax uint64
|
||||
if shift < 63 {
|
||||
upperMax = term | ((uint64(1) << (shift + 1)) - 1)
|
||||
} else {
|
||||
upperMax = 0xffffffffffffffff
|
||||
}
|
||||
lowerMax := split - 1
|
||||
grc.relateAndRecurse(term, lowerMax, shift)
|
||||
grc.relateAndRecurse(split, upperMax, shift)
|
||||
}
|
||||
|
||||
func (grc *geoRangeCompute) relateAndRecurse(start, end uint64, res uint) {
|
||||
minLon := geo.MortonUnhashLon(start)
|
||||
minLat := geo.MortonUnhashLat(start)
|
||||
maxLon := geo.MortonUnhashLon(end)
|
||||
maxLat := geo.MortonUnhashLat(end)
|
||||
|
||||
level := (GeoBitsShift1 - res) >> 1
|
||||
|
||||
within := res%document.GeoPrecisionStep == 0 &&
|
||||
geo.RectWithin(minLon, minLat, maxLon, maxLat,
|
||||
grc.sminLon, grc.sminLat, grc.smaxLon, grc.smaxLat)
|
||||
if within || (level == geoDetailLevel &&
|
||||
geo.RectIntersects(minLon, minLat, maxLon, maxLat,
|
||||
grc.sminLon, grc.sminLat, grc.smaxLon, grc.smaxLat)) {
|
||||
codedTerm := grc.makePrefixCoded(int64(start), res)
|
||||
if grc.isIndexed(codedTerm) {
|
||||
if !within && grc.checkBoundaries {
|
||||
grc.onBoundary = append(grc.onBoundary, codedTerm)
|
||||
} else {
|
||||
grc.notOnBoundary = append(grc.notOnBoundary, codedTerm)
|
||||
}
|
||||
}
|
||||
} else if level < geoDetailLevel &&
|
||||
geo.RectIntersects(minLon, minLat, maxLon, maxLat,
|
||||
grc.sminLon, grc.sminLat, grc.smaxLon, grc.smaxLat) {
|
||||
grc.computeGeoRange(start, res-1)
|
||||
}
|
||||
}
|
180
vendor/github.com/blevesearch/bleve/search/searcher/search_multi_term.go
generated
vendored
180
vendor/github.com/blevesearch/bleve/search/searcher/search_multi_term.go
generated
vendored
|
@ -15,6 +15,7 @@
|
|||
package searcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/blevesearch/bleve/index"
|
||||
"github.com/blevesearch/bleve/search"
|
||||
)
|
||||
|
@ -22,10 +23,113 @@ import (
|
|||
func NewMultiTermSearcher(indexReader index.IndexReader, terms []string,
|
||||
field string, boost float64, options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
if limit && tooManyClauses(len(terms)) {
|
||||
return nil, tooManyClausesErr(len(terms))
|
||||
|
||||
if tooManyClauses(len(terms)) {
|
||||
if optionsDisjunctionOptimizable(options) {
|
||||
return optimizeMultiTermSearcher(indexReader, terms, field, boost, options)
|
||||
}
|
||||
if limit {
|
||||
return nil, tooManyClausesErr(field, len(terms))
|
||||
}
|
||||
}
|
||||
|
||||
qsearchers, err := makeBatchSearchers(indexReader, terms, field, boost, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// build disjunction searcher of these ranges
|
||||
return newMultiTermSearcherInternal(indexReader, qsearchers, field, boost,
|
||||
options, limit)
|
||||
}
|
||||
|
||||
func NewMultiTermSearcherBytes(indexReader index.IndexReader, terms [][]byte,
|
||||
field string, boost float64, options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
|
||||
if tooManyClauses(len(terms)) {
|
||||
if optionsDisjunctionOptimizable(options) {
|
||||
return optimizeMultiTermSearcherBytes(indexReader, terms, field, boost, options)
|
||||
}
|
||||
|
||||
if limit {
|
||||
return nil, tooManyClausesErr(field, len(terms))
|
||||
}
|
||||
}
|
||||
|
||||
qsearchers, err := makeBatchSearchersBytes(indexReader, terms, field, boost, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// build disjunction searcher of these ranges
|
||||
return newMultiTermSearcherInternal(indexReader, qsearchers, field, boost,
|
||||
options, limit)
|
||||
}
|
||||
|
||||
func newMultiTermSearcherInternal(indexReader index.IndexReader,
|
||||
searchers []search.Searcher, field string, boost float64,
|
||||
options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
|
||||
// build disjunction searcher of these ranges
|
||||
searcher, err := newDisjunctionSearcher(indexReader, searchers, 0, options,
|
||||
limit)
|
||||
if err != nil {
|
||||
for _, s := range searchers {
|
||||
_ = s.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return searcher, nil
|
||||
}
|
||||
|
||||
func optimizeMultiTermSearcher(indexReader index.IndexReader, terms []string,
|
||||
field string, boost float64, options search.SearcherOptions) (
|
||||
search.Searcher, error) {
|
||||
var finalSearcher search.Searcher
|
||||
for len(terms) > 0 {
|
||||
var batchTerms []string
|
||||
if len(terms) > DisjunctionMaxClauseCount {
|
||||
batchTerms = terms[:DisjunctionMaxClauseCount]
|
||||
terms = terms[DisjunctionMaxClauseCount:]
|
||||
} else {
|
||||
batchTerms = terms
|
||||
terms = nil
|
||||
}
|
||||
batch, err := makeBatchSearchers(indexReader, batchTerms, field, boost, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalSearcher != nil {
|
||||
batch = append(batch, finalSearcher)
|
||||
}
|
||||
cleanup := func() {
|
||||
for _, searcher := range batch {
|
||||
if searcher != nil {
|
||||
_ = searcher.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
finalSearcher, err = optimizeCompositeSearcher("disjunction:unadorned",
|
||||
indexReader, batch, options)
|
||||
// all searchers in batch should be closed, regardless of error or optimization failure
|
||||
// either we're returning, or continuing and only finalSearcher is needed for next loop
|
||||
cleanup()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalSearcher == nil {
|
||||
return nil, fmt.Errorf("unable to optimize")
|
||||
}
|
||||
}
|
||||
return finalSearcher, nil
|
||||
}
|
||||
|
||||
func makeBatchSearchers(indexReader index.IndexReader, terms []string, field string,
|
||||
boost float64, options search.SearcherOptions) ([]search.Searcher, error) {
|
||||
|
||||
qsearchers := make([]search.Searcher, len(terms))
|
||||
qsearchersClose := func() {
|
||||
for _, searcher := range qsearchers {
|
||||
|
@ -42,17 +146,54 @@ func NewMultiTermSearcher(indexReader index.IndexReader, terms []string,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
// build disjunction searcher of these ranges
|
||||
return newMultiTermSearcherBytes(indexReader, qsearchers, field, boost,
|
||||
options, limit)
|
||||
return qsearchers, nil
|
||||
}
|
||||
|
||||
func NewMultiTermSearcherBytes(indexReader index.IndexReader, terms [][]byte,
|
||||
field string, boost float64, options search.SearcherOptions, limit bool) (
|
||||
func optimizeMultiTermSearcherBytes(indexReader index.IndexReader, terms [][]byte,
|
||||
field string, boost float64, options search.SearcherOptions) (
|
||||
search.Searcher, error) {
|
||||
if limit && tooManyClauses(len(terms)) {
|
||||
return nil, tooManyClausesErr(len(terms))
|
||||
|
||||
var finalSearcher search.Searcher
|
||||
for len(terms) > 0 {
|
||||
var batchTerms [][]byte
|
||||
if len(terms) > DisjunctionMaxClauseCount {
|
||||
batchTerms = terms[:DisjunctionMaxClauseCount]
|
||||
terms = terms[DisjunctionMaxClauseCount:]
|
||||
} else {
|
||||
batchTerms = terms
|
||||
terms = nil
|
||||
}
|
||||
batch, err := makeBatchSearchersBytes(indexReader, batchTerms, field, boost, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalSearcher != nil {
|
||||
batch = append(batch, finalSearcher)
|
||||
}
|
||||
cleanup := func() {
|
||||
for _, searcher := range batch {
|
||||
if searcher != nil {
|
||||
_ = searcher.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
finalSearcher, err = optimizeCompositeSearcher("disjunction:unadorned",
|
||||
indexReader, batch, options)
|
||||
// all searchers in batch should be closed, regardless of error or optimization failure
|
||||
// either we're returning, or continuing and only finalSearcher is needed for next loop
|
||||
cleanup()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalSearcher == nil {
|
||||
return nil, fmt.Errorf("unable to optimize")
|
||||
}
|
||||
}
|
||||
return finalSearcher, nil
|
||||
}
|
||||
|
||||
func makeBatchSearchersBytes(indexReader index.IndexReader, terms [][]byte, field string,
|
||||
boost float64, options search.SearcherOptions) ([]search.Searcher, error) {
|
||||
|
||||
qsearchers := make([]search.Searcher, len(terms))
|
||||
qsearchersClose := func() {
|
||||
|
@ -70,24 +211,5 @@ func NewMultiTermSearcherBytes(indexReader index.IndexReader, terms [][]byte,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
return newMultiTermSearcherBytes(indexReader, qsearchers, field, boost,
|
||||
options, limit)
|
||||
}
|
||||
|
||||
func newMultiTermSearcherBytes(indexReader index.IndexReader,
|
||||
searchers []search.Searcher, field string, boost float64,
|
||||
options search.SearcherOptions, limit bool) (
|
||||
search.Searcher, error) {
|
||||
|
||||
// build disjunction searcher of these ranges
|
||||
searcher, err := newDisjunctionSearcher(indexReader, searchers, 0, options,
|
||||
limit)
|
||||
if err != nil {
|
||||
for _, s := range searchers {
|
||||
_ = s.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return searcher, nil
|
||||
return qsearchers, nil
|
||||
}
|
||||
|
|
7
vendor/github.com/blevesearch/bleve/search/searcher/search_numeric_range.go
generated
vendored
7
vendor/github.com/blevesearch/bleve/search/searcher/search_numeric_range.go
generated
vendored
|
@ -74,9 +74,8 @@ func NewNumericRangeSearcher(indexReader index.IndexReader,
|
|||
terms := termRanges.Enumerate(isIndexed)
|
||||
if fieldDict != nil {
|
||||
if fd, ok := fieldDict.(index.FieldDict); ok {
|
||||
cerr := fd.Close()
|
||||
if cerr != nil {
|
||||
err = cerr
|
||||
if err = fd.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +96,7 @@ func NewNumericRangeSearcher(indexReader index.IndexReader,
|
|||
}
|
||||
|
||||
if tooManyClauses(len(terms)) {
|
||||
return nil, tooManyClausesErr(len(terms))
|
||||
return nil, tooManyClausesErr(field, len(terms))
|
||||
}
|
||||
|
||||
return NewMultiTermSearcherBytes(indexReader, terms, field, boost, options,
|
||||
|
|
2
vendor/github.com/blevesearch/bleve/search/searcher/search_regexp.go
generated
vendored
2
vendor/github.com/blevesearch/bleve/search/searcher/search_regexp.go
generated
vendored
|
@ -110,7 +110,7 @@ func findRegexpCandidateTerms(indexReader index.IndexReader,
|
|||
if matchPos != nil && matchPos[0] == 0 && matchPos[1] == len(tfd.Term) {
|
||||
rv = append(rv, tfd.Term)
|
||||
if tooManyClauses(len(rv)) {
|
||||
return rv, tooManyClausesErr(len(rv))
|
||||
return rv, tooManyClausesErr(field, len(rv))
|
||||
}
|
||||
}
|
||||
tfd, err = fieldDict.Next()
|
||||
|
|
2
vendor/github.com/blevesearch/bleve/search/searcher/search_term.go
generated
vendored
2
vendor/github.com/blevesearch/bleve/search/searcher/search_term.go
generated
vendored
|
@ -137,5 +137,5 @@ func (s *TermSearcher) Optimize(kind string, octx index.OptimizableContext) (
|
|||
return o.Optimize(kind, octx)
|
||||
}
|
||||
|
||||
return octx, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
2
vendor/github.com/blevesearch/bleve/search/searcher/search_term_prefix.go
generated
vendored
2
vendor/github.com/blevesearch/bleve/search/searcher/search_term_prefix.go
generated
vendored
|
@ -38,7 +38,7 @@ func NewTermPrefixSearcher(indexReader index.IndexReader, prefix string,
|
|||
for err == nil && tfd != nil {
|
||||
terms = append(terms, tfd.Term)
|
||||
if tooManyClauses(len(terms)) {
|
||||
return nil, tooManyClausesErr(len(terms))
|
||||
return nil, tooManyClausesErr(field, len(terms))
|
||||
}
|
||||
tfd, err = fieldDict.Next()
|
||||
}
|
||||
|
|
9
vendor/github.com/blevesearch/bleve/search/sort.go
generated
vendored
9
vendor/github.com/blevesearch/bleve/search/sort.go
generated
vendored
|
@ -233,7 +233,11 @@ func (so SortOrder) Compare(cachedScoring, cachedDesc []bool, i, j *DocumentMatc
|
|||
} else {
|
||||
iVal := i.Sort[x]
|
||||
jVal := j.Sort[x]
|
||||
c = strings.Compare(iVal, jVal)
|
||||
if iVal < jVal {
|
||||
c = -1
|
||||
} else if iVal > jVal {
|
||||
c = 1
|
||||
}
|
||||
}
|
||||
|
||||
if c == 0 {
|
||||
|
@ -423,7 +427,8 @@ func (s *SortField) filterTermsByType(terms [][]byte) [][]byte {
|
|||
allTermsPrefixCoded = false
|
||||
}
|
||||
}
|
||||
if allTermsPrefixCoded {
|
||||
// reset the terms only when valid zero shift terms are found.
|
||||
if allTermsPrefixCoded && len(termsWithShiftZero) > 0 {
|
||||
terms = termsWithShiftZero
|
||||
s.tmp = termsWithShiftZero[:0]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue