1//  Copyright (c) 2014 Couchbase, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// 		http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package bleve
16
17import (
18	"github.com/blevesearch/bleve/document"
19	"github.com/blevesearch/bleve/index"
20	"github.com/blevesearch/bleve/index/store"
21	"github.com/blevesearch/bleve/mapping"
22	"golang.org/x/net/context"
23)
24
25// A Batch groups together multiple Index and Delete
26// operations you would like performed at the same
27// time.  The Batch structure is NOT thread-safe.
28// You should only perform operations on a batch
29// from a single thread at a time.  Once batch
30// execution has started, you may not modify it.
31type Batch struct {
32	index    Index
33	internal *index.Batch
34}
35
36// Index adds the specified index operation to the
37// batch.  NOTE: the bleve Index is not updated
38// until the batch is executed.
39func (b *Batch) Index(id string, data interface{}) error {
40	if id == "" {
41		return ErrorEmptyID
42	}
43	doc := document.NewDocument(id)
44	err := b.index.Mapping().MapDocument(doc, data)
45	if err != nil {
46		return err
47	}
48	b.internal.Update(doc)
49	return nil
50}
51
52// IndexAdvanced adds the specified index operation to the
53// batch which skips the mapping.  NOTE: the bleve Index is not updated
54// until the batch is executed.
55func (b *Batch) IndexAdvanced(doc *document.Document) (err error) {
56	if doc.ID == "" {
57		return ErrorEmptyID
58	}
59	b.internal.Update(doc)
60	return nil
61}
62
63// Delete adds the specified delete operation to the
64// batch.  NOTE: the bleve Index is not updated until
65// the batch is executed.
66func (b *Batch) Delete(id string) {
67	if id != "" {
68		b.internal.Delete(id)
69	}
70}
71
72// SetInternal adds the specified set internal
73// operation to the batch. NOTE: the bleve Index is
74// not updated until the batch is executed.
75func (b *Batch) SetInternal(key, val []byte) {
76	b.internal.SetInternal(key, val)
77}
78
79// DeleteInternal adds the specified delete internal
80// operation to the batch. NOTE: the bleve Index is
81// not updated until the batch is executed.
82func (b *Batch) DeleteInternal(key []byte) {
83	b.internal.DeleteInternal(key)
84}
85
86// Size returns the total number of operations inside the batch
87// including normal index operations and internal operations.
88func (b *Batch) Size() int {
89	return len(b.internal.IndexOps) + len(b.internal.InternalOps)
90}
91
92// String prints a user friendly string representation of what
93// is inside this batch.
94func (b *Batch) String() string {
95	return b.internal.String()
96}
97
98// Reset returns a Batch to the empty state so that it can
99// be re-used in the future.
100func (b *Batch) Reset() {
101	b.internal.Reset()
102}
103
104// An Index implements all the indexing and searching
105// capabilities of bleve.  An Index can be created
106// using the New() and Open() methods.
107//
108// Index() takes an input value, deduces a DocumentMapping for its type,
109// assigns string paths to its fields or values then applies field mappings on
110// them.
111//
112// The DocumentMapping used to index a value is deduced by the following rules:
113// 1) If value implements mapping.bleveClassifier interface, resolve the mapping
114//    from BleveType().
115// 2) If value implements mapping.Classifier interface, resolve the mapping
116//    from Type().
117// 3) If value has a string field or value at IndexMapping.TypeField.
118// (defaulting to "_type"), use it to resolve the mapping. Fields addressing
119// is described below.
120// 4) If IndexMapping.DefaultType is registered, return it.
121// 5) Return IndexMapping.DefaultMapping.
122//
123// Each field or nested field of the value is identified by a string path, then
124// mapped to one or several FieldMappings which extract the result for analysis.
125//
126// Struct values fields are identified by their "json:" tag, or by their name.
127// Nested fields are identified by prefixing with their parent identifier,
128// separated by a dot.
129//
130// Map values entries are identified by their string key. Entries not indexed
131// by strings are ignored. Entry values are identified recursively like struct
132// fields.
133//
134// Slice and array values are identified by their field name. Their elements
135// are processed sequentially with the same FieldMapping.
136//
137// String, float64 and time.Time values are identified by their field name.
138// Other types are ignored.
139//
140// Each value identifier is decomposed in its parts and recursively address
141// SubDocumentMappings in the tree starting at the root DocumentMapping.  If a
142// mapping is found, all its FieldMappings are applied to the value. If no
143// mapping is found and the root DocumentMapping is dynamic, default mappings
144// are used based on value type and IndexMapping default configurations.
145//
146// Finally, mapped values are analyzed, indexed or stored. See
147// FieldMapping.Analyzer to know how an analyzer is resolved for a given field.
148//
149// Examples:
150//
151//  type Date struct {
152//    Day string `json:"day"`
153//    Month string
154//    Year string
155//  }
156//
157//  type Person struct {
158//    FirstName string `json:"first_name"`
159//    LastName string
160//    BirthDate Date `json:"birth_date"`
161//  }
162//
163// A Person value FirstName is mapped by the SubDocumentMapping at
164// "first_name". Its LastName is mapped by the one at "LastName". The day of
165// BirthDate is mapped to the SubDocumentMapping "day" of the root
166// SubDocumentMapping "birth_date". It will appear as the "birth_date.day"
167// field in the index. The month is mapped to "birth_date.Month".
168type Index interface {
169	// Index analyzes, indexes or stores mapped data fields. Supplied
170	// identifier is bound to analyzed data and will be retrieved by search
171	// requests. See Index interface documentation for details about mapping
172	// rules.
173	Index(id string, data interface{}) error
174	Delete(id string) error
175
176	NewBatch() *Batch
177	Batch(b *Batch) error
178
179	// Document returns specified document or nil if the document is not
180	// indexed or stored.
181	Document(id string) (*document.Document, error)
182	// DocCount returns the number of documents in the index.
183	DocCount() (uint64, error)
184
185	Search(req *SearchRequest) (*SearchResult, error)
186	SearchInContext(ctx context.Context, req *SearchRequest) (*SearchResult, error)
187
188	Fields() ([]string, error)
189
190	FieldDict(field string) (index.FieldDict, error)
191	FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error)
192	FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error)
193
194	Close() error
195
196	Mapping() mapping.IndexMapping
197
198	Stats() *IndexStat
199	StatsMap() map[string]interface{}
200
201	GetInternal(key []byte) ([]byte, error)
202	SetInternal(key, val []byte) error
203	DeleteInternal(key []byte) error
204
205	// Name returns the name of the index (by default this is the path)
206	Name() string
207	// SetName lets you assign your own logical name to this index
208	SetName(string)
209
210	// Advanced returns the indexer and data store, exposing lower level
211	// methods to enumerate records and access data.
212	Advanced() (index.Index, store.KVStore, error)
213}
214
215// New index at the specified path, must not exist.
216// The provided mapping will be used for all
217// Index/Search operations.
218func New(path string, mapping mapping.IndexMapping) (Index, error) {
219	return newIndexUsing(path, mapping, Config.DefaultIndexType, Config.DefaultKVStore, nil)
220}
221
222// NewMemOnly creates a memory-only index.
223// The contents of the index is NOT persisted,
224// and will be lost once closed.
225// The provided mapping will be used for all
226// Index/Search operations.
227func NewMemOnly(mapping mapping.IndexMapping) (Index, error) {
228	return newIndexUsing("", mapping, Config.DefaultIndexType, Config.DefaultMemKVStore, nil)
229}
230
231// NewUsing creates index at the specified path,
232// which must not already exist.
233// The provided mapping will be used for all
234// Index/Search operations.
235// The specified index type will be used.
236// The specified kvstore implementation will be used
237// and the provided kvconfig will be passed to its
238// constructor. Note that currently the values of kvconfig must
239// be able to be marshaled and unmarshaled using the encoding/json library (used
240// when reading/writing the index metadata file).
241func NewUsing(path string, mapping mapping.IndexMapping, indexType string, kvstore string, kvconfig map[string]interface{}) (Index, error) {
242	return newIndexUsing(path, mapping, indexType, kvstore, kvconfig)
243}
244
245// Open index at the specified path, must exist.
246// The mapping used when it was created will be used for all Index/Search operations.
247func Open(path string) (Index, error) {
248	return openIndexUsing(path, nil)
249}
250
251// OpenUsing opens index at the specified path, must exist.
252// The mapping used when it was created will be used for all Index/Search operations.
253// The provided runtimeConfig can override settings
254// persisted when the kvstore was created.
255func OpenUsing(path string, runtimeConfig map[string]interface{}) (Index, error) {
256	return openIndexUsing(path, runtimeConfig)
257}
258