pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / backwards / src / test / org / apache / lucene / search / TestDisjunctionMaxQuery.java
1 package org.apache.lucene.search;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import org.apache.lucene.util.LuceneTestCase;
21 import org.apache.lucene.analysis.MockAnalyzer;
22 import org.apache.lucene.analysis.WhitespaceAnalyzer;
23 import org.apache.lucene.document.Document;
24 import org.apache.lucene.document.Field;
25 import org.apache.lucene.index.IndexReader;
26 import org.apache.lucene.index.FieldInvertState;
27 import org.apache.lucene.index.RandomIndexWriter;
28 import org.apache.lucene.index.Term;
29 import org.apache.lucene.store.Directory;
30
31 import java.text.DecimalFormat;
32 import java.io.IOException;
33
34 /**
35  * Test of the DisjunctionMaxQuery.
36  * 
37  */
38 public class TestDisjunctionMaxQuery extends LuceneTestCase {
39   
40   /** threshold for comparing floats */
41   public static final float SCORE_COMP_THRESH = 0.0000f;
42   
43   /**
44    * Similarity to eliminate tf, idf and lengthNorm effects to isolate test
45    * case.
46    * 
47    * <p>
48    * same as TestRankingSimilarity in TestRanking.zip from
49    * http://issues.apache.org/jira/browse/LUCENE-323
50    * </p>
51    */
52   private static class TestSimilarity extends DefaultSimilarity {
53     
54     public TestSimilarity() {}
55     
56     @Override
57     public float tf(float freq) {
58       if (freq > 0.0f) return 1.0f;
59       else return 0.0f;
60     }
61     
62     @Override
63     public float computeNorm(String fieldName, FieldInvertState state) {
64       // Disable length norm
65       return state.getBoost();
66     }
67     
68     @Override
69     public float idf(int docFreq, int numDocs) {
70       return 1.0f;
71     }
72   }
73   
74   public Similarity sim = new TestSimilarity();
75   public Directory index;
76   public IndexReader r;
77   public IndexSearcher s;
78   
79   @Override
80   public void setUp() throws Exception {
81     super.setUp();
82     
83     index = newDirectory();
84     RandomIndexWriter writer = new RandomIndexWriter(random, index,
85         newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))
86                                                      .setSimilarity(sim).setMergePolicy(newLogMergePolicy()));
87     
88     // hed is the most important field, dek is secondary
89     
90     // d1 is an "ok" match for: albino elephant
91     {
92       Document d1 = new Document();
93       d1.add(newField("id", "d1", Field.Store.YES, Field.Index.NOT_ANALYZED));// Field.Keyword("id",
94                                                                                // "d1"));
95       d1
96           .add(newField("hed", "elephant", Field.Store.YES,
97               Field.Index.ANALYZED));// Field.Text("hed", "elephant"));
98       d1
99           .add(newField("dek", "elephant", Field.Store.YES,
100               Field.Index.ANALYZED));// Field.Text("dek", "elephant"));
101       writer.addDocument(d1);
102     }
103     
104     // d2 is a "good" match for: albino elephant
105     {
106       Document d2 = new Document();
107       d2.add(newField("id", "d2", Field.Store.YES, Field.Index.NOT_ANALYZED));// Field.Keyword("id",
108                                                                                // "d2"));
109       d2
110           .add(newField("hed", "elephant", Field.Store.YES,
111               Field.Index.ANALYZED));// Field.Text("hed", "elephant"));
112       d2.add(newField("dek", "albino", Field.Store.YES, Field.Index.ANALYZED));// Field.Text("dek",
113                                                                                 // "albino"));
114       d2
115           .add(newField("dek", "elephant", Field.Store.YES,
116               Field.Index.ANALYZED));// Field.Text("dek", "elephant"));
117       writer.addDocument(d2);
118     }
119     
120     // d3 is a "better" match for: albino elephant
121     {
122       Document d3 = new Document();
123       d3.add(newField("id", "d3", Field.Store.YES, Field.Index.NOT_ANALYZED));// Field.Keyword("id",
124                                                                                // "d3"));
125       d3.add(newField("hed", "albino", Field.Store.YES, Field.Index.ANALYZED));// Field.Text("hed",
126                                                                                 // "albino"));
127       d3
128           .add(newField("hed", "elephant", Field.Store.YES,
129               Field.Index.ANALYZED));// Field.Text("hed", "elephant"));
130       writer.addDocument(d3);
131     }
132     
133     // d4 is the "best" match for: albino elephant
134     {
135       Document d4 = new Document();
136       d4.add(newField("id", "d4", Field.Store.YES, Field.Index.NOT_ANALYZED));// Field.Keyword("id",
137                                                                                // "d4"));
138       d4.add(newField("hed", "albino", Field.Store.YES, Field.Index.ANALYZED));// Field.Text("hed",
139                                                                                 // "albino"));
140       d4
141           .add(newField("hed", "elephant", Field.Store.YES,
142               Field.Index.ANALYZED));// Field.Text("hed", "elephant"));
143       d4.add(newField("dek", "albino", Field.Store.YES, Field.Index.ANALYZED));// Field.Text("dek",
144                                                                                 // "albino"));
145       writer.addDocument(d4);
146     }
147
148     writer.optimize();
149     r = writer.getReader();
150     writer.close();
151     s = newSearcher(r);
152     s.setSimilarity(sim);
153   }
154   
155   @Override
156   public void tearDown() throws Exception {
157     s.close();
158     r.close();
159     index.close();
160     super.tearDown();
161   }
162   
163   public void testSkipToFirsttimeMiss() throws IOException {
164     final DisjunctionMaxQuery dq = new DisjunctionMaxQuery(0.0f);
165     dq.add(tq("id", "d1"));
166     dq.add(tq("dek", "DOES_NOT_EXIST"));
167     
168     QueryUtils.check(random, dq, s);
169     
170     final Weight dw = s.createNormalizedWeight(dq);
171     IndexReader sub = s.getIndexReader().getSequentialSubReaders() == null ?
172         s.getIndexReader() : s.getIndexReader().getSequentialSubReaders()[0];
173     final Scorer ds = dw.scorer(sub, true, false);
174     final boolean skipOk = ds.advance(3) != DocIdSetIterator.NO_MORE_DOCS;
175     if (skipOk) {
176       fail("firsttime skipTo found a match? ... "
177           + r.document(ds.docID()).get("id"));
178     }
179   }
180   
181   public void testSkipToFirsttimeHit() throws IOException {
182     final DisjunctionMaxQuery dq = new DisjunctionMaxQuery(0.0f);
183     dq.add(tq("dek", "albino"));
184     dq.add(tq("dek", "DOES_NOT_EXIST"));
185     
186     QueryUtils.check(random, dq, s);
187
188     final Weight dw = s.createNormalizedWeight(dq);
189     IndexReader sub = s.getIndexReader().getSequentialSubReaders() == null ?
190         s.getIndexReader() : s.getIndexReader().getSequentialSubReaders()[0];
191     final Scorer ds = dw.scorer(sub, true, false);
192     assertTrue("firsttime skipTo found no match",
193         ds.advance(3) != DocIdSetIterator.NO_MORE_DOCS);
194     assertEquals("found wrong docid", "d4", r.document(ds.docID()).get("id"));
195   }
196   
197   public void testSimpleEqualScores1() throws Exception {
198     
199     DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
200     q.add(tq("hed", "albino"));
201     q.add(tq("hed", "elephant"));
202     QueryUtils.check(random, q, s);
203     
204     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
205     
206     try {
207       assertEquals("all docs should match " + q.toString(), 4, h.length);
208       
209       float score = h[0].score;
210       for (int i = 1; i < h.length; i++) {
211         assertEquals("score #" + i + " is not the same", score, h[i].score,
212             SCORE_COMP_THRESH);
213       }
214     } catch (Error e) {
215       printHits("testSimpleEqualScores1", h, s);
216       throw e;
217     }
218     
219   }
220   
221   public void testSimpleEqualScores2() throws Exception {
222     
223     DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
224     q.add(tq("dek", "albino"));
225     q.add(tq("dek", "elephant"));
226     QueryUtils.check(random, q, s);
227     
228     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
229     
230     try {
231       assertEquals("3 docs should match " + q.toString(), 3, h.length);
232       float score = h[0].score;
233       for (int i = 1; i < h.length; i++) {
234         assertEquals("score #" + i + " is not the same", score, h[i].score,
235             SCORE_COMP_THRESH);
236       }
237     } catch (Error e) {
238       printHits("testSimpleEqualScores2", h, s);
239       throw e;
240     }
241     
242   }
243   
244   public void testSimpleEqualScores3() throws Exception {
245     
246     DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
247     q.add(tq("hed", "albino"));
248     q.add(tq("hed", "elephant"));
249     q.add(tq("dek", "albino"));
250     q.add(tq("dek", "elephant"));
251     QueryUtils.check(random, q, s);
252     
253     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
254     
255     try {
256       assertEquals("all docs should match " + q.toString(), 4, h.length);
257       float score = h[0].score;
258       for (int i = 1; i < h.length; i++) {
259         assertEquals("score #" + i + " is not the same", score, h[i].score,
260             SCORE_COMP_THRESH);
261       }
262     } catch (Error e) {
263       printHits("testSimpleEqualScores3", h, s);
264       throw e;
265     }
266     
267   }
268   
269   public void testSimpleTiebreaker() throws Exception {
270     
271     DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.01f);
272     q.add(tq("dek", "albino"));
273     q.add(tq("dek", "elephant"));
274     QueryUtils.check(random, q, s);
275     
276     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
277     
278     try {
279       assertEquals("3 docs should match " + q.toString(), 3, h.length);
280       assertEquals("wrong first", "d2", s.doc(h[0].doc).get("id"));
281       float score0 = h[0].score;
282       float score1 = h[1].score;
283       float score2 = h[2].score;
284       assertTrue("d2 does not have better score then others: " + score0
285           + " >? " + score1, score0 > score1);
286       assertEquals("d4 and d1 don't have equal scores", score1, score2,
287           SCORE_COMP_THRESH);
288     } catch (Error e) {
289       printHits("testSimpleTiebreaker", h, s);
290       throw e;
291     }
292   }
293   
294   public void testBooleanRequiredEqualScores() throws Exception {
295     
296     BooleanQuery q = new BooleanQuery();
297     {
298       DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.0f);
299       q1.add(tq("hed", "albino"));
300       q1.add(tq("dek", "albino"));
301       q.add(q1, BooleanClause.Occur.MUST);// true,false);
302       QueryUtils.check(random, q1, s);
303       
304     }
305     {
306       DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.0f);
307       q2.add(tq("hed", "elephant"));
308       q2.add(tq("dek", "elephant"));
309       q.add(q2, BooleanClause.Occur.MUST);// true,false);
310       QueryUtils.check(random, q2, s);
311     }
312     
313     QueryUtils.check(random, q, s);
314     
315     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
316     
317     try {
318       assertEquals("3 docs should match " + q.toString(), 3, h.length);
319       float score = h[0].score;
320       for (int i = 1; i < h.length; i++) {
321         assertEquals("score #" + i + " is not the same", score, h[i].score,
322             SCORE_COMP_THRESH);
323       }
324     } catch (Error e) {
325       printHits("testBooleanRequiredEqualScores1", h, s);
326       throw e;
327     }
328   }
329   
330   public void testBooleanOptionalNoTiebreaker() throws Exception {
331     
332     BooleanQuery q = new BooleanQuery();
333     {
334       DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.0f);
335       q1.add(tq("hed", "albino"));
336       q1.add(tq("dek", "albino"));
337       q.add(q1, BooleanClause.Occur.SHOULD);// false,false);
338     }
339     {
340       DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.0f);
341       q2.add(tq("hed", "elephant"));
342       q2.add(tq("dek", "elephant"));
343       q.add(q2, BooleanClause.Occur.SHOULD);// false,false);
344     }
345     QueryUtils.check(random, q, s);
346     
347     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
348     
349     try {
350       assertEquals("4 docs should match " + q.toString(), 4, h.length);
351       float score = h[0].score;
352       for (int i = 1; i < h.length - 1; i++) { /* note: -1 */
353         assertEquals("score #" + i + " is not the same", score, h[i].score,
354             SCORE_COMP_THRESH);
355       }
356       assertEquals("wrong last", "d1", s.doc(h[h.length - 1].doc).get("id"));
357       float score1 = h[h.length - 1].score;
358       assertTrue("d1 does not have worse score then others: " + score + " >? "
359           + score1, score > score1);
360     } catch (Error e) {
361       printHits("testBooleanOptionalNoTiebreaker", h, s);
362       throw e;
363     }
364   }
365   
366   public void testBooleanOptionalWithTiebreaker() throws Exception {
367     
368     BooleanQuery q = new BooleanQuery();
369     {
370       DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.01f);
371       q1.add(tq("hed", "albino"));
372       q1.add(tq("dek", "albino"));
373       q.add(q1, BooleanClause.Occur.SHOULD);// false,false);
374     }
375     {
376       DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.01f);
377       q2.add(tq("hed", "elephant"));
378       q2.add(tq("dek", "elephant"));
379       q.add(q2, BooleanClause.Occur.SHOULD);// false,false);
380     }
381     QueryUtils.check(random, q, s);
382     
383     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
384     
385     try {
386       
387       assertEquals("4 docs should match " + q.toString(), 4, h.length);
388       
389       float score0 = h[0].score;
390       float score1 = h[1].score;
391       float score2 = h[2].score;
392       float score3 = h[3].score;
393       
394       String doc0 = s.doc(h[0].doc).get("id");
395       String doc1 = s.doc(h[1].doc).get("id");
396       String doc2 = s.doc(h[2].doc).get("id");
397       String doc3 = s.doc(h[3].doc).get("id");
398       
399       assertTrue("doc0 should be d2 or d4: " + doc0, doc0.equals("d2")
400           || doc0.equals("d4"));
401       assertTrue("doc1 should be d2 or d4: " + doc0, doc1.equals("d2")
402           || doc1.equals("d4"));
403       assertEquals("score0 and score1 should match", score0, score1,
404           SCORE_COMP_THRESH);
405       assertEquals("wrong third", "d3", doc2);
406       assertTrue("d3 does not have worse score then d2 and d4: " + score1
407           + " >? " + score2, score1 > score2);
408       
409       assertEquals("wrong fourth", "d1", doc3);
410       assertTrue("d1 does not have worse score then d3: " + score2 + " >? "
411           + score3, score2 > score3);
412       
413     } catch (Error e) {
414       printHits("testBooleanOptionalWithTiebreaker", h, s);
415       throw e;
416     }
417     
418   }
419   
420   public void testBooleanOptionalWithTiebreakerAndBoost() throws Exception {
421     
422     BooleanQuery q = new BooleanQuery();
423     {
424       DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.01f);
425       q1.add(tq("hed", "albino", 1.5f));
426       q1.add(tq("dek", "albino"));
427       q.add(q1, BooleanClause.Occur.SHOULD);// false,false);
428     }
429     {
430       DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.01f);
431       q2.add(tq("hed", "elephant", 1.5f));
432       q2.add(tq("dek", "elephant"));
433       q.add(q2, BooleanClause.Occur.SHOULD);// false,false);
434     }
435     QueryUtils.check(random, q, s);
436     
437     ScoreDoc[] h = s.search(q, null, 1000).scoreDocs;
438     
439     try {
440       
441       assertEquals("4 docs should match " + q.toString(), 4, h.length);
442       
443       float score0 = h[0].score;
444       float score1 = h[1].score;
445       float score2 = h[2].score;
446       float score3 = h[3].score;
447       
448       String doc0 = s.doc(h[0].doc).get("id");
449       String doc1 = s.doc(h[1].doc).get("id");
450       String doc2 = s.doc(h[2].doc).get("id");
451       String doc3 = s.doc(h[3].doc).get("id");
452       
453       assertEquals("doc0 should be d4: ", "d4", doc0);
454       assertEquals("doc1 should be d3: ", "d3", doc1);
455       assertEquals("doc2 should be d2: ", "d2", doc2);
456       assertEquals("doc3 should be d1: ", "d1", doc3);
457       
458       assertTrue("d4 does not have a better score then d3: " + score0 + " >? "
459           + score1, score0 > score1);
460       assertTrue("d3 does not have a better score then d2: " + score1 + " >? "
461           + score2, score1 > score2);
462       assertTrue("d3 does not have a better score then d1: " + score2 + " >? "
463           + score3, score2 > score3);
464       
465     } catch (Error e) {
466       printHits("testBooleanOptionalWithTiebreakerAndBoost", h, s);
467       throw e;
468     }
469   }
470   
471   /** macro */
472   protected Query tq(String f, String t) {
473     return new TermQuery(new Term(f, t));
474   }
475   
476   /** macro */
477   protected Query tq(String f, String t, float b) {
478     Query q = tq(f, t);
479     q.setBoost(b);
480     return q;
481   }
482   
483   protected void printHits(String test, ScoreDoc[] h, Searcher searcher)
484       throws Exception {
485     
486     System.err.println("------- " + test + " -------");
487     
488     DecimalFormat f = new DecimalFormat("0.000000000");
489     
490     for (int i = 0; i < h.length; i++) {
491       Document d = searcher.doc(h[i].doc);
492       float score = h[i].score;
493       System.err
494           .println("#" + i + ": " + f.format(score) + " - " + d.get("id"));
495     }
496   }
497 }