| Index: src/java/org/apache/lucene/search/BooleanScorer2.java |
| =================================================================== |
| --- src/java/org/apache/lucene/search/BooleanScorer2.java (revision 293416) |
| +++ src/java/org/apache/lucene/search/BooleanScorer2.java (working copy) |
| @@ -37,6 +37,27 @@ |
| private float[] coordFactors = null; |
| |
| void init() { // use after all scorers have been added. |
| + |
| + /* first thing first: if minNrShouldMatch, then we need to rollup |
| + * the optional scorers and make the new scorer required. |
| + */ |
| + if (0 < minNrShouldMatch) { |
| + if (1 < optionalScorers.size()) { |
| + requiredScorers.add(countingDisjunctionSumScorer(optionalScorers, |
| + minNrShouldMatch)); |
| + maxCoord++; |
| + optionalScorers = new ArrayList(); |
| + } else if (1 == optionalScorers.size() && 1 == minNrShouldMatch) { |
| + requiredScorers.add(optionalScorers.get(0)); |
| + maxCoord++; |
| + optionalScorers = new ArrayList(); |
| + } else { |
| + /* remaining situations don't allow for any matches. */ |
| + requiredScorers.add(new NonMatchingScorer()); |
| + maxCoord++; |
| + } |
| + } |
| + |
| coordFactors = new float[maxCoord + 1]; |
| Similarity sim = getSimilarity(); |
| for (int i = 0; i <= maxCoord; i++) { |
| @@ -62,10 +83,17 @@ |
| */ |
| private Scorer countingSumScorer = null; |
| |
| - public BooleanScorer2(Similarity similarity) { |
| + /** The number of optionalScorers that need to match (if there are any) */ |
| + private int minNrShouldMatch = 0; |
| + |
| + public BooleanScorer2(Similarity similarity, int minNrShouldMatch) { |
| super(similarity); |
| coordinator = new Coordinator(); |
| + this.minNrShouldMatch = minNrShouldMatch; |
| } |
| + public BooleanScorer2(Similarity similarity) { |
| + this(similarity, 0); |
| + } |
| |
| public void add(final Scorer scorer, boolean required, boolean prohibited) { |
| if (!prohibited) { |
| @@ -126,10 +154,11 @@ |
| } |
| } |
| |
| - private Scorer countingDisjunctionSumScorer(List scorers) |
| + private Scorer countingDisjunctionSumScorer(List scorers, |
| + int minMrShouldMatch) |
| // each scorer from the list counted as a single matcher |
| { |
| - return new DisjunctionSumScorer(scorers) { |
| + return new DisjunctionSumScorer(scorers, minMrShouldMatch) { |
| private int lastScoredDoc = -1; |
| public float score() throws IOException { |
| if (doc() > lastScoredDoc) { |
| @@ -184,7 +213,7 @@ |
| new ArrayList()); // no optional scorers left |
| } else { // more than 1 optionalScorers, no required scorers |
| return makeCountingSumScorer2( // at least one optional scorer is required |
| - countingDisjunctionSumScorer(optionalScorers), |
| + countingDisjunctionSumScorer(optionalScorers, 1), |
| new ArrayList()); // no optional scorers left |
| } |
| } else if (requiredScorers.size() == 1) { // 1 required |
| @@ -226,7 +255,7 @@ |
| } else { // more optional |
| return makeCountingSumScorer3( |
| requiredCountingSumScorer, |
| - countingDisjunctionSumScorer(optionalScorers)); |
| + countingDisjunctionSumScorer(optionalScorers,1)); |
| } |
| } |
| |
| Index: src/java/org/apache/lucene/search/BooleanQuery.java |
| =================================================================== |
| --- src/java/org/apache/lucene/search/BooleanQuery.java (revision 293416) |
| +++ src/java/org/apache/lucene/search/BooleanQuery.java (working copy) |
| @@ -104,6 +104,34 @@ |
| return result; |
| } |
| |
| + /** |
| + * Specifies a minimum number of the optional BooleanClauses |
| + * which must be satisifed. |
| + * |
| + * <p> |
| + * By default no optional clauses are neccessary for a match |
| + * (unless there are no required clauses). If this method is used, |
| + * then the specified numebr of clauses is required. |
| + * </p> |
| + * <p> |
| + * Use of this method is totally independant of specifying that |
| + * any specific clauses are required (or prohibited). This number will |
| + * only be compared against the number of matching optional clauses. |
| + * </p> |
| + * <p> |
| + * EXPERT NOTE: Using this method will force the use of BooleanWeight2, |
| + * regardless of wether setUseScorer14(true) has been called. |
| + * </p> |
| + * |
| + * @param min the number of optional clauses that must match |
| + * @see #setUseScorer14 |
| + */ |
| + public void setMinimumNumberShouldMatch(int min) { |
| + this.minNrShouldMatch = min; |
| + } |
| + protected int minNrShouldMatch = 0; |
| + |
| + |
| /** Adds a clause to a boolean query. Clauses may be: |
| * <ul> |
| * <li><code>required</code> which means that documents which <i>do not</i> |
| @@ -296,7 +324,8 @@ |
| * and scores documents in document number order. |
| */ |
| public Scorer scorer(IndexReader reader) throws IOException { |
| - BooleanScorer2 result = new BooleanScorer2(similarity); |
| + BooleanScorer2 result = new BooleanScorer2(similarity, |
| + minNrShouldMatch); |
| |
| for (int i = 0 ; i < weights.size(); i++) { |
| BooleanClause c = (BooleanClause)clauses.elementAt(i); |
| @@ -324,6 +353,12 @@ |
| } |
| |
| protected Weight createWeight(Searcher searcher) throws IOException { |
| + |
| + if (0 < minNrShouldMatch) { |
| + // :TODO: should we throw an exception if getUseScorer14 ? |
| + return new BooleanWeight2(searcher); |
| + } |
| + |
| return getUseScorer14() ? (Weight) new BooleanWeight(searcher) |
| : (Weight) new BooleanWeight2(searcher); |
| } |