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 15package facet 16 17import ( 18 "reflect" 19 "sort" 20 21 "github.com/blevesearch/bleve/search" 22 "github.com/blevesearch/bleve/size" 23) 24 25var reflectStaticSizeTermsFacetBuilder int 26 27func init() { 28 var tfb TermsFacetBuilder 29 reflectStaticSizeTermsFacetBuilder = int(reflect.TypeOf(tfb).Size()) 30} 31 32type TermsFacetBuilder struct { 33 size int 34 field string 35 termsCount map[string]int 36 total int 37 missing int 38 sawValue bool 39} 40 41func NewTermsFacetBuilder(field string, size int) *TermsFacetBuilder { 42 return &TermsFacetBuilder{ 43 size: size, 44 field: field, 45 termsCount: make(map[string]int), 46 } 47} 48 49func (fb *TermsFacetBuilder) Size() int { 50 sizeInBytes := reflectStaticSizeTermsFacetBuilder + size.SizeOfPtr + 51 len(fb.field) 52 53 for k, _ := range fb.termsCount { 54 sizeInBytes += size.SizeOfString + len(k) + 55 size.SizeOfInt 56 } 57 58 return sizeInBytes 59} 60 61func (fb *TermsFacetBuilder) Field() string { 62 return fb.field 63} 64 65func (fb *TermsFacetBuilder) UpdateVisitor(field string, term []byte) { 66 if field == fb.field { 67 fb.sawValue = true 68 fb.termsCount[string(term)] = fb.termsCount[string(term)] + 1 69 fb.total++ 70 } 71} 72 73func (fb *TermsFacetBuilder) StartDoc() { 74 fb.sawValue = false 75} 76 77func (fb *TermsFacetBuilder) EndDoc() { 78 if !fb.sawValue { 79 fb.missing++ 80 } 81} 82 83func (fb *TermsFacetBuilder) Result() *search.FacetResult { 84 rv := search.FacetResult{ 85 Field: fb.field, 86 Total: fb.total, 87 Missing: fb.missing, 88 } 89 90 rv.Terms = make([]*search.TermFacet, 0, len(fb.termsCount)) 91 92 for term, count := range fb.termsCount { 93 tf := &search.TermFacet{ 94 Term: term, 95 Count: count, 96 } 97 98 rv.Terms = append(rv.Terms, tf) 99 } 100 101 sort.Sort(rv.Terms) 102 103 // we now have the list of the top N facets 104 trimTopN := fb.size 105 if trimTopN > len(rv.Terms) { 106 trimTopN = len(rv.Terms) 107 } 108 rv.Terms = rv.Terms[:trimTopN] 109 110 notOther := 0 111 for _, tf := range rv.Terms { 112 notOther += tf.Count 113 } 114 rv.Other = fb.total - notOther 115 116 return &rv 117} 118