本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

857 lines
19KB

  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. package bleve
  15. import (
  16. "context"
  17. "encoding/json"
  18. "fmt"
  19. "os"
  20. "sync"
  21. "sync/atomic"
  22. "time"
  23. "github.com/blevesearch/bleve/document"
  24. "github.com/blevesearch/bleve/index"
  25. "github.com/blevesearch/bleve/index/store"
  26. "github.com/blevesearch/bleve/index/upsidedown"
  27. "github.com/blevesearch/bleve/mapping"
  28. "github.com/blevesearch/bleve/registry"
  29. "github.com/blevesearch/bleve/search"
  30. "github.com/blevesearch/bleve/search/collector"
  31. "github.com/blevesearch/bleve/search/facet"
  32. "github.com/blevesearch/bleve/search/highlight"
  33. )
  34. type indexImpl struct {
  35. path string
  36. name string
  37. meta *indexMeta
  38. i index.Index
  39. m mapping.IndexMapping
  40. mutex sync.RWMutex
  41. open bool
  42. stats *IndexStat
  43. }
  44. const storePath = "store"
  45. var mappingInternalKey = []byte("_mapping")
  46. const SearchQueryStartCallbackKey = "_search_query_start_callback_key"
  47. const SearchQueryEndCallbackKey = "_search_query_end_callback_key"
  48. type SearchQueryStartCallbackFn func(size uint64) error
  49. type SearchQueryEndCallbackFn func(size uint64) error
  50. func indexStorePath(path string) string {
  51. return path + string(os.PathSeparator) + storePath
  52. }
  53. func newIndexUsing(path string, mapping mapping.IndexMapping, indexType string, kvstore string, kvconfig map[string]interface{}) (*indexImpl, error) {
  54. // first validate the mapping
  55. err := mapping.Validate()
  56. if err != nil {
  57. return nil, err
  58. }
  59. if kvconfig == nil {
  60. kvconfig = map[string]interface{}{}
  61. }
  62. if kvstore == "" {
  63. return nil, fmt.Errorf("bleve not configured for file based indexing")
  64. }
  65. rv := indexImpl{
  66. path: path,
  67. name: path,
  68. m: mapping,
  69. meta: newIndexMeta(indexType, kvstore, kvconfig),
  70. }
  71. rv.stats = &IndexStat{i: &rv}
  72. // at this point there is hope that we can be successful, so save index meta
  73. if path != "" {
  74. err = rv.meta.Save(path)
  75. if err != nil {
  76. return nil, err
  77. }
  78. kvconfig["create_if_missing"] = true
  79. kvconfig["error_if_exists"] = true
  80. kvconfig["path"] = indexStorePath(path)
  81. } else {
  82. kvconfig["path"] = ""
  83. }
  84. // open the index
  85. indexTypeConstructor := registry.IndexTypeConstructorByName(rv.meta.IndexType)
  86. if indexTypeConstructor == nil {
  87. return nil, ErrorUnknownIndexType
  88. }
  89. rv.i, err = indexTypeConstructor(rv.meta.Storage, kvconfig, Config.analysisQueue)
  90. if err != nil {
  91. return nil, err
  92. }
  93. err = rv.i.Open()
  94. if err != nil {
  95. if err == index.ErrorUnknownStorageType {
  96. return nil, ErrorUnknownStorageType
  97. }
  98. return nil, err
  99. }
  100. // now persist the mapping
  101. mappingBytes, err := json.Marshal(mapping)
  102. if err != nil {
  103. return nil, err
  104. }
  105. err = rv.i.SetInternal(mappingInternalKey, mappingBytes)
  106. if err != nil {
  107. return nil, err
  108. }
  109. // mark the index as open
  110. rv.mutex.Lock()
  111. defer rv.mutex.Unlock()
  112. rv.open = true
  113. indexStats.Register(&rv)
  114. return &rv, nil
  115. }
  116. func openIndexUsing(path string, runtimeConfig map[string]interface{}) (rv *indexImpl, err error) {
  117. rv = &indexImpl{
  118. path: path,
  119. name: path,
  120. }
  121. rv.stats = &IndexStat{i: rv}
  122. rv.meta, err = openIndexMeta(path)
  123. if err != nil {
  124. return nil, err
  125. }
  126. // backwards compatibility if index type is missing
  127. if rv.meta.IndexType == "" {
  128. rv.meta.IndexType = upsidedown.Name
  129. }
  130. storeConfig := rv.meta.Config
  131. if storeConfig == nil {
  132. storeConfig = map[string]interface{}{}
  133. }
  134. storeConfig["path"] = indexStorePath(path)
  135. storeConfig["create_if_missing"] = false
  136. storeConfig["error_if_exists"] = false
  137. for rck, rcv := range runtimeConfig {
  138. storeConfig[rck] = rcv
  139. }
  140. // open the index
  141. indexTypeConstructor := registry.IndexTypeConstructorByName(rv.meta.IndexType)
  142. if indexTypeConstructor == nil {
  143. return nil, ErrorUnknownIndexType
  144. }
  145. rv.i, err = indexTypeConstructor(rv.meta.Storage, storeConfig, Config.analysisQueue)
  146. if err != nil {
  147. return nil, err
  148. }
  149. err = rv.i.Open()
  150. if err != nil {
  151. if err == index.ErrorUnknownStorageType {
  152. return nil, ErrorUnknownStorageType
  153. }
  154. return nil, err
  155. }
  156. // now load the mapping
  157. indexReader, err := rv.i.Reader()
  158. if err != nil {
  159. return nil, err
  160. }
  161. defer func() {
  162. if cerr := indexReader.Close(); cerr != nil && err == nil {
  163. err = cerr
  164. }
  165. }()
  166. mappingBytes, err := indexReader.GetInternal(mappingInternalKey)
  167. if err != nil {
  168. return nil, err
  169. }
  170. var im *mapping.IndexMappingImpl
  171. err = json.Unmarshal(mappingBytes, &im)
  172. if err != nil {
  173. return nil, fmt.Errorf("error parsing mapping JSON: %v\nmapping contents:\n%s", err, string(mappingBytes))
  174. }
  175. // mark the index as open
  176. rv.mutex.Lock()
  177. defer rv.mutex.Unlock()
  178. rv.open = true
  179. // validate the mapping
  180. err = im.Validate()
  181. if err != nil {
  182. // note even if the mapping is invalid
  183. // we still return an open usable index
  184. return rv, err
  185. }
  186. rv.m = im
  187. indexStats.Register(rv)
  188. return rv, err
  189. }
  190. // Advanced returns implementation internals
  191. // necessary ONLY for advanced usage.
  192. func (i *indexImpl) Advanced() (index.Index, store.KVStore, error) {
  193. s, err := i.i.Advanced()
  194. if err != nil {
  195. return nil, nil, err
  196. }
  197. return i.i, s, nil
  198. }
  199. // Mapping returns the IndexMapping in use by this
  200. // Index.
  201. func (i *indexImpl) Mapping() mapping.IndexMapping {
  202. return i.m
  203. }
  204. // Index the object with the specified identifier.
  205. // The IndexMapping for this index will determine
  206. // how the object is indexed.
  207. func (i *indexImpl) Index(id string, data interface{}) (err error) {
  208. if id == "" {
  209. return ErrorEmptyID
  210. }
  211. i.mutex.RLock()
  212. defer i.mutex.RUnlock()
  213. if !i.open {
  214. return ErrorIndexClosed
  215. }
  216. doc := document.NewDocument(id)
  217. err = i.m.MapDocument(doc, data)
  218. if err != nil {
  219. return
  220. }
  221. err = i.i.Update(doc)
  222. return
  223. }
  224. // IndexAdvanced takes a document.Document object
  225. // skips the mapping and indexes it.
  226. func (i *indexImpl) IndexAdvanced(doc *document.Document) (err error) {
  227. if doc.ID == "" {
  228. return ErrorEmptyID
  229. }
  230. i.mutex.RLock()
  231. defer i.mutex.RUnlock()
  232. if !i.open {
  233. return ErrorIndexClosed
  234. }
  235. err = i.i.Update(doc)
  236. return
  237. }
  238. // Delete entries for the specified identifier from
  239. // the index.
  240. func (i *indexImpl) Delete(id string) (err error) {
  241. if id == "" {
  242. return ErrorEmptyID
  243. }
  244. i.mutex.RLock()
  245. defer i.mutex.RUnlock()
  246. if !i.open {
  247. return ErrorIndexClosed
  248. }
  249. err = i.i.Delete(id)
  250. return
  251. }
  252. // Batch executes multiple Index and Delete
  253. // operations at the same time. There are often
  254. // significant performance benefits when performing
  255. // operations in a batch.
  256. func (i *indexImpl) Batch(b *Batch) error {
  257. i.mutex.RLock()
  258. defer i.mutex.RUnlock()
  259. if !i.open {
  260. return ErrorIndexClosed
  261. }
  262. return i.i.Batch(b.internal)
  263. }
  264. // Document is used to find the values of all the
  265. // stored fields for a document in the index. These
  266. // stored fields are put back into a Document object
  267. // and returned.
  268. func (i *indexImpl) Document(id string) (doc *document.Document, err error) {
  269. i.mutex.RLock()
  270. defer i.mutex.RUnlock()
  271. if !i.open {
  272. return nil, ErrorIndexClosed
  273. }
  274. indexReader, err := i.i.Reader()
  275. if err != nil {
  276. return nil, err
  277. }
  278. defer func() {
  279. if cerr := indexReader.Close(); err == nil && cerr != nil {
  280. err = cerr
  281. }
  282. }()
  283. doc, err = indexReader.Document(id)
  284. if err != nil {
  285. return nil, err
  286. }
  287. return doc, nil
  288. }
  289. // DocCount returns the number of documents in the
  290. // index.
  291. func (i *indexImpl) DocCount() (count uint64, err error) {
  292. i.mutex.RLock()
  293. defer i.mutex.RUnlock()
  294. if !i.open {
  295. return 0, ErrorIndexClosed
  296. }
  297. // open a reader for this search
  298. indexReader, err := i.i.Reader()
  299. if err != nil {
  300. return 0, fmt.Errorf("error opening index reader %v", err)
  301. }
  302. defer func() {
  303. if cerr := indexReader.Close(); err == nil && cerr != nil {
  304. err = cerr
  305. }
  306. }()
  307. count, err = indexReader.DocCount()
  308. return
  309. }
  310. // Search executes a search request operation.
  311. // Returns a SearchResult object or an error.
  312. func (i *indexImpl) Search(req *SearchRequest) (sr *SearchResult, err error) {
  313. return i.SearchInContext(context.Background(), req)
  314. }
  315. var documentMatchEmptySize int
  316. var searchContextEmptySize int
  317. var facetResultEmptySize int
  318. var documentEmptySize int
  319. func init() {
  320. var dm search.DocumentMatch
  321. documentMatchEmptySize = dm.Size()
  322. var sc search.SearchContext
  323. searchContextEmptySize = sc.Size()
  324. var fr search.FacetResult
  325. facetResultEmptySize = fr.Size()
  326. var d document.Document
  327. documentEmptySize = d.Size()
  328. }
  329. // memNeededForSearch is a helper function that returns an estimate of RAM
  330. // needed to execute a search request.
  331. func memNeededForSearch(req *SearchRequest,
  332. searcher search.Searcher,
  333. topnCollector *collector.TopNCollector) uint64 {
  334. backingSize := req.Size + req.From + 1
  335. if req.Size+req.From > collector.PreAllocSizeSkipCap {
  336. backingSize = collector.PreAllocSizeSkipCap + 1
  337. }
  338. numDocMatches := backingSize + searcher.DocumentMatchPoolSize()
  339. estimate := 0
  340. // overhead, size in bytes from collector
  341. estimate += topnCollector.Size()
  342. // pre-allocing DocumentMatchPool
  343. estimate += searchContextEmptySize + numDocMatches*documentMatchEmptySize
  344. // searcher overhead
  345. estimate += searcher.Size()
  346. // overhead from results, lowestMatchOutsideResults
  347. estimate += (numDocMatches + 1) * documentMatchEmptySize
  348. // additional overhead from SearchResult
  349. estimate += reflectStaticSizeSearchResult + reflectStaticSizeSearchStatus
  350. // overhead from facet results
  351. if req.Facets != nil {
  352. estimate += len(req.Facets) * facetResultEmptySize
  353. }
  354. // highlighting, store
  355. if len(req.Fields) > 0 || req.Highlight != nil {
  356. // Size + From => number of hits
  357. estimate += (req.Size + req.From) * documentEmptySize
  358. }
  359. return uint64(estimate)
  360. }
  361. // SearchInContext executes a search request operation within the provided
  362. // Context. Returns a SearchResult object or an error.
  363. func (i *indexImpl) SearchInContext(ctx context.Context, req *SearchRequest) (sr *SearchResult, err error) {
  364. i.mutex.RLock()
  365. defer i.mutex.RUnlock()
  366. searchStart := time.Now()
  367. if !i.open {
  368. return nil, ErrorIndexClosed
  369. }
  370. collector := collector.NewTopNCollector(req.Size, req.From, req.Sort)
  371. // open a reader for this search
  372. indexReader, err := i.i.Reader()
  373. if err != nil {
  374. return nil, fmt.Errorf("error opening index reader %v", err)
  375. }
  376. defer func() {
  377. if cerr := indexReader.Close(); err == nil && cerr != nil {
  378. err = cerr
  379. }
  380. }()
  381. searcher, err := req.Query.Searcher(indexReader, i.m, search.SearcherOptions{
  382. Explain: req.Explain,
  383. IncludeTermVectors: req.IncludeLocations || req.Highlight != nil,
  384. Score: req.Score,
  385. })
  386. if err != nil {
  387. return nil, err
  388. }
  389. defer func() {
  390. if serr := searcher.Close(); err == nil && serr != nil {
  391. err = serr
  392. }
  393. }()
  394. if req.Facets != nil {
  395. facetsBuilder := search.NewFacetsBuilder(indexReader)
  396. for facetName, facetRequest := range req.Facets {
  397. if facetRequest.NumericRanges != nil {
  398. // build numeric range facet
  399. facetBuilder := facet.NewNumericFacetBuilder(facetRequest.Field, facetRequest.Size)
  400. for _, nr := range facetRequest.NumericRanges {
  401. facetBuilder.AddRange(nr.Name, nr.Min, nr.Max)
  402. }
  403. facetsBuilder.Add(facetName, facetBuilder)
  404. } else if facetRequest.DateTimeRanges != nil {
  405. // build date range facet
  406. facetBuilder := facet.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size)
  407. dateTimeParser := i.m.DateTimeParserNamed("")
  408. for _, dr := range facetRequest.DateTimeRanges {
  409. start, end := dr.ParseDates(dateTimeParser)
  410. facetBuilder.AddRange(dr.Name, start, end)
  411. }
  412. facetsBuilder.Add(facetName, facetBuilder)
  413. } else {
  414. // build terms facet
  415. facetBuilder := facet.NewTermsFacetBuilder(facetRequest.Field, facetRequest.Size)
  416. facetsBuilder.Add(facetName, facetBuilder)
  417. }
  418. }
  419. collector.SetFacetsBuilder(facetsBuilder)
  420. }
  421. memNeeded := memNeededForSearch(req, searcher, collector)
  422. if cb := ctx.Value(SearchQueryStartCallbackKey); cb != nil {
  423. if cbF, ok := cb.(SearchQueryStartCallbackFn); ok {
  424. err = cbF(memNeeded)
  425. }
  426. }
  427. if err != nil {
  428. return nil, err
  429. }
  430. if cb := ctx.Value(SearchQueryEndCallbackKey); cb != nil {
  431. if cbF, ok := cb.(SearchQueryEndCallbackFn); ok {
  432. defer func() {
  433. _ = cbF(memNeeded)
  434. }()
  435. }
  436. }
  437. err = collector.Collect(ctx, searcher, indexReader)
  438. if err != nil {
  439. return nil, err
  440. }
  441. hits := collector.Results()
  442. var highlighter highlight.Highlighter
  443. if req.Highlight != nil {
  444. // get the right highlighter
  445. highlighter, err = Config.Cache.HighlighterNamed(Config.DefaultHighlighter)
  446. if err != nil {
  447. return nil, err
  448. }
  449. if req.Highlight.Style != nil {
  450. highlighter, err = Config.Cache.HighlighterNamed(*req.Highlight.Style)
  451. if err != nil {
  452. return nil, err
  453. }
  454. }
  455. if highlighter == nil {
  456. return nil, fmt.Errorf("no highlighter named `%s` registered", *req.Highlight.Style)
  457. }
  458. }
  459. for _, hit := range hits {
  460. if len(req.Fields) > 0 || highlighter != nil {
  461. doc, err := indexReader.Document(hit.ID)
  462. if err == nil && doc != nil {
  463. if len(req.Fields) > 0 {
  464. fieldsToLoad := deDuplicate(req.Fields)
  465. for _, f := range fieldsToLoad {
  466. for _, docF := range doc.Fields {
  467. if f == "*" || docF.Name() == f {
  468. var value interface{}
  469. switch docF := docF.(type) {
  470. case *document.TextField:
  471. value = string(docF.Value())
  472. case *document.NumericField:
  473. num, err := docF.Number()
  474. if err == nil {
  475. value = num
  476. }
  477. case *document.DateTimeField:
  478. datetime, err := docF.DateTime()
  479. if err == nil {
  480. value = datetime.Format(time.RFC3339)
  481. }
  482. case *document.BooleanField:
  483. boolean, err := docF.Boolean()
  484. if err == nil {
  485. value = boolean
  486. }
  487. case *document.GeoPointField:
  488. lon, err := docF.Lon()
  489. if err == nil {
  490. lat, err := docF.Lat()
  491. if err == nil {
  492. value = []float64{lon, lat}
  493. }
  494. }
  495. }
  496. if value != nil {
  497. hit.AddFieldValue(docF.Name(), value)
  498. }
  499. }
  500. }
  501. }
  502. }
  503. if highlighter != nil {
  504. highlightFields := req.Highlight.Fields
  505. if highlightFields == nil {
  506. // add all fields with matches
  507. highlightFields = make([]string, 0, len(hit.Locations))
  508. for k := range hit.Locations {
  509. highlightFields = append(highlightFields, k)
  510. }
  511. }
  512. for _, hf := range highlightFields {
  513. highlighter.BestFragmentsInField(hit, doc, hf, 1)
  514. }
  515. }
  516. } else if doc == nil {
  517. // unexpected case, a doc ID that was found as a search hit
  518. // was unable to be found during document lookup
  519. return nil, ErrorIndexReadInconsistency
  520. }
  521. }
  522. if i.name != "" {
  523. hit.Index = i.name
  524. }
  525. }
  526. atomic.AddUint64(&i.stats.searches, 1)
  527. searchDuration := time.Since(searchStart)
  528. atomic.AddUint64(&i.stats.searchTime, uint64(searchDuration))
  529. if Config.SlowSearchLogThreshold > 0 &&
  530. searchDuration > Config.SlowSearchLogThreshold {
  531. logger.Printf("slow search took %s - %v", searchDuration, req)
  532. }
  533. return &SearchResult{
  534. Status: &SearchStatus{
  535. Total: 1,
  536. Successful: 1,
  537. },
  538. Request: req,
  539. Hits: hits,
  540. Total: collector.Total(),
  541. MaxScore: collector.MaxScore(),
  542. Took: searchDuration,
  543. Facets: collector.FacetResults(),
  544. }, nil
  545. }
  546. // Fields returns the name of all the fields this
  547. // Index has operated on.
  548. func (i *indexImpl) Fields() (fields []string, err error) {
  549. i.mutex.RLock()
  550. defer i.mutex.RUnlock()
  551. if !i.open {
  552. return nil, ErrorIndexClosed
  553. }
  554. indexReader, err := i.i.Reader()
  555. if err != nil {
  556. return nil, err
  557. }
  558. defer func() {
  559. if cerr := indexReader.Close(); err == nil && cerr != nil {
  560. err = cerr
  561. }
  562. }()
  563. fields, err = indexReader.Fields()
  564. if err != nil {
  565. return nil, err
  566. }
  567. return fields, nil
  568. }
  569. func (i *indexImpl) FieldDict(field string) (index.FieldDict, error) {
  570. i.mutex.RLock()
  571. if !i.open {
  572. i.mutex.RUnlock()
  573. return nil, ErrorIndexClosed
  574. }
  575. indexReader, err := i.i.Reader()
  576. if err != nil {
  577. i.mutex.RUnlock()
  578. return nil, err
  579. }
  580. fieldDict, err := indexReader.FieldDict(field)
  581. if err != nil {
  582. i.mutex.RUnlock()
  583. return nil, err
  584. }
  585. return &indexImplFieldDict{
  586. index: i,
  587. indexReader: indexReader,
  588. fieldDict: fieldDict,
  589. }, nil
  590. }
  591. func (i *indexImpl) FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) {
  592. i.mutex.RLock()
  593. if !i.open {
  594. i.mutex.RUnlock()
  595. return nil, ErrorIndexClosed
  596. }
  597. indexReader, err := i.i.Reader()
  598. if err != nil {
  599. i.mutex.RUnlock()
  600. return nil, err
  601. }
  602. fieldDict, err := indexReader.FieldDictRange(field, startTerm, endTerm)
  603. if err != nil {
  604. i.mutex.RUnlock()
  605. return nil, err
  606. }
  607. return &indexImplFieldDict{
  608. index: i,
  609. indexReader: indexReader,
  610. fieldDict: fieldDict,
  611. }, nil
  612. }
  613. func (i *indexImpl) FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) {
  614. i.mutex.RLock()
  615. if !i.open {
  616. i.mutex.RUnlock()
  617. return nil, ErrorIndexClosed
  618. }
  619. indexReader, err := i.i.Reader()
  620. if err != nil {
  621. i.mutex.RUnlock()
  622. return nil, err
  623. }
  624. fieldDict, err := indexReader.FieldDictPrefix(field, termPrefix)
  625. if err != nil {
  626. i.mutex.RUnlock()
  627. return nil, err
  628. }
  629. return &indexImplFieldDict{
  630. index: i,
  631. indexReader: indexReader,
  632. fieldDict: fieldDict,
  633. }, nil
  634. }
  635. func (i *indexImpl) Close() error {
  636. i.mutex.Lock()
  637. defer i.mutex.Unlock()
  638. indexStats.UnRegister(i)
  639. i.open = false
  640. return i.i.Close()
  641. }
  642. func (i *indexImpl) Stats() *IndexStat {
  643. return i.stats
  644. }
  645. func (i *indexImpl) StatsMap() map[string]interface{} {
  646. return i.stats.statsMap()
  647. }
  648. func (i *indexImpl) GetInternal(key []byte) (val []byte, err error) {
  649. i.mutex.RLock()
  650. defer i.mutex.RUnlock()
  651. if !i.open {
  652. return nil, ErrorIndexClosed
  653. }
  654. reader, err := i.i.Reader()
  655. if err != nil {
  656. return nil, err
  657. }
  658. defer func() {
  659. if cerr := reader.Close(); err == nil && cerr != nil {
  660. err = cerr
  661. }
  662. }()
  663. val, err = reader.GetInternal(key)
  664. if err != nil {
  665. return nil, err
  666. }
  667. return val, nil
  668. }
  669. func (i *indexImpl) SetInternal(key, val []byte) error {
  670. i.mutex.RLock()
  671. defer i.mutex.RUnlock()
  672. if !i.open {
  673. return ErrorIndexClosed
  674. }
  675. return i.i.SetInternal(key, val)
  676. }
  677. func (i *indexImpl) DeleteInternal(key []byte) error {
  678. i.mutex.RLock()
  679. defer i.mutex.RUnlock()
  680. if !i.open {
  681. return ErrorIndexClosed
  682. }
  683. return i.i.DeleteInternal(key)
  684. }
  685. // NewBatch creates a new empty batch.
  686. func (i *indexImpl) NewBatch() *Batch {
  687. return &Batch{
  688. index: i,
  689. internal: index.NewBatch(),
  690. }
  691. }
  692. func (i *indexImpl) Name() string {
  693. return i.name
  694. }
  695. func (i *indexImpl) SetName(name string) {
  696. indexStats.UnRegister(i)
  697. i.name = name
  698. indexStats.Register(i)
  699. }
  700. type indexImplFieldDict struct {
  701. index *indexImpl
  702. indexReader index.IndexReader
  703. fieldDict index.FieldDict
  704. }
  705. func (f *indexImplFieldDict) Next() (*index.DictEntry, error) {
  706. return f.fieldDict.Next()
  707. }
  708. func (f *indexImplFieldDict) Close() error {
  709. defer f.index.mutex.RUnlock()
  710. err := f.fieldDict.Close()
  711. if err != nil {
  712. return err
  713. }
  714. return f.indexReader.Close()
  715. }
  716. // helper function to remove duplicate entries from slice of strings
  717. func deDuplicate(fields []string) []string {
  718. entries := make(map[string]struct{})
  719. ret := []string{}
  720. for _, entry := range fields {
  721. if _, exists := entries[entry]; !exists {
  722. entries[entry] = struct{}{}
  723. ret = append(ret, entry)
  724. }
  725. }
  726. return ret
  727. }
上海开阖软件有限公司 沪ICP备12045867号-1