+++ /dev/null
-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 org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.RandomIndexWriter;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.store.Directory;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-
-import java.text.DecimalFormat;
-import java.util.Random;
-
-/** Test that BooleanQuery.setMinimumNumberShouldMatch works.
- */
-public class TestBooleanMinShouldMatch extends LuceneTestCase {
-
- private static Directory index;
- private static IndexReader r;
- private static IndexSearcher s;
-
- @BeforeClass
- public static void beforeClass() throws Exception {
- String[] data = new String [] {
- "A 1 2 3 4 5 6",
- "Z 4 5 6",
- null,
- "B 2 4 5 6",
- "Y 3 5 6",
- null,
- "C 3 6",
- "X 4 5 6"
- };
-
- index = newDirectory();
- RandomIndexWriter w = new RandomIndexWriter(random, index);
-
- for (int i = 0; i < data.length; i++) {
- Document doc = new Document();
- doc.add(newField("id", String.valueOf(i), Field.Store.YES, Field.Index.NOT_ANALYZED));//Field.Keyword("id",String.valueOf(i)));
- doc.add(newField("all", "all", Field.Store.YES, Field.Index.NOT_ANALYZED));//Field.Keyword("all","all"));
- if (null != data[i]) {
- doc.add(newField("data", data[i], Field.Store.YES, Field.Index.ANALYZED));//Field.Text("data",data[i]));
- }
- w.addDocument(doc);
- }
-
- r = w.getReader();
- s = newSearcher(r);
- w.close();
-//System.out.println("Set up " + getName());
- }
-
- @AfterClass
- public static void afterClass() throws Exception {
- s.close();
- s = null;
- r.close();
- r = null;
- index.close();
- index = null;
- }
-
-
- public void verifyNrHits(Query q, int expected) throws Exception {
- ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
- if (expected != h.length) {
- printHits(getName(), h, s);
- }
- assertEquals("result count", expected, h.length);
- QueryUtils.check(random, q,s);
- }
-
- public void testAllOptional() throws Exception {
-
- BooleanQuery q = new BooleanQuery();
- for (int i = 1; i <=4; i++) {
- q.add(new TermQuery(new Term("data",""+i)), BooleanClause.Occur.SHOULD);//false, false);
- }
- q.setMinimumNumberShouldMatch(2); // match at least two of 4
- verifyNrHits(q, 2);
- }
-
- public void testOneReqAndSomeOptional() throws Exception {
-
- /* one required, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.SHOULD);//false, false);
-
- q.setMinimumNumberShouldMatch(2); // 2 of 3 optional
-
- verifyNrHits(q, 5);
- }
-
- public void testSomeReqAndSomeOptional() throws Exception {
-
- /* two required, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.SHOULD);//false, false);
-
- q.setMinimumNumberShouldMatch(2); // 2 of 3 optional
-
- verifyNrHits(q, 5);
- }
-
- public void testOneProhibAndSomeOptional() throws Exception {
-
- /* one prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
-
- q.setMinimumNumberShouldMatch(2); // 2 of 3 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testSomeProhibAndSomeOptional() throws Exception {
-
- /* two prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "C" )), BooleanClause.Occur.MUST_NOT);//false, true );
-
- q.setMinimumNumberShouldMatch(2); // 2 of 3 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testOneReqOneProhibAndSomeOptional() throws Exception {
-
- /* one required, one prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);// true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
-
- q.setMinimumNumberShouldMatch(3); // 3 of 4 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testSomeReqOneProhibAndSomeOptional() throws Exception {
-
- /* two required, one prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all")), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
-
- q.setMinimumNumberShouldMatch(3); // 3 of 4 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testOneReqSomeProhibAndSomeOptional() throws Exception {
-
- /* one required, two prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "C" )), BooleanClause.Occur.MUST_NOT);//false, true );
-
- q.setMinimumNumberShouldMatch(3); // 3 of 4 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testSomeReqSomeProhibAndSomeOptional() throws Exception {
-
- /* two required, two prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all")), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "C" )), BooleanClause.Occur.MUST_NOT);//false, true );
-
- q.setMinimumNumberShouldMatch(3); // 3 of 4 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testMinHigherThenNumOptional() throws Exception {
-
- /* two required, two prohibited, some optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all")), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "5" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "4" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST_NOT);//false, true );
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "1" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "C" )), BooleanClause.Occur.MUST_NOT);//false, true );
-
- q.setMinimumNumberShouldMatch(90); // 90 of 4 optional ?!?!?!
-
- verifyNrHits(q, 0);
- }
-
- public void testMinEqualToNumOptional() throws Exception {
-
- /* two required, two optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "6" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.SHOULD);//false, false);
-
- q.setMinimumNumberShouldMatch(2); // 2 of 2 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testOneOptionalEqualToMin() throws Exception {
-
- /* two required, one optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "3" )), BooleanClause.Occur.SHOULD);//false, false);
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.MUST);//true, false);
-
- q.setMinimumNumberShouldMatch(1); // 1 of 1 optional
-
- verifyNrHits(q, 1);
- }
-
- public void testNoOptionalButMin() throws Exception {
-
- /* two required, no optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all" )), BooleanClause.Occur.MUST);//true, false);
- q.add(new TermQuery(new Term("data", "2" )), BooleanClause.Occur.MUST);//true, false);
-
- q.setMinimumNumberShouldMatch(1); // 1 of 0 optional
-
- verifyNrHits(q, 0);
- }
-
- public void testNoOptionalButMin2() throws Exception {
-
- /* one required, no optional */
- BooleanQuery q = new BooleanQuery();
- q.add(new TermQuery(new Term("all", "all" )), BooleanClause.Occur.MUST);//true, false);
-
- q.setMinimumNumberShouldMatch(1); // 1 of 0 optional
-
- verifyNrHits(q, 0);
- }
-
- public void testRandomQueries() throws Exception {
- String field="data";
- String[] vals = {"1","2","3","4","5","6","A","Z","B","Y","Z","X","foo"};
- int maxLev=4;
-
- // callback object to set a random setMinimumNumberShouldMatch
- TestBoolean2.Callback minNrCB = new TestBoolean2.Callback() {
- public void postCreate(BooleanQuery q) {
- BooleanClause[] c =q.getClauses();
- int opt=0;
- for (int i=0; i<c.length;i++) {
- if (c[i].getOccur() == BooleanClause.Occur.SHOULD) opt++;
- }
- q.setMinimumNumberShouldMatch(random.nextInt(opt+2));
- }
- };
-
-
-
- // increase number of iterations for more complete testing
- int num = atLeast(10);
- for (int i = 0; i < num; i++) {
- int lev = random.nextInt(maxLev);
- final long seed = random.nextLong();
- BooleanQuery q1 = TestBoolean2.randBoolQuery(new Random(seed), true, lev, field, vals, null);
- // BooleanQuery q2 = TestBoolean2.randBoolQuery(new Random(seed), lev, field, vals, minNrCB);
- BooleanQuery q2 = TestBoolean2.randBoolQuery(new Random(seed), true, lev, field, vals, null);
- // only set minimumNumberShouldMatch on the top level query since setting
- // at a lower level can change the score.
- minNrCB.postCreate(q2);
-
- // Can't use Hits because normalized scores will mess things
- // up. The non-sorting version of search() that returns TopDocs
- // will not normalize scores.
- TopDocs top1 = s.search(q1,null,100);
- TopDocs top2 = s.search(q2,null,100);
- if (i < 100) {
- QueryUtils.check(random, q1,s);
- QueryUtils.check(random, q2,s);
- }
- // The constrained query
- // should be a superset to the unconstrained query.
- if (top2.totalHits > top1.totalHits) {
- fail("Constrained results not a subset:\n"
- + CheckHits.topdocsString(top1,0,0)
- + CheckHits.topdocsString(top2,0,0)
- + "for query:" + q2.toString());
- }
-
- for (int hit=0; hit<top2.totalHits; hit++) {
- int id = top2.scoreDocs[hit].doc;
- float score = top2.scoreDocs[hit].score;
- boolean found=false;
- // find this doc in other hits
- for (int other=0; other<top1.totalHits; other++) {
- if (top1.scoreDocs[other].doc == id) {
- found=true;
- float otherScore = top1.scoreDocs[other].score;
- // check if scores match
- if (Math.abs(otherScore-score)>1.0e-6f) {
- fail("Doc " + id + " scores don't match\n"
- + CheckHits.topdocsString(top1,0,0)
- + CheckHits.topdocsString(top2,0,0)
- + "for query:" + q2.toString());
- }
- }
- }
-
- // check if subset
- if (!found) fail("Doc " + id + " not found\n"
- + CheckHits.topdocsString(top1,0,0)
- + CheckHits.topdocsString(top2,0,0)
- + "for query:" + q2.toString());
- }
- }
- // System.out.println("Total hits:"+tot);
- }
-
-
-
- protected void printHits(String test, ScoreDoc[] h, Searcher searcher) throws Exception {
-
- System.err.println("------- " + test + " -------");
-
- DecimalFormat f = new DecimalFormat("0.000000");
-
- for (int i = 0; i < h.length; i++) {
- Document d = searcher.doc(h[i].doc);
- float score = h[i].score;
- System.err.println("#" + i + ": " + f.format(score) + " - " +
- d.get("id") + " - " + d.get("data"));
- }
- }
-}