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.

296 lines
7.5 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. "sort"
  17. "github.com/blevesearch/bleve/index"
  18. )
  19. type FacetBuilder interface {
  20. Update(index.FieldTerms)
  21. Result() *FacetResult
  22. Field() string
  23. }
  24. type FacetsBuilder struct {
  25. indexReader index.IndexReader
  26. facets map[string]FacetBuilder
  27. fields []string
  28. }
  29. func NewFacetsBuilder(indexReader index.IndexReader) *FacetsBuilder {
  30. return &FacetsBuilder{
  31. indexReader: indexReader,
  32. facets: make(map[string]FacetBuilder, 0),
  33. }
  34. }
  35. func (fb *FacetsBuilder) Add(name string, facetBuilder FacetBuilder) {
  36. fb.facets[name] = facetBuilder
  37. }
  38. func (fb *FacetsBuilder) Update(docMatch *DocumentMatch) error {
  39. if fb.fields == nil {
  40. for _, facetBuilder := range fb.facets {
  41. fb.fields = append(fb.fields, facetBuilder.Field())
  42. }
  43. }
  44. if len(fb.fields) > 0 {
  45. // find out which fields haven't been loaded yet
  46. fieldsToLoad := docMatch.CachedFieldTerms.FieldsNotYetCached(fb.fields)
  47. // look them up
  48. fieldTerms, err := fb.indexReader.DocumentFieldTerms(docMatch.IndexInternalID, fieldsToLoad)
  49. if err != nil {
  50. return err
  51. }
  52. // cache these as well
  53. if docMatch.CachedFieldTerms == nil {
  54. docMatch.CachedFieldTerms = make(map[string][]string)
  55. }
  56. docMatch.CachedFieldTerms.Merge(fieldTerms)
  57. }
  58. for _, facetBuilder := range fb.facets {
  59. facetBuilder.Update(docMatch.CachedFieldTerms)
  60. }
  61. return nil
  62. }
  63. type TermFacet struct {
  64. Term string `json:"term"`
  65. Count int `json:"count"`
  66. }
  67. type TermFacets []*TermFacet
  68. func (tf TermFacets) Add(termFacet *TermFacet) TermFacets {
  69. for _, existingTerm := range tf {
  70. if termFacet.Term == existingTerm.Term {
  71. existingTerm.Count += termFacet.Count
  72. return tf
  73. }
  74. }
  75. // if we got here it wasn't already in the existing terms
  76. tf = append(tf, termFacet)
  77. return tf
  78. }
  79. func (tf TermFacets) Len() int { return len(tf) }
  80. func (tf TermFacets) Swap(i, j int) { tf[i], tf[j] = tf[j], tf[i] }
  81. func (tf TermFacets) Less(i, j int) bool {
  82. if tf[i].Count == tf[j].Count {
  83. return tf[i].Term < tf[j].Term
  84. }
  85. return tf[i].Count > tf[j].Count
  86. }
  87. type NumericRangeFacet struct {
  88. Name string `json:"name"`
  89. Min *float64 `json:"min,omitempty"`
  90. Max *float64 `json:"max,omitempty"`
  91. Count int `json:"count"`
  92. }
  93. func (nrf *NumericRangeFacet) Same(other *NumericRangeFacet) bool {
  94. if nrf.Min == nil && other.Min != nil {
  95. return false
  96. }
  97. if nrf.Min != nil && other.Min == nil {
  98. return false
  99. }
  100. if nrf.Min != nil && other.Min != nil && *nrf.Min != *other.Min {
  101. return false
  102. }
  103. if nrf.Max == nil && other.Max != nil {
  104. return false
  105. }
  106. if nrf.Max != nil && other.Max == nil {
  107. return false
  108. }
  109. if nrf.Max != nil && other.Max != nil && *nrf.Max != *other.Max {
  110. return false
  111. }
  112. return true
  113. }
  114. type NumericRangeFacets []*NumericRangeFacet
  115. func (nrf NumericRangeFacets) Add(numericRangeFacet *NumericRangeFacet) NumericRangeFacets {
  116. for _, existingNr := range nrf {
  117. if numericRangeFacet.Same(existingNr) {
  118. existingNr.Count += numericRangeFacet.Count
  119. return nrf
  120. }
  121. }
  122. // if we got here it wasn't already in the existing terms
  123. nrf = append(nrf, numericRangeFacet)
  124. return nrf
  125. }
  126. func (nrf NumericRangeFacets) Len() int { return len(nrf) }
  127. func (nrf NumericRangeFacets) Swap(i, j int) { nrf[i], nrf[j] = nrf[j], nrf[i] }
  128. func (nrf NumericRangeFacets) Less(i, j int) bool {
  129. if nrf[i].Count == nrf[j].Count {
  130. return nrf[i].Name < nrf[j].Name
  131. }
  132. return nrf[i].Count > nrf[j].Count
  133. }
  134. type DateRangeFacet struct {
  135. Name string `json:"name"`
  136. Start *string `json:"start,omitempty"`
  137. End *string `json:"end,omitempty"`
  138. Count int `json:"count"`
  139. }
  140. func (drf *DateRangeFacet) Same(other *DateRangeFacet) bool {
  141. if drf.Start == nil && other.Start != nil {
  142. return false
  143. }
  144. if drf.Start != nil && other.Start == nil {
  145. return false
  146. }
  147. if drf.Start != nil && other.Start != nil && *drf.Start != *other.Start {
  148. return false
  149. }
  150. if drf.End == nil && other.End != nil {
  151. return false
  152. }
  153. if drf.End != nil && other.End == nil {
  154. return false
  155. }
  156. if drf.End != nil && other.End != nil && *drf.End != *other.End {
  157. return false
  158. }
  159. return true
  160. }
  161. type DateRangeFacets []*DateRangeFacet
  162. func (drf DateRangeFacets) Add(dateRangeFacet *DateRangeFacet) DateRangeFacets {
  163. for _, existingDr := range drf {
  164. if dateRangeFacet.Same(existingDr) {
  165. existingDr.Count += dateRangeFacet.Count
  166. return drf
  167. }
  168. }
  169. // if we got here it wasn't already in the existing terms
  170. drf = append(drf, dateRangeFacet)
  171. return drf
  172. }
  173. func (drf DateRangeFacets) Len() int { return len(drf) }
  174. func (drf DateRangeFacets) Swap(i, j int) { drf[i], drf[j] = drf[j], drf[i] }
  175. func (drf DateRangeFacets) Less(i, j int) bool {
  176. if drf[i].Count == drf[j].Count {
  177. return drf[i].Name < drf[j].Name
  178. }
  179. return drf[i].Count > drf[j].Count
  180. }
  181. type FacetResult struct {
  182. Field string `json:"field"`
  183. Total int `json:"total"`
  184. Missing int `json:"missing"`
  185. Other int `json:"other"`
  186. Terms TermFacets `json:"terms,omitempty"`
  187. NumericRanges NumericRangeFacets `json:"numeric_ranges,omitempty"`
  188. DateRanges DateRangeFacets `json:"date_ranges,omitempty"`
  189. }
  190. func (fr *FacetResult) Merge(other *FacetResult) {
  191. fr.Total += other.Total
  192. fr.Missing += other.Missing
  193. fr.Other += other.Other
  194. if fr.Terms != nil && other.Terms != nil {
  195. for _, term := range other.Terms {
  196. fr.Terms = fr.Terms.Add(term)
  197. }
  198. }
  199. if fr.NumericRanges != nil && other.NumericRanges != nil {
  200. for _, nr := range other.NumericRanges {
  201. fr.NumericRanges = fr.NumericRanges.Add(nr)
  202. }
  203. }
  204. if fr.DateRanges != nil && other.DateRanges != nil {
  205. for _, dr := range other.DateRanges {
  206. fr.DateRanges = fr.DateRanges.Add(dr)
  207. }
  208. }
  209. }
  210. func (fr *FacetResult) Fixup(size int) {
  211. if fr.Terms != nil {
  212. sort.Sort(fr.Terms)
  213. if len(fr.Terms) > size {
  214. moveToOther := fr.Terms[size:]
  215. for _, mto := range moveToOther {
  216. fr.Other += mto.Count
  217. }
  218. fr.Terms = fr.Terms[0:size]
  219. }
  220. } else if fr.NumericRanges != nil {
  221. sort.Sort(fr.NumericRanges)
  222. if len(fr.NumericRanges) > size {
  223. moveToOther := fr.NumericRanges[size:]
  224. for _, mto := range moveToOther {
  225. fr.Other += mto.Count
  226. }
  227. fr.NumericRanges = fr.NumericRanges[0:size]
  228. }
  229. } else if fr.DateRanges != nil {
  230. sort.Sort(fr.DateRanges)
  231. if len(fr.DateRanges) > size {
  232. moveToOther := fr.DateRanges[size:]
  233. for _, mto := range moveToOther {
  234. fr.Other += mto.Count
  235. }
  236. fr.DateRanges = fr.DateRanges[0:size]
  237. }
  238. }
  239. }
  240. type FacetResults map[string]*FacetResult
  241. func (fr FacetResults) Merge(other FacetResults) {
  242. for name, oFacetResult := range other {
  243. facetResult, ok := fr[name]
  244. if ok {
  245. facetResult.Merge(oFacetResult)
  246. } else {
  247. fr[name] = oFacetResult
  248. }
  249. }
  250. }
  251. func (fr FacetResults) Fixup(name string, size int) {
  252. facetResult, ok := fr[name]
  253. if ok {
  254. facetResult.Fixup(size)
  255. }
  256. }
  257. func (fb *FacetsBuilder) Results() FacetResults {
  258. fr := make(FacetResults)
  259. for facetName, facetBuilder := range fb.facets {
  260. facetResult := facetBuilder.Result()
  261. fr[facetName] = facetResult
  262. }
  263. return fr
  264. }