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  }