You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2013/03/21 21:50:30 UTC

svn commit: r1459521 - /lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java

Author: rmuir
Date: Thu Mar 21 20:50:30 2013
New Revision: 1459521

URL: http://svn.apache.org/r1459521
Log:
LUCENE-4571: improve minShouldMatch testing

Added:
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java   (with props)

Added: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java?rev=1459521&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java (added)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java Thu Mar 21 20:50:30 2013
@@ -0,0 +1,236 @@
+package org.apache.lucene.search;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.SortedSetDocValuesField;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.index.AtomicReader;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanQuery.BooleanWeight;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util._TestUtil;
+import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
+
+/** tests BooleanScorer2's minShouldMatch */
+@SuppressCodecs({"Lucene40", "Lucene41"})
+public class TestMinShouldMatch2 extends LuceneTestCase {
+  Directory dir;
+  DirectoryReader r;
+  AtomicReader reader;
+  IndexSearcher searcher;
+  
+  static final String alwaysTerms[] = { "a" };
+  static final String commonTerms[] = { "b", "c", "d" };
+  static final String mediumTerms[] = { "e", "f", "g" };
+  static final String rareTerms[]   = { "h", "i", "j" };
+  
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    dir = newDirectory();
+    RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
+    final int numDocs = 1000;
+    for (int i = 0; i < numDocs; i++) {
+      Document doc = new Document();
+      
+      addSome(doc, alwaysTerms);
+      
+      if (random().nextInt(100) < 90) {
+        addSome(doc, commonTerms);
+      }
+      if (random().nextInt(100) < 50) {
+        addSome(doc, mediumTerms);
+      }
+      if (random().nextInt(100) < 10) {
+        addSome(doc, rareTerms);
+      }
+      iw.addDocument(doc);
+    }
+    iw.forceMerge(1);
+    iw.close();
+    r = DirectoryReader.open(dir);
+    reader = getOnlySegmentReader(r);
+    searcher = new IndexSearcher(reader);
+  }
+  
+  @Override
+  public void tearDown() throws Exception {
+    reader.close();
+    dir.close();
+    super.tearDown();
+  }
+  
+  private void addSome(Document doc, String values[]) {
+    List<String> list = Arrays.asList(values);
+    Collections.shuffle(list, random());
+    int howMany = _TestUtil.nextInt(random(), 1, list.size());
+    for (int i = 0; i < howMany; i++) {
+      doc.add(new StringField("field", list.get(i), Field.Store.NO));
+      doc.add(new SortedSetDocValuesField("dv", new BytesRef(list.get(i))));
+    }
+  }
+  
+  private Scorer scorer(String values[], int minShouldMatch, boolean slow) throws Exception {
+    BooleanQuery bq = new BooleanQuery();
+    for (String value : values) {
+      bq.add(new TermQuery(new Term("field", value)), BooleanClause.Occur.SHOULD);
+    }
+    bq.setMinimumNumberShouldMatch(minShouldMatch);
+
+    BooleanWeight weight = (BooleanWeight) searcher.createNormalizedWeight(bq);
+    
+    if (slow) {
+      return new SlowMinShouldMatchScorer(weight, reader.getSortedSetDocValues("dv"), reader.maxDoc());
+    } else {
+      return weight.scorer(reader.getContext(), true, false, null);
+    }
+  }
+  
+  private void assertNext(Scorer expected, Scorer actual) throws Exception {
+    if (actual == null) {
+      assertEquals(DocIdSetIterator.NO_MORE_DOCS, expected.nextDoc());
+    }
+    int doc;
+    while ((doc = expected.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
+      assertEquals(doc, actual.nextDoc());
+    }
+    assertEquals(DocIdSetIterator.NO_MORE_DOCS, actual.nextDoc());
+  }
+  
+  private void assertAdvance(Scorer expected, Scorer actual, int amount) throws Exception {
+    if (actual == null) {
+      assertEquals(DocIdSetIterator.NO_MORE_DOCS, expected.nextDoc());
+    }
+    int prevDoc = 0;
+    int doc;
+    while ((doc = expected.advance(prevDoc+amount)) != DocIdSetIterator.NO_MORE_DOCS) {
+      assertEquals(doc, actual.advance(prevDoc+amount));
+      prevDoc = doc;
+    }
+    assertEquals(DocIdSetIterator.NO_MORE_DOCS, actual.advance(prevDoc+amount));
+  }
+  
+  /** simple test for next() */
+  public void testNext() throws Exception {
+    Scorer expected = scorer(new String[] { "b", "f", "j" }, 2, true);
+    Scorer actual = scorer(new String[] { "b", "f", "j" }, 2, false);
+    assertNext(expected, actual);
+  }
+  
+  /** simple test for advance() */
+  public void testAdvance() throws Exception {
+    Scorer expected = scorer(new String[] { "b", "f", "j" }, 2, true);
+    Scorer actual = scorer(new String[] { "b", "f", "j" }, 2, false);
+    assertAdvance(expected, actual, 25);
+  }
+  
+  // TODO: more tests
+  
+  // a slow min-should match scorer that uses a docvalues field.
+  // later, we can make debugging easier as it can record the set of ords it currently matched
+  // and e.g. print out their values and so on for the document
+  static class SlowMinShouldMatchScorer extends Scorer {
+    int currentDoc = -1;     // current docid
+    int currentMatched = -1; // current number of terms matched
+    
+    final SortedSetDocValues dv;
+    final int maxDoc;
+
+    final Set<Long> ords = new HashSet<Long>();
+    final int minNrShouldMatch;
+
+    SlowMinShouldMatchScorer(BooleanWeight weight, SortedSetDocValues dv, int maxDoc) {
+      super(weight);
+      this.dv = dv;
+      this.maxDoc = maxDoc;
+      BooleanQuery bq = (BooleanQuery) weight.getQuery();
+      this.minNrShouldMatch = bq.getMinimumNumberShouldMatch();
+      for (BooleanClause clause : bq.getClauses()) {
+        assert !clause.isProhibited();
+        assert !clause.isRequired();
+        Term term = ((TermQuery)clause.getQuery()).getTerm();
+        long ord = dv.lookupTerm(term.bytes());
+        if (ord >= 0) {
+          boolean success = ords.add(ord);
+          assert success; // no dups
+        }
+      }
+    }
+
+    @Override
+    public float score() throws IOException {
+      return 1.0f; // bogus
+    }
+
+    @Override
+    public int freq() throws IOException {
+      return currentMatched;
+    }
+
+    @Override
+    public int docID() {
+      return currentDoc;
+    }
+
+    @Override
+    public int nextDoc() throws IOException {
+      assert currentDoc != NO_MORE_DOCS;
+      for (currentDoc = currentDoc+1; currentDoc < maxDoc; currentDoc++) {
+        currentMatched = 0;
+        dv.setDocument(currentDoc);
+        long ord;
+        while ((ord = dv.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+          if (ords.contains(ord)) {
+            currentMatched++;
+          }
+        }
+        if (currentMatched >= minNrShouldMatch) {
+          return currentDoc;
+        }
+      }
+      return currentDoc = NO_MORE_DOCS;
+    }
+
+    @Override
+    public int advance(int target) throws IOException {
+      int doc;
+      while ((doc = nextDoc()) < target) {
+      }
+      return doc;
+    }
+
+    @Override
+    public long cost() {
+      return maxDoc;
+    }
+  }
+}