github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/search/weights.go (about)

     1  package search
     2  
     3  import (
     4  	"github.com/balzaczyy/golucene/core/index"
     5  	. "github.com/balzaczyy/golucene/core/search/model"
     6  	"github.com/balzaczyy/golucene/core/util"
     7  )
     8  
     9  // search/Weight.java
    10  
    11  /*
    12  Expert: calculate query weights and build query scorers.
    13  
    14  The purpose of Weight is to ensure searching does not modify a Qurey,
    15  so that a Query instance can be reused.
    16  IndexSearcher dependent state of the query should reside in the Weight.
    17  AtomicReader dependent state should reside in the Scorer.
    18  
    19  Since Weight creates Scorer instances for a given AtomicReaderContext
    20  (scorer()), callers must maintain the relationship between the
    21  searcher's top-level IndexReaderCntext and context used to create a
    22  Scorer.
    23  
    24  A Weight is used in the following way:
    25  	1. A Weight is constructed by a top-level query, given a
    26  	IndexSearcher (Query.createWeight()).
    27  	2. The valueForNormalizatin() method is called on the Weight to
    28  	compute the query normalization factor Similarity.queryNorm() of
    29  	the query clauses contained in the query.
    30  	3. The query normlaization factor is passed to normalize(). At this
    31  	point the weighting is complete.
    32  	4. A Scorer is constructed by scorer().
    33  */
    34  type Weight interface {
    35  	// An explanation of the score computation for the named document.
    36  	Explain(*index.AtomicReaderContext, int) (Explanation, error)
    37  	/** The value for normalization of contained query clauses (e.g. sum of squared weights). */
    38  	ValueForNormalization() float32
    39  	/** Assigns the query normalization factor and boost from parent queries to this. */
    40  	Normalize(norm float32, topLevelBoost float32)
    41  	// Scorer(*index.AtomicReaderContext, util.Bits) (Scorer, error)
    42  	/**
    43  	 * Returns a {@link Scorer} which scores documents in/out-of order according
    44  	 * to <code>scoreDocsInOrder</code>.
    45  	 * <p>
    46  	 * <b>NOTE:</b> even if <code>scoreDocsInOrder</code> is false, it is
    47  	 * recommended to check whether the returned <code>Scorer</code> indeed scores
    48  	 * documents out of order (i.e., call {@link #scoresDocsOutOfOrder()}), as
    49  	 * some <code>Scorer</code> implementations will always return documents
    50  	 * in-order.<br>
    51  	 * <b>NOTE:</b> null can be returned if no documents will be scored by this
    52  	 * query.
    53  	 */
    54  	BulkScorer(*index.AtomicReaderContext, bool, util.Bits) (BulkScorer, error)
    55  	/**
    56  	 * Returns true iff this implementation scores docs only out of order. This
    57  	 * method is used in conjunction with {@link Collector}'s
    58  	 * {@link Collector#acceptsDocsOutOfOrder() acceptsDocsOutOfOrder} and
    59  	 * {@link #scorer(AtomicReaderContext, boolean, boolean, Bits)} to
    60  	 * create a matching {@link Scorer} instance for a given {@link Collector}, or
    61  	 * vice versa.
    62  	 * <p>
    63  	 * <b>NOTE:</b> the default implementation returns <code>false</code>, i.e.
    64  	 * the <code>Scorer</code> scores documents in-order.
    65  	 */
    66  	IsScoresDocsOutOfOrder() bool // usually false
    67  }
    68  
    69  type WeightImplSPI interface {
    70  	Scorer(*index.AtomicReaderContext, util.Bits) (Scorer, error)
    71  }
    72  
    73  type WeightImpl struct {
    74  	spi WeightImplSPI
    75  }
    76  
    77  func newWeightImpl(spi WeightImplSPI) *WeightImpl {
    78  	return &WeightImpl{spi}
    79  }
    80  
    81  func (w *WeightImpl) BulkScorer(ctx *index.AtomicReaderContext,
    82  	scoreDocsInOrder bool, acceptDoc util.Bits) (bs BulkScorer, err error) {
    83  
    84  	var scorer Scorer
    85  	if scorer, err = w.spi.Scorer(ctx, acceptDoc); err != nil {
    86  		return nil, err
    87  	} else if scorer == nil {
    88  		// no docs match
    89  		return nil, nil
    90  	}
    91  
    92  	// this impl always scores docs in order, so we can ignore scoreDocsInOrder:
    93  	return newDefaultScorer(scorer), nil
    94  }
    95  
    96  /* Just wraps a Scorer and performs top scoring using it. */
    97  type DefaultBulkScorer struct {
    98  	*BulkScorerImpl
    99  	scorer Scorer
   100  }
   101  
   102  func newDefaultScorer(scorer Scorer) *DefaultBulkScorer {
   103  	assert(scorer != nil)
   104  	ans := &DefaultBulkScorer{scorer: scorer}
   105  	ans.BulkScorerImpl = newBulkScorer(ans)
   106  	return ans
   107  }
   108  
   109  func (s *DefaultBulkScorer) ScoreAndCollectUpto(collector Collector, max int) (ok bool, err error) {
   110  	collector.SetScorer(s.scorer)
   111  	if max == NO_MORE_DOCS {
   112  		return false, s.scoreAll(collector, s.scorer)
   113  	}
   114  	doc := s.scorer.DocId()
   115  	if doc < 0 {
   116  		if doc, err = s.scorer.NextDoc(); err != nil {
   117  			return false, err
   118  		}
   119  	}
   120  	return s.scoreRange(collector, s.scorer, doc, max)
   121  }
   122  
   123  func (s *DefaultBulkScorer) scoreRange(collector Collector,
   124  	scorer Scorer, currentDoc, end int) (bool, error) {
   125  
   126  	var err error
   127  	for currentDoc < end && err == nil {
   128  		if err = collector.Collect(currentDoc); err == nil {
   129  			currentDoc, err = scorer.NextDoc()
   130  		}
   131  	}
   132  	return currentDoc != NO_MORE_DOCS, err
   133  }
   134  
   135  func (s *DefaultBulkScorer) scoreAll(collector Collector, scorer Scorer) (err error) {
   136  	var doc int
   137  	for doc, err = scorer.NextDoc(); doc != NO_MORE_DOCS && err == nil; doc, err = scorer.NextDoc() {
   138  		err = collector.Collect(doc)
   139  	}
   140  	return
   141  }