github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/search/booleanQuery.go (about) 1 package search 2 3 import ( 4 "bytes" 5 "github.com/balzaczyy/golucene/core/index" 6 "github.com/balzaczyy/golucene/core/util" 7 ) 8 9 const maxClauseCount = 1024 10 11 type BooleanQuery struct { 12 *AbstractQuery 13 clauses []*BooleanClause 14 disableCoord bool 15 minNrShouldMatch int 16 } 17 18 func NewBooleanQuery() *BooleanQuery { 19 return NewBooleanQueryDisableCoord(false) 20 } 21 22 func NewBooleanQueryDisableCoord(disableCoord bool) *BooleanQuery { 23 ans := &BooleanQuery{ 24 disableCoord: disableCoord, 25 } 26 ans.AbstractQuery = NewAbstractQuery(ans) 27 return ans 28 } 29 30 func (q *BooleanQuery) Add(query Query, occur Occur) { 31 q.AddClause(NewBooleanClause(query, occur)) 32 } 33 34 func (q *BooleanQuery) AddClause(clause *BooleanClause) { 35 assert(len(q.clauses) < maxClauseCount) 36 q.clauses = append(q.clauses, clause) 37 } 38 39 type BooleanWeight struct { 40 owner *BooleanQuery 41 similarity Similarity 42 weights []Weight 43 maxCoord int // num optional +num required 44 disableCoord bool 45 } 46 47 func newBooleanWeight(owner *BooleanQuery, 48 searcher *IndexSearcher, disableCoord bool) (w *BooleanWeight, err error) { 49 50 w = &BooleanWeight{ 51 owner: owner, 52 similarity: searcher.similarity, 53 disableCoord: disableCoord, 54 } 55 var subWeight Weight 56 for _, c := range owner.clauses { 57 if subWeight, err = c.query.CreateWeight(searcher); err != nil { 58 return nil, err 59 } 60 w.weights = append(w.weights, subWeight) 61 if !c.IsProhibited() { 62 w.maxCoord++ 63 } 64 } 65 return w, nil 66 } 67 68 func (w *BooleanWeight) ValueForNormalization() (sum float32) { 69 for i, subWeight := range w.weights { 70 // call sumOfSquaredWeights for all clauses in case of side effects 71 s := subWeight.ValueForNormalization() // sum sub weights 72 if !w.owner.clauses[i].IsProhibited() { 73 // only add to sum for non-prohibited clauses 74 sum += s 75 } 76 } 77 78 sum *= (w.owner.boost * w.owner.boost) // boost each sub-weight 79 return 80 } 81 82 func (w *BooleanWeight) coord(overlap, maxOverlap int) float32 { 83 if maxOverlap == 1 { 84 return 1 85 } 86 return w.similarity.Coord(overlap, maxOverlap) 87 } 88 89 func (w *BooleanWeight) Normalize(norm, topLevelBoost float32) { 90 topLevelBoost *= w.owner.boost 91 for _, subWeight := range w.weights { 92 // normalize all clauses, (even if prohibited in case of side effects) 93 subWeight.Normalize(norm, topLevelBoost) 94 } 95 } 96 97 func (w *BooleanWeight) Explain(context *index.AtomicReaderContext, doc int) (Explanation, error) { 98 panic("not implemented yet") 99 } 100 101 func (w *BooleanWeight) BulkScorer(context *index.AtomicReaderContext, 102 scoreDocsInOrder bool, acceptDocs util.Bits) (BulkScorer, error) { 103 104 if scoreDocsInOrder || w.owner.minNrShouldMatch > 1 { 105 panic("not implemented yet") 106 } 107 108 var prohibited, optional []BulkScorer 109 for i, subWeight := range w.weights { 110 c := w.owner.clauses[i] 111 subScorer, err := subWeight.BulkScorer(context, false, acceptDocs) 112 if err != nil { 113 return nil, err 114 } 115 if subScorer == nil { 116 if c.IsRequired() { 117 return nil, nil 118 } 119 } else if c.IsRequired() { 120 panic("not implemented yet") 121 } else if c.IsProhibited() { 122 prohibited = append(prohibited, subScorer) 123 } else { 124 optional = append(optional, subScorer) 125 } 126 } 127 128 return newBooleanScorer(w, w.disableCoord, w.owner.minNrShouldMatch, optional, prohibited, w.maxCoord), nil 129 } 130 131 func (w *BooleanWeight) IsScoresDocsOutOfOrder() bool { 132 if w.owner.minNrShouldMatch > 1 { 133 // BS2 (in-order) will be used by scorer() 134 return false 135 } 136 optionalCount := 0 137 for _, c := range w.owner.clauses { 138 if c.IsRequired() { 139 // BS2 (in-order) will be used by scorer() 140 return false 141 } else if !c.IsProhibited() { 142 optionalCount++ 143 } 144 } 145 146 if optionalCount == w.owner.minNrShouldMatch { 147 return false // BS2 (in-order) will be used, as this means conjunction 148 } 149 150 // scorer() will return an out-of-order scorer if requested. 151 return true 152 } 153 154 func (q *BooleanQuery) CreateWeight(searcher *IndexSearcher) (Weight, error) { 155 return newBooleanWeight(q, searcher, q.disableCoord) 156 } 157 158 func (q *BooleanQuery) Rewrite(reader index.IndexReader) Query { 159 if q.minNrShouldMatch == 0 && len(q.clauses) == 1 { 160 panic("not implemented yet") 161 } 162 163 var clone *BooleanQuery // recursively rewrite 164 for _, c := range q.clauses { 165 if query := c.query.Rewrite(reader); query != c.query { 166 // clause rewrote: must clone 167 if clone == nil { 168 // The BooleanQuery clone is lazily initialized so only 169 // initialize it if a rewritten clause differs from the 170 // original clause (and hasn't been initialized already). If 171 // nothing difers, the clone isn't needlessly created 172 panic("not implemented yet") 173 } 174 panic("not implemented yet") 175 } 176 } 177 if clone != nil { 178 return clone // some clauses rewrote 179 } 180 return q 181 } 182 183 func (q *BooleanQuery) ToString(field string) string { 184 var buf bytes.Buffer 185 needParens := q.Boost() != 1 || q.minNrShouldMatch > 0 186 if needParens { 187 buf.WriteRune('(') 188 } 189 190 for i, c := range q.clauses { 191 if c.IsProhibited() { 192 buf.WriteRune('-') 193 } else if c.IsRequired() { 194 buf.WriteRune('+') 195 } 196 197 if subQuery := c.query; subQuery != nil { 198 if _, ok := subQuery.(*BooleanQuery); ok { // wrap sub-bools in parens 199 buf.WriteRune('(') 200 buf.WriteString(subQuery.ToString(field)) 201 buf.WriteRune(')') 202 } else { 203 buf.WriteString(subQuery.ToString(field)) 204 } 205 } else { 206 buf.WriteString("nil") 207 } 208 209 if i != len(q.clauses)-1 { 210 buf.WriteRune(' ') 211 } 212 } 213 214 if needParens { 215 buf.WriteRune(')') 216 } 217 218 if q.minNrShouldMatch > 0 { 219 panic("not implemented yet") 220 } 221 222 if q.Boost() != 1 { 223 panic("not implemented yet") 224 } 225 226 return buf.String() 227 }