facets_builder.go 8.6 KB

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