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.

facet_builder_numeric.go 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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 facet
  15. import (
  16. "sort"
  17. "github.com/blevesearch/bleve/numeric"
  18. "github.com/blevesearch/bleve/search"
  19. )
  20. type numericRange struct {
  21. min *float64
  22. max *float64
  23. }
  24. type NumericFacetBuilder struct {
  25. size int
  26. field string
  27. termsCount map[string]int
  28. total int
  29. missing int
  30. ranges map[string]*numericRange
  31. sawValue bool
  32. }
  33. func NewNumericFacetBuilder(field string, size int) *NumericFacetBuilder {
  34. return &NumericFacetBuilder{
  35. size: size,
  36. field: field,
  37. termsCount: make(map[string]int),
  38. ranges: make(map[string]*numericRange, 0),
  39. }
  40. }
  41. func (fb *NumericFacetBuilder) AddRange(name string, min, max *float64) {
  42. r := numericRange{
  43. min: min,
  44. max: max,
  45. }
  46. fb.ranges[name] = &r
  47. }
  48. func (fb *NumericFacetBuilder) Field() string {
  49. return fb.field
  50. }
  51. func (fb *NumericFacetBuilder) UpdateVisitor(field string, term []byte) {
  52. if field == fb.field {
  53. fb.sawValue = true
  54. // only consider the values which are shifted 0
  55. prefixCoded := numeric.PrefixCoded(term)
  56. shift, err := prefixCoded.Shift()
  57. if err == nil && shift == 0 {
  58. i64, err := prefixCoded.Int64()
  59. if err == nil {
  60. f64 := numeric.Int64ToFloat64(i64)
  61. // look at each of the ranges for a match
  62. for rangeName, r := range fb.ranges {
  63. if (r.min == nil || f64 >= *r.min) && (r.max == nil || f64 < *r.max) {
  64. fb.termsCount[rangeName] = fb.termsCount[rangeName] + 1
  65. fb.total++
  66. }
  67. }
  68. }
  69. }
  70. }
  71. }
  72. func (fb *NumericFacetBuilder) StartDoc() {
  73. fb.sawValue = false
  74. }
  75. func (fb *NumericFacetBuilder) EndDoc() {
  76. if !fb.sawValue {
  77. fb.missing++
  78. }
  79. }
  80. func (fb *NumericFacetBuilder) Result() *search.FacetResult {
  81. rv := search.FacetResult{
  82. Field: fb.field,
  83. Total: fb.total,
  84. Missing: fb.missing,
  85. }
  86. rv.NumericRanges = make([]*search.NumericRangeFacet, 0, len(fb.termsCount))
  87. for term, count := range fb.termsCount {
  88. numericRange := fb.ranges[term]
  89. tf := &search.NumericRangeFacet{
  90. Name: term,
  91. Count: count,
  92. Min: numericRange.min,
  93. Max: numericRange.max,
  94. }
  95. rv.NumericRanges = append(rv.NumericRanges, tf)
  96. }
  97. sort.Sort(rv.NumericRanges)
  98. // we now have the list of the top N facets
  99. if fb.size < len(rv.NumericRanges) {
  100. rv.NumericRanges = rv.NumericRanges[:fb.size]
  101. }
  102. notOther := 0
  103. for _, nr := range rv.NumericRanges {
  104. notOther += nr.Count
  105. }
  106. rv.Other = fb.total - notOther
  107. return &rv
  108. }