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.

144 lines
4.4 KiB

  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 search
  15. import (
  16. "fmt"
  17. "github.com/blevesearch/bleve/document"
  18. "github.com/blevesearch/bleve/index"
  19. )
  20. type Location struct {
  21. Pos float64 `json:"pos"`
  22. Start float64 `json:"start"`
  23. End float64 `json:"end"`
  24. ArrayPositions []float64 `json:"array_positions"`
  25. }
  26. // SameArrayElement returns true if two locations are point to
  27. // the same array element
  28. func (l *Location) SameArrayElement(other *Location) bool {
  29. if len(l.ArrayPositions) != len(other.ArrayPositions) {
  30. return false
  31. }
  32. for i, elem := range l.ArrayPositions {
  33. if other.ArrayPositions[i] != elem {
  34. return false
  35. }
  36. }
  37. return true
  38. }
  39. type Locations []*Location
  40. type TermLocationMap map[string]Locations
  41. func (t TermLocationMap) AddLocation(term string, location *Location) {
  42. t[term] = append(t[term], location)
  43. }
  44. type FieldTermLocationMap map[string]TermLocationMap
  45. type FieldFragmentMap map[string][]string
  46. type DocumentMatch struct {
  47. Index string `json:"index,omitempty"`
  48. ID string `json:"id"`
  49. IndexInternalID index.IndexInternalID `json:"-"`
  50. Score float64 `json:"score"`
  51. Expl *Explanation `json:"explanation,omitempty"`
  52. Locations FieldTermLocationMap `json:"locations,omitempty"`
  53. Fragments FieldFragmentMap `json:"fragments,omitempty"`
  54. Sort []string `json:"sort,omitempty"`
  55. // Fields contains the values for document fields listed in
  56. // SearchRequest.Fields. Text fields are returned as strings, numeric
  57. // fields as float64s and date fields as time.RFC3339 formatted strings.
  58. Fields map[string]interface{} `json:"fields,omitempty"`
  59. // as we learn field terms, we can cache important ones for later use
  60. // for example, sorting and building facets need these values
  61. CachedFieldTerms index.FieldTerms `json:"-"`
  62. // if we load the document for this hit, remember it so we dont load again
  63. Document *document.Document `json:"-"`
  64. // used to maintain natural index order
  65. HitNumber uint64 `json:"-"`
  66. }
  67. func (dm *DocumentMatch) AddFieldValue(name string, value interface{}) {
  68. if dm.Fields == nil {
  69. dm.Fields = make(map[string]interface{})
  70. }
  71. existingVal, ok := dm.Fields[name]
  72. if !ok {
  73. dm.Fields[name] = value
  74. return
  75. }
  76. valSlice, ok := existingVal.([]interface{})
  77. if ok {
  78. // already a slice, append to it
  79. valSlice = append(valSlice, value)
  80. } else {
  81. // create a slice
  82. valSlice = []interface{}{existingVal, value}
  83. }
  84. dm.Fields[name] = valSlice
  85. }
  86. // Reset allows an already allocated DocumentMatch to be reused
  87. func (dm *DocumentMatch) Reset() *DocumentMatch {
  88. // remember the []byte used for the IndexInternalID
  89. indexInternalID := dm.IndexInternalID
  90. // remember the []interface{} used for sort
  91. sort := dm.Sort
  92. // idiom to copy over from empty DocumentMatch (0 allocations)
  93. *dm = DocumentMatch{}
  94. // reuse the []byte already allocated (and reset len to 0)
  95. dm.IndexInternalID = indexInternalID[:0]
  96. // reuse the []interface{} already allocated (and reset len to 0)
  97. dm.Sort = sort[:0]
  98. return dm
  99. }
  100. func (dm *DocumentMatch) String() string {
  101. return fmt.Sprintf("[%s-%f]", string(dm.IndexInternalID), dm.Score)
  102. }
  103. type DocumentMatchCollection []*DocumentMatch
  104. func (c DocumentMatchCollection) Len() int { return len(c) }
  105. func (c DocumentMatchCollection) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
  106. func (c DocumentMatchCollection) Less(i, j int) bool { return c[i].Score > c[j].Score }
  107. type Searcher interface {
  108. Next(ctx *SearchContext) (*DocumentMatch, error)
  109. Advance(ctx *SearchContext, ID index.IndexInternalID) (*DocumentMatch, error)
  110. Close() error
  111. Weight() float64
  112. SetQueryNorm(float64)
  113. Count() uint64
  114. Min() int
  115. DocumentMatchPoolSize() int
  116. }
  117. // SearchContext represents the context around a single search
  118. type SearchContext struct {
  119. DocumentMatchPool *DocumentMatchPool
  120. }