pkg/index/index.go (156 lines of code) (raw):

// Licensed to Apache Software Foundation (ASF) under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Apache Software Foundation (ASF) licenses this file to you 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 index implements the index system for searching data. package index import ( "bytes" "fmt" "io" "github.com/pkg/errors" "github.com/apache/skywalking-banyandb/api/common" databasev1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1" modelv1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1" "github.com/apache/skywalking-banyandb/pkg/convert" "github.com/apache/skywalking-banyandb/pkg/index/posting" ) var errMalformed = errors.New("the data is malformed") // FieldKey is the key of field in a document. type FieldKey struct { SeriesID common.SeriesID IndexRuleID uint32 Analyzer databasev1.IndexRule_Analyzer } // MarshalIndexRule encodes the index rule id to string representation. func (f FieldKey) MarshalIndexRule() string { return string(convert.Uint32ToBytes(f.IndexRuleID)) } // Marshal encodes f to bytes. func (f FieldKey) Marshal() []byte { var s []byte if f.HasSeriesID() { s = f.SeriesID.Marshal() } i := []byte(f.MarshalIndexRule()) b := make([]byte, len(s)+len(i)) copy(b, s) copy(b[len(s):], i) return b } // HasSeriesID reports whether f has a series id. func (f FieldKey) HasSeriesID() bool { return f.SeriesID > 0 } // MarshalToStr encodes f to string. func (f FieldKey) MarshalToStr() string { return string(f.Marshal()) } // Unmarshal decodes bytes to f. func (f *FieldKey) Unmarshal(raw []byte) error { f.SeriesID = common.SeriesID(convert.BytesToUint64(raw[0:8])) f.IndexRuleID = convert.BytesToUint32(raw[8:]) return nil } // Equal reports whether f and other have the same series id and index rule id. func (f FieldKey) Equal(other FieldKey) bool { return f.SeriesID == other.SeriesID && f.IndexRuleID == other.IndexRuleID } // Field is a indexed item in a document. type Field struct { Term []byte Key FieldKey } // Marshal encodes f to bytes. func (f Field) Marshal() []byte { s := f.Key.SeriesID.Marshal() i := []byte(f.Key.MarshalIndexRule()) b := make([]byte, len(s)+len(i)+len(f.Term)) bp := copy(b, s) bp += copy(b[bp:], i) copy(b[bp:], f.Term) return b } // FieldStr return a string represent of Field which is composed by key and term. func FieldStr(key FieldKey, term []byte) string { f := Field{Key: key, Term: term} return string(f.Marshal()) } // Unmarshal decodes bytes to f. func (f *Field) Unmarshal(raw []byte) error { if len(raw) < 13 { return errors.WithMessagef(errMalformed, "malformed field: expected more than 12, got %d", len(raw)) } fk := &f.Key err := fk.Unmarshal(raw[:12]) if err != nil { return errors.Wrap(err, "unmarshal a field") } f.Term = UnmarshalTerm(raw) return nil } // UnmarshalTerm decodes term from a encoded field. func UnmarshalTerm(raw []byte) []byte { term := raw[12:] result := make([]byte, len(term)) copy(result, term) return result } // RangeOpts contains options to performance a continuous scan. type RangeOpts struct { Upper []byte Lower []byte IncludesUpper bool IncludesLower bool } // Between reports whether value is in the range. func (r RangeOpts) Between(value []byte) int { if r.Upper != nil { var in bool if r.IncludesUpper { in = bytes.Compare(r.Upper, value) >= 0 } else { in = bytes.Compare(r.Upper, value) > 0 } if !in { return 1 } } if r.Lower != nil { var in bool if r.IncludesLower { in = bytes.Compare(r.Lower, value) <= 0 } else { in = bytes.Compare(r.Lower, value) < 0 } if !in { return -1 } } return 0 } // FieldIterator allows iterating over a field's posting values. type FieldIterator interface { Next() bool Val() *PostingValue Close() error } // DummyFieldIterator never iterates. var DummyFieldIterator = &dummyIterator{} type dummyIterator struct{} func (i *dummyIterator) Next() bool { return false } func (i *dummyIterator) Val() *PostingValue { return nil } func (i *dummyIterator) Close() error { return nil } // PostingValue is the collection of a field's values. type PostingValue struct { Value posting.List Term []byte } // Writer allows writing fields and docID in a document to a index. type Writer interface { Write(fields []Field, docID uint64) error } // FieldIterable allows building a FieldIterator. type FieldIterable interface { Iterator(fieldKey FieldKey, termRange RangeOpts, order modelv1.Sort) (iter FieldIterator, err error) } // Searcher allows searching a field either by its key or by its key and term. type Searcher interface { FieldIterable Match(fieldKey FieldKey, match []string) (list posting.List, err error) MatchField(fieldKey FieldKey) (list posting.List, err error) MatchTerms(field Field) (list posting.List, err error) Range(fieldKey FieldKey, opts RangeOpts) (list posting.List, err error) } // Store is an abstract of a index repository. type Store interface { io.Closer Writer Searcher SizeOnDisk() int64 } // GetSearcher returns a searcher associated with input index rule type. type GetSearcher func(location databasev1.IndexRule_Type) (Searcher, error) // Filter is a node in the filter tree. type Filter interface { fmt.Stringer Execute(getSearcher GetSearcher, seriesID common.SeriesID) (posting.List, error) }