// Copyright (c) 2017 Couchbase, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package scorch import ( "bytes" "reflect" "sync/atomic" "github.com/blevesearch/bleve/index" "github.com/blevesearch/bleve/index/scorch/segment" "github.com/blevesearch/bleve/size" ) var reflectStaticSizeIndexSnapshotTermFieldReader int func init() { var istfr IndexSnapshotTermFieldReader reflectStaticSizeIndexSnapshotTermFieldReader = int(reflect.TypeOf(istfr).Size()) } type IndexSnapshotTermFieldReader struct { term []byte field string snapshot *IndexSnapshot postings []segment.PostingsList iterators []segment.PostingsIterator segmentOffset int includeFreq bool includeNorm bool includeTermVectors bool currPosting segment.Posting currID index.IndexInternalID } func (i *IndexSnapshotTermFieldReader) Size() int { sizeInBytes := reflectStaticSizeIndexSnapshotTermFieldReader + size.SizeOfPtr + len(i.term) + len(i.field) + len(i.currID) for _, entry := range i.postings { sizeInBytes += entry.Size() } for _, entry := range i.iterators { sizeInBytes += entry.Size() } if i.currPosting != nil { sizeInBytes += i.currPosting.Size() } return sizeInBytes } func (i *IndexSnapshotTermFieldReader) Next(preAlloced *index.TermFieldDoc) (*index.TermFieldDoc, error) { rv := preAlloced if rv == nil { rv = &index.TermFieldDoc{} } // find the next hit for i.segmentOffset < len(i.postings) { next, err := i.iterators[i.segmentOffset].Next() if err != nil { return nil, err } if next != nil { // make segment number into global number by adding offset globalOffset := i.snapshot.offsets[i.segmentOffset] nnum := next.Number() rv.ID = docNumberToBytes(rv.ID, nnum+globalOffset) i.postingToTermFieldDoc(next, rv) i.currID = rv.ID i.currPosting = next return rv, nil } i.segmentOffset++ } return nil, nil } func (i *IndexSnapshotTermFieldReader) postingToTermFieldDoc(next segment.Posting, rv *index.TermFieldDoc) { if i.includeFreq { rv.Freq = next.Frequency() } if i.includeNorm { rv.Norm = next.Norm() } if i.includeTermVectors { locs := next.Locations() rv.Vectors = make([]*index.TermFieldVector, len(locs)) for i, loc := range locs { rv.Vectors[i] = &index.TermFieldVector{ Start: loc.Start(), End: loc.End(), Pos: loc.Pos(), ArrayPositions: loc.ArrayPositions(), Field: loc.Field(), } } } } func (i *IndexSnapshotTermFieldReader) Advance(ID index.IndexInternalID, preAlloced *index.TermFieldDoc) (*index.TermFieldDoc, error) { // FIXME do something better // for now, if we need to seek backwards, then restart from the beginning if i.currPosting != nil && bytes.Compare(i.currID, ID) >= 0 { i2, err := i.snapshot.TermFieldReader(i.term, i.field, i.includeFreq, i.includeNorm, i.includeTermVectors) if err != nil { return nil, err } *i = *(i2.(*IndexSnapshotTermFieldReader)) } // FIXME do something better next, err := i.Next(preAlloced) if err != nil { return nil, err } if next == nil { return nil, nil } for bytes.Compare(next.ID, ID) < 0 { next, err = i.Next(preAlloced) if err != nil { return nil, err } if next == nil { break } } return next, nil } func (i *IndexSnapshotTermFieldReader) Count() uint64 { var rv uint64 for _, posting := range i.postings { rv += posting.Count() } return rv } func (i *IndexSnapshotTermFieldReader) Close() error { if i.snapshot != nil { atomic.AddUint64(&i.snapshot.parent.stats.TotTermSearchersFinished, uint64(1)) } return nil }