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.

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