/* * 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. */ using System; using Lucene.Net.Index; using Lucene.Net.Store; using NUnit.Framework; using WhitespaceAnalyzer = Lucene.Net.Analysis.WhitespaceAnalyzer; using Document = Lucene.Net.Documents.Document; using Field = Lucene.Net.Documents.Field; using IndexWriter = Lucene.Net.Index.IndexWriter; using Term = Lucene.Net.Index.Term; using ParseException = Lucene.Net.QueryParsers.ParseException; using QueryParser = Lucene.Net.QueryParsers.QueryParser; using RAMDirectory = Lucene.Net.Store.RAMDirectory; using LuceneTestCase = Lucene.Net.Util.LuceneTestCase; namespace Lucene.Net.Search { /// Test BooleanQuery2 against BooleanQuery by overriding the standard query parser. /// This also tests the scoring order of BooleanQuery. /// [TestFixture] public class TestBoolean2:LuceneTestCase { [Serializable] private class AnonymousClassDefaultSimilarity:DefaultSimilarity { public AnonymousClassDefaultSimilarity(TestBoolean2 enclosingInstance) { InitBlock(enclosingInstance); } private void InitBlock(TestBoolean2 enclosingInstance) { this.enclosingInstance = enclosingInstance; } private TestBoolean2 enclosingInstance; public TestBoolean2 Enclosing_Instance { get { return enclosingInstance; } } public override float Coord(int overlap, int maxOverlap) { return overlap / ((float) maxOverlap - 1); } } private IndexSearcher searcher; private IndexSearcher bigSearcher; private IndexReader reader; private static int NUM_EXTRA_DOCS = 6000; public const System.String field = "field"; private Directory dir2; private int mulFactor; [SetUp] public override void SetUp() { base.SetUp(); RAMDirectory directory = new RAMDirectory(); IndexWriter writer = new IndexWriter(directory, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); for (int i = 0; i < docFields.Length; i++) { Document document = new Document(); document.Add(new Field(field, docFields[i], Field.Store.NO, Field.Index.ANALYZED)); writer.AddDocument(document); } writer.Close(); searcher = new IndexSearcher(directory, true); // Make big index dir2 = new MockRAMDirectory(directory); // First multiply small test index: mulFactor = 1; int docCount = 0; do { Directory copy = new RAMDirectory(dir2); IndexWriter indexWriter = new IndexWriter(dir2, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); indexWriter.AddIndexesNoOptimize(new[] {copy}); docCount = indexWriter.MaxDoc(); indexWriter.Close(); mulFactor *= 2; } while (docCount < 3000); IndexWriter w = new IndexWriter(dir2, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); Document doc = new Document(); doc.Add(new Field("field2", "xxx", Field.Store.NO, Field.Index.ANALYZED)); for (int i = 0; i < NUM_EXTRA_DOCS / 2; i++) { w.AddDocument(doc); } doc = new Document(); doc.Add(new Field("field2", "big bad bug", Field.Store.NO, Field.Index.ANALYZED)); for (int i = 0; i < NUM_EXTRA_DOCS / 2; i++) { w.AddDocument(doc); } // optimize to 1 segment w.Optimize(); reader = w.GetReader(); w.Close(); bigSearcher = new IndexSearcher(reader); } [TearDown] public override void TearDown() { reader.Close(); dir2.Close(); } private System.String[] docFields = new System.String[]{"w1 w2 w3 w4 w5", "w1 w3 w2 w3", "w1 xx w2 yy w3", "w1 w3 xx w2 yy w3"}; public virtual Query MakeQuery(System.String queryText) { Query q = (new QueryParser(Util.Version.LUCENE_CURRENT, field, new WhitespaceAnalyzer())).Parse(queryText); return q; } public virtual void QueriesTest(System.String queryText, int[] expDocNrs) { //System.out.println(); //System.out.println("Query: " + queryText); Query query1 = MakeQuery(queryText); TopScoreDocCollector collector = TopScoreDocCollector.Create(1000, false); searcher.Search(query1, null, collector); ScoreDoc[] hits1 = collector.TopDocs().ScoreDocs; Query query2 = MakeQuery(queryText); // there should be no need to parse again... collector = TopScoreDocCollector.Create(1000, true); searcher.Search(query2, null, collector); ScoreDoc[] hits2 = collector.TopDocs().ScoreDocs; Assert.AreEqual(mulFactor*collector.internalTotalHits, bigSearcher.Search(query1, 1).TotalHits); CheckHits.CheckHitsQuery(query2, hits1, hits2, expDocNrs); } [Test] public virtual void TestQueries01() { System.String queryText = "+w3 +xx"; int[] expDocNrs = new int[]{2, 3}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries02() { System.String queryText = "+w3 xx"; int[] expDocNrs = new int[]{2, 3, 1, 0}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries03() { System.String queryText = "w3 xx"; int[] expDocNrs = new int[]{2, 3, 1, 0}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries04() { System.String queryText = "w3 -xx"; int[] expDocNrs = new int[]{1, 0}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries05() { System.String queryText = "+w3 -xx"; int[] expDocNrs = new int[]{1, 0}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries06() { System.String queryText = "+w3 -xx -w5"; int[] expDocNrs = new int[]{1}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries07() { System.String queryText = "-w3 -xx -w5"; int[] expDocNrs = new int[]{}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries08() { System.String queryText = "+w3 xx -w5"; int[] expDocNrs = new int[]{2, 3, 1}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries09() { System.String queryText = "+w3 +xx +w2 zz"; int[] expDocNrs = new int[]{2, 3}; QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestQueries10() { System.String queryText = "+w3 +xx +w2 zz"; int[] expDocNrs = new int[]{2, 3}; searcher.Similarity = new AnonymousClassDefaultSimilarity(this); QueriesTest(queryText, expDocNrs); } [Test] public virtual void TestRandomQueries() { System.Random rnd = NewRandom(); System.String[] vals = new System.String[]{"w1", "w2", "w3", "w4", "w5", "xx", "yy", "zzz"}; int tot = 0; BooleanQuery q1 = null; try { // increase number of iterations for more complete testing for (int i = 0; i < 1000; i++) { int level = rnd.Next(3); q1 = RandBoolQuery(new System.Random(rnd.Next(System.Int32.MaxValue)), rnd.Next(0, 2) == 0 ? false : true, level, field, vals, null); // Can't sort by relevance since floating point numbers may not quite // match up. Sort sort = Sort.INDEXORDER; QueryUtils.Check(q1, searcher); TopFieldCollector collector = TopFieldCollector.Create(sort, 1000, false, true, true, true); searcher.Search(q1, null, collector); ScoreDoc[] hits1 = collector.TopDocs().ScoreDocs; collector = TopFieldCollector.Create(sort, 1000, false, true, true, false); searcher.Search(q1, null, collector); ScoreDoc[] hits2 = collector.TopDocs().ScoreDocs; tot += hits2.Length; CheckHits.CheckEqual(q1, hits1, hits2); BooleanQuery q3 = new BooleanQuery(); q3.Add(q1, Occur.SHOULD); q3.Add(new PrefixQuery(new Term("field2", "b")), Occur.SHOULD); TopDocs hits4 = bigSearcher.Search(q3, 1); Assert.AreEqual(mulFactor*collector.internalTotalHits + NUM_EXTRA_DOCS/2, hits4.TotalHits); } } catch (System.Exception e) { // For easier debugging System.Console.Out.WriteLine("failed query: " + q1); throw e; } // System.out.println("Total hits:"+tot); } // used to set properties or change every BooleanQuery // generated from randBoolQuery. public interface Callback { void PostCreate(BooleanQuery q); } // Random rnd is passed in so that the exact same random query may be created // more than once. public static BooleanQuery RandBoolQuery(System.Random rnd, bool allowMust, int level, System.String field, System.String[] vals, TestBoolean2.Callback cb) { BooleanQuery current = new BooleanQuery(rnd.Next() < 0); for (int i = 0; i < rnd.Next(vals.Length) + 1; i++) { int qType = 0; // term query if (level > 0) { qType = rnd.Next(10); } Query q; if (qType < 3) { q = new TermQuery(new Term(field, vals[rnd.Next(vals.Length)])); } else if (qType < 7) { q = new WildcardQuery(new Term(field, "w*")); } else { q = RandBoolQuery(rnd, allowMust, level - 1, field, vals, cb); } int r = rnd.Next(10); Occur occur; if (r < 2) { occur = Occur.MUST_NOT; } else if (r < 5) { occur = allowMust ? Occur.MUST : Occur.SHOULD; } else { occur = Occur.SHOULD; } current.Add(q, occur); } if (cb != null) cb.PostCreate(current); return current; } } }