pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / test / org / apache / lucene / search / TestNumericRangeQuery32.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.analysis.MockAnalyzer;
21 import org.apache.lucene.document.Document;
22 import org.apache.lucene.document.Field;
23 import org.apache.lucene.document.NumericField;
24 import org.apache.lucene.index.IndexReader;
25 import org.apache.lucene.index.Term;
26 import org.apache.lucene.index.RandomIndexWriter;
27 import org.apache.lucene.store.Directory;
28 import org.apache.lucene.util.LuceneTestCase;
29 import org.apache.lucene.util.NumericUtils;
30 import org.apache.lucene.util.TestNumericUtils; // NaN arrays
31 import org.apache.lucene.util.StringHelper;
32 import org.apache.lucene.util._TestUtil;
33
34 import org.junit.Test;
35 import org.junit.AfterClass;
36 import org.junit.BeforeClass;
37
38 public class TestNumericRangeQuery32 extends LuceneTestCase {
39   // distance of entries
40   private static int distance;
41   // shift the starting of the values to the left, to also have negative values:
42   private static final int startOffset = - 1 << 15;
43   // number of docs to generate for testing
44   private static int noDocs;
45   
46   private static Directory directory = null;
47   private static IndexReader reader = null;
48   private static IndexSearcher searcher = null;
49   
50   @BeforeClass
51   public static void beforeClass() throws Exception {
52     noDocs = atLeast(4096);
53     distance = (1 << 30) / noDocs;
54     directory = newDirectory();
55     RandomIndexWriter writer = new RandomIndexWriter(random, directory,
56         newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random))
57         .setMaxBufferedDocs(_TestUtil.nextInt(random, 100, 1000))
58         .setMergePolicy(newLogMergePolicy()));
59     
60     NumericField
61       field8 = new NumericField("field8", 8, Field.Store.YES, true),
62       field4 = new NumericField("field4", 4, Field.Store.YES, true),
63       field2 = new NumericField("field2", 2, Field.Store.YES, true),
64       fieldNoTrie = new NumericField("field"+Integer.MAX_VALUE, Integer.MAX_VALUE, Field.Store.YES, true),
65       ascfield8 = new NumericField("ascfield8", 8, Field.Store.NO, true),
66       ascfield4 = new NumericField("ascfield4", 4, Field.Store.NO, true),
67       ascfield2 = new NumericField("ascfield2", 2, Field.Store.NO, true);
68     
69     Document doc = new Document();
70     // add fields, that have a distance to test general functionality
71     doc.add(field8); doc.add(field4); doc.add(field2); doc.add(fieldNoTrie);
72     // add ascending fields with a distance of 1, beginning at -noDocs/2 to test the correct splitting of range and inclusive/exclusive
73     doc.add(ascfield8); doc.add(ascfield4); doc.add(ascfield2);
74     
75     // Add a series of noDocs docs with increasing int values
76     for (int l=0; l<noDocs; l++) {
77       int val=distance*l+startOffset;
78       field8.setIntValue(val);
79       field4.setIntValue(val);
80       field2.setIntValue(val);
81       fieldNoTrie.setIntValue(val);
82
83       val=l-(noDocs/2);
84       ascfield8.setIntValue(val);
85       ascfield4.setIntValue(val);
86       ascfield2.setIntValue(val);
87       writer.addDocument(doc);
88     }
89   
90     reader = writer.getReader();
91     searcher=newSearcher(reader);
92     writer.close();
93   }
94   
95   @AfterClass
96   public static void afterClass() throws Exception {
97     searcher.close();
98     searcher = null;
99     reader.close();
100     reader = null;
101     directory.close();
102     directory = null;
103   }
104   
105   @Override
106   public void setUp() throws Exception {
107     super.setUp();
108     // set the theoretical maximum term count for 8bit (see docs for the number)
109     // super.tearDown will restore the default
110     BooleanQuery.setMaxClauseCount(3*255*2 + 255);
111   }
112   
113   /** test for both constant score and boolean query, the other tests only use the constant score mode */
114   private void testRange(int precisionStep) throws Exception {
115     String field="field"+precisionStep;
116     int count=3000;
117     int lower=(distance*3/2)+startOffset, upper=lower + count*distance + (distance/3);
118     NumericRangeQuery<Integer> q = NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
119     NumericRangeFilter<Integer> f = NumericRangeFilter.newIntRange(field, precisionStep, lower, upper, true, true);
120     for (byte i=0; i<3; i++) {
121       TopDocs topDocs;
122       String type;
123       switch (i) {
124         case 0:
125           type = " (constant score filter rewrite)";
126           q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE);
127           topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
128           break;
129         case 1:
130           type = " (constant score boolean rewrite)";
131           q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE);
132           topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
133           break;
134         case 2:
135           type = " (filter)";
136           topDocs = searcher.search(new MatchAllDocsQuery(), f, noDocs, Sort.INDEXORDER);
137           break;
138         default:
139           return;
140       }
141       ScoreDoc[] sd = topDocs.scoreDocs;
142       assertNotNull(sd);
143       assertEquals("Score doc count"+type, count, sd.length );
144       Document doc=searcher.doc(sd[0].doc);
145       assertEquals("First doc"+type, 2*distance+startOffset, Integer.parseInt(doc.get(field)) );
146       doc=searcher.doc(sd[sd.length-1].doc);
147       assertEquals("Last doc"+type, (1+count)*distance+startOffset, Integer.parseInt(doc.get(field)) );
148     }
149   }
150
151   @Test
152   public void testRange_8bit() throws Exception {
153     testRange(8);
154   }
155   
156   @Test
157   public void testRange_4bit() throws Exception {
158     testRange(4);
159   }
160   
161   @Test
162   public void testRange_2bit() throws Exception {
163     testRange(2);
164   }
165   
166   @Test
167   public void testInverseRange() throws Exception {
168     NumericRangeFilter<Integer> f = NumericRangeFilter.newIntRange("field8", 8, 1000, -1000, true, true);
169     assertSame("A inverse range should return the EMPTY_DOCIDSET instance", DocIdSet.EMPTY_DOCIDSET, f.getDocIdSet(searcher.getIndexReader()));
170     f = NumericRangeFilter.newIntRange("field8", 8, Integer.MAX_VALUE, null, false, false);
171     assertSame("A exclusive range starting with Integer.MAX_VALUE should return the EMPTY_DOCIDSET instance",
172       DocIdSet.EMPTY_DOCIDSET, f.getDocIdSet(searcher.getIndexReader()));
173     f = NumericRangeFilter.newIntRange("field8", 8, null, Integer.MIN_VALUE, false, false);
174     assertSame("A exclusive range ending with Integer.MIN_VALUE should return the EMPTY_DOCIDSET instance",
175       DocIdSet.EMPTY_DOCIDSET, f.getDocIdSet(searcher.getIndexReader()));
176   }
177   
178   @Test
179   public void testOneMatchQuery() throws Exception {
180     NumericRangeQuery<Integer> q = NumericRangeQuery.newIntRange("ascfield8", 8, 1000, 1000, true, true);
181     assertSame(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE, q.getRewriteMethod());
182     TopDocs topDocs = searcher.search(q, noDocs);
183     ScoreDoc[] sd = topDocs.scoreDocs;
184     assertNotNull(sd);
185     assertEquals("Score doc count", 1, sd.length );
186   }
187   
188   private void testLeftOpenRange(int precisionStep) throws Exception {
189     String field="field"+precisionStep;
190     int count=3000;
191     int upper=(count-1)*distance + (distance/3) + startOffset;
192     NumericRangeQuery<Integer> q=NumericRangeQuery.newIntRange(field, precisionStep, null, upper, true, true);
193     TopDocs topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
194     ScoreDoc[] sd = topDocs.scoreDocs;
195     assertNotNull(sd);
196     assertEquals("Score doc count", count, sd.length );
197     Document doc=searcher.doc(sd[0].doc);
198     assertEquals("First doc", startOffset, Integer.parseInt(doc.get(field)) );
199     doc=searcher.doc(sd[sd.length-1].doc);
200     assertEquals("Last doc", (count-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
201     
202     q=NumericRangeQuery.newIntRange(field, precisionStep, null, upper, false, true);
203     topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
204     sd = topDocs.scoreDocs;
205     assertNotNull(sd);
206     assertEquals("Score doc count", count, sd.length );
207     doc=searcher.doc(sd[0].doc);
208     assertEquals("First doc", startOffset, Integer.parseInt(doc.get(field)) );
209     doc=searcher.doc(sd[sd.length-1].doc);
210     assertEquals("Last doc", (count-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
211   }
212   
213   @Test
214   public void testLeftOpenRange_8bit() throws Exception {
215     testLeftOpenRange(8);
216   }
217   
218   @Test
219   public void testLeftOpenRange_4bit() throws Exception {
220     testLeftOpenRange(4);
221   }
222   
223   @Test
224   public void testLeftOpenRange_2bit() throws Exception {
225     testLeftOpenRange(2);
226   }
227   
228   private void testRightOpenRange(int precisionStep) throws Exception {
229     String field="field"+precisionStep;
230     int count=3000;
231     int lower=(count-1)*distance + (distance/3) +startOffset;
232     NumericRangeQuery<Integer> q=NumericRangeQuery.newIntRange(field, precisionStep, lower, null, true, true);
233     TopDocs topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
234     ScoreDoc[] sd = topDocs.scoreDocs;
235     assertNotNull(sd);
236     assertEquals("Score doc count", noDocs-count, sd.length );
237     Document doc=searcher.doc(sd[0].doc);
238     assertEquals("First doc", count*distance+startOffset, Integer.parseInt(doc.get(field)) );
239     doc=searcher.doc(sd[sd.length-1].doc);
240     assertEquals("Last doc", (noDocs-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
241
242     q=NumericRangeQuery.newIntRange(field, precisionStep, lower, null, true, false);
243     topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
244     sd = topDocs.scoreDocs;
245     assertNotNull(sd);
246     assertEquals("Score doc count", noDocs-count, sd.length );
247     doc=searcher.doc(sd[0].doc);
248     assertEquals("First doc", count*distance+startOffset, Integer.parseInt(doc.get(field)) );
249     doc=searcher.doc(sd[sd.length-1].doc);
250     assertEquals("Last doc", (noDocs-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
251   }
252   
253   @Test
254   public void testRightOpenRange_8bit() throws Exception {
255     testRightOpenRange(8);
256   }
257   
258   @Test
259   public void testRightOpenRange_4bit() throws Exception {
260     testRightOpenRange(4);
261   }
262   
263   @Test
264   public void testRightOpenRange_2bit() throws Exception {
265     testRightOpenRange(2);
266   }
267   
268   @Test
269   public void testInfiniteValues() throws Exception {
270     Directory dir = newDirectory();
271     RandomIndexWriter writer = new RandomIndexWriter(random, dir,
272       newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
273     Document doc = new Document();
274     doc.add(new NumericField("float").setFloatValue(Float.NEGATIVE_INFINITY));
275     doc.add(new NumericField("int").setIntValue(Integer.MIN_VALUE));
276     writer.addDocument(doc);
277     
278     doc = new Document();
279     doc.add(new NumericField("float").setFloatValue(Float.POSITIVE_INFINITY));
280     doc.add(new NumericField("int").setIntValue(Integer.MAX_VALUE));
281     writer.addDocument(doc);
282     
283     doc = new Document();
284     doc.add(new NumericField("float").setFloatValue(0.0f));
285     doc.add(new NumericField("int").setIntValue(0));
286     writer.addDocument(doc);
287     
288     for (float f : TestNumericUtils.FLOAT_NANs) {
289       doc = new Document();
290       doc.add(new NumericField("float").setFloatValue(f));
291       writer.addDocument(doc);
292     }
293     
294     writer.close();
295     
296     IndexReader r = IndexReader.open(dir);
297     IndexSearcher s = new IndexSearcher(r);
298     
299     Query q=NumericRangeQuery.newIntRange("int", null, null, true, true);
300     TopDocs topDocs = s.search(q, 10);
301     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
302     
303     q=NumericRangeQuery.newIntRange("int", null, null, false, false);
304     topDocs = s.search(q, 10);
305     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
306
307     q=NumericRangeQuery.newIntRange("int", Integer.MIN_VALUE, Integer.MAX_VALUE, true, true);
308     topDocs = s.search(q, 10);
309     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
310     
311     q=NumericRangeQuery.newIntRange("int", Integer.MIN_VALUE, Integer.MAX_VALUE, false, false);
312     topDocs = s.search(q, 10);
313     assertEquals("Score doc count", 1,  topDocs.scoreDocs.length );
314
315     q=NumericRangeQuery.newFloatRange("float", null, null, true, true);
316     topDocs = s.search(q, 10);
317     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
318
319     q=NumericRangeQuery.newFloatRange("float", null, null, false, false);
320     topDocs = s.search(q, 10);
321     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
322
323     q=NumericRangeQuery.newFloatRange("float", Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, true, true);
324     topDocs = s.search(q, 10);
325     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
326
327     q=NumericRangeQuery.newFloatRange("float", Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, false, false);
328     topDocs = s.search(q, 10);
329     assertEquals("Score doc count", 1,  topDocs.scoreDocs.length );
330
331     q=NumericRangeQuery.newFloatRange("float", Float.NaN, Float.NaN, true, true);
332     topDocs = s.search(q, 10);
333     assertEquals("Score doc count", TestNumericUtils.FLOAT_NANs.length,  topDocs.scoreDocs.length );
334
335     s.close();
336     r.close();
337     dir.close();
338   }
339   
340   private void testRandomTrieAndClassicRangeQuery(int precisionStep) throws Exception {
341     String field=StringHelper.intern("field"+precisionStep);
342     int totalTermCountT=0,totalTermCountC=0,termCountT,termCountC;
343     int num = _TestUtil.nextInt(random, 10, 20);
344     for (int i = 0; i < num; i++) {
345       int lower=(int)(random.nextDouble()*noDocs*distance)+startOffset;
346       int upper=(int)(random.nextDouble()*noDocs*distance)+startOffset;
347       if (lower>upper) {
348         int a=lower; lower=upper; upper=a;
349       }
350       // test inclusive range
351       NumericRangeQuery<Integer> tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
352       TermRangeQuery cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), true, true);
353       TopDocs tTopDocs = searcher.search(tq, 1);
354       TopDocs cTopDocs = searcher.search(cq, 1);
355       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
356       totalTermCountT += termCountT = countTerms(tq, field);
357       totalTermCountC += termCountC = countTerms(cq, field);
358       checkTermCounts(precisionStep, termCountT, termCountC);
359       // test exclusive range
360       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, false);
361       cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), false, false);
362       tTopDocs = searcher.search(tq, 1);
363       cTopDocs = searcher.search(cq, 1);
364       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
365       totalTermCountT += termCountT = countTerms(tq, field);
366       totalTermCountC += termCountC = countTerms(cq, field);
367       checkTermCounts(precisionStep, termCountT, termCountC);
368       // test left exclusive range
369       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, true);
370       cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), false, true);
371       tTopDocs = searcher.search(tq, 1);
372       cTopDocs = searcher.search(cq, 1);
373       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
374       totalTermCountT += termCountT = countTerms(tq, field);
375       totalTermCountC += termCountC = countTerms(cq, field);
376       checkTermCounts(precisionStep, termCountT, termCountC);
377       // test right exclusive range
378       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, false);
379       cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), true, false);
380       tTopDocs = searcher.search(tq, 1);
381       cTopDocs = searcher.search(cq, 1);
382       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
383       totalTermCountT += termCountT = countTerms(tq, field);
384       totalTermCountC += termCountC = countTerms(cq, field);
385       checkTermCounts(precisionStep, termCountT, termCountC);
386     }
387     
388     checkTermCounts(precisionStep, totalTermCountT, totalTermCountC);
389     if (VERBOSE && precisionStep != Integer.MAX_VALUE) {
390       System.out.println("Average number of terms during random search on '" + field + "':");
391       System.out.println(" Numeric query: " + (((double)totalTermCountT)/(num * 4)));
392       System.out.println(" Classical query: " + (((double)totalTermCountC)/(num * 4)));
393     }
394   }
395   
396   @Test
397   public void testEmptyEnums() throws Exception {
398     int count=3000;
399     int lower=(distance*3/2)+startOffset, upper=lower + count*distance + (distance/3);
400     // test empty enum
401     assert lower < upper;
402     assertTrue(0 < countTerms(NumericRangeQuery.newIntRange("field4", 4, lower, upper, true, true), "field4"));
403     assertEquals(0, countTerms(NumericRangeQuery.newIntRange("field4", 4, upper, lower, true, true), "field4"));
404     // test empty enum outside of bounds
405     lower = distance*noDocs+startOffset;
406     upper = 2 * lower;
407     assert lower < upper;
408     assertEquals(0, countTerms(NumericRangeQuery.newIntRange("field4", 4, lower, upper, true, true), "field4"));
409   }
410   
411   private int countTerms(MultiTermQuery q, String field) throws Exception {
412     FilteredTermEnum termEnum = q.getEnum(reader);
413     try {
414       int count = 0;
415       Term last = null;
416       do {
417         final Term cur = termEnum.term();
418         if (cur != null) {
419           count++;
420           assertSame(field, cur.field());
421           if (last != null) {
422             assertTrue(last.text().compareTo(cur.text()) < 0);
423           }
424           last = cur;
425         } else break;
426       } while (termEnum.next());
427       assertFalse(termEnum.next());
428       return count;
429     } finally {
430       termEnum.close();
431     }
432   }
433   
434   private void checkTermCounts(int precisionStep, int termCountT, int termCountC) {
435     if (precisionStep == Integer.MAX_VALUE) {
436       assertEquals("Number of terms should be equal for unlimited precStep", termCountC, termCountT);
437     } else {
438       assertTrue("Number of terms for NRQ should be <= compared to classical TRQ", termCountT <= termCountC);
439     }
440   }
441
442   @Test
443   public void testRandomTrieAndClassicRangeQuery_8bit() throws Exception {
444     testRandomTrieAndClassicRangeQuery(8);
445   }
446   
447   @Test
448   public void testRandomTrieAndClassicRangeQuery_4bit() throws Exception {
449     testRandomTrieAndClassicRangeQuery(4);
450   }
451   
452   @Test
453   public void testRandomTrieAndClassicRangeQuery_2bit() throws Exception {
454     testRandomTrieAndClassicRangeQuery(2);
455   }
456   
457   @Test
458   public void testRandomTrieAndClassicRangeQuery_NoTrie() throws Exception {
459     testRandomTrieAndClassicRangeQuery(Integer.MAX_VALUE);
460   }
461   
462   private void testRangeSplit(int precisionStep) throws Exception {
463     String field="ascfield"+precisionStep;
464     // 10 random tests
465     int num = _TestUtil.nextInt(random, 10, 20);
466     for (int  i =0;  i< num; i++) {
467       int lower=(int)(random.nextDouble()*noDocs - noDocs/2);
468       int upper=(int)(random.nextDouble()*noDocs - noDocs/2);
469       if (lower>upper) {
470         int a=lower; lower=upper; upper=a;
471       }
472       // test inclusive range
473       Query tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
474       TopDocs tTopDocs = searcher.search(tq, 1);
475       assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
476       // test exclusive range
477       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, false);
478       tTopDocs = searcher.search(tq, 1);
479       assertEquals("Returned count of range query must be equal to exclusive range length", Math.max(upper-lower-1, 0), tTopDocs.totalHits );
480       // test left exclusive range
481       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, true);
482       tTopDocs = searcher.search(tq, 1);
483       assertEquals("Returned count of range query must be equal to half exclusive range length", upper-lower, tTopDocs.totalHits );
484       // test right exclusive range
485       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, false);
486       tTopDocs = searcher.search(tq, 1);
487       assertEquals("Returned count of range query must be equal to half exclusive range length", upper-lower, tTopDocs.totalHits );
488     }
489   }
490
491   @Test
492   public void testRangeSplit_8bit() throws Exception {
493     testRangeSplit(8);
494   }
495   
496   @Test
497   public void testRangeSplit_4bit() throws Exception {
498     testRangeSplit(4);
499   }
500   
501   @Test
502   public void testRangeSplit_2bit() throws Exception {
503     testRangeSplit(2);
504   }
505   
506   /** we fake a float test using int2float conversion of NumericUtils */
507   private void testFloatRange(int precisionStep) throws Exception {
508     final String field="ascfield"+precisionStep;
509     final int lower=-1000, upper=+2000;
510     
511     Query tq=NumericRangeQuery.newFloatRange(field, precisionStep,
512       NumericUtils.sortableIntToFloat(lower), NumericUtils.sortableIntToFloat(upper), true, true);
513     TopDocs tTopDocs = searcher.search(tq, 1);
514     assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
515     
516     Filter tf=NumericRangeFilter.newFloatRange(field, precisionStep,
517       NumericUtils.sortableIntToFloat(lower), NumericUtils.sortableIntToFloat(upper), true, true);
518     tTopDocs = searcher.search(new MatchAllDocsQuery(), tf, 1);
519     assertEquals("Returned count of range filter must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
520   }
521
522   @Test
523   public void testFloatRange_8bit() throws Exception {
524     testFloatRange(8);
525   }
526   
527   @Test
528   public void testFloatRange_4bit() throws Exception {
529     testFloatRange(4);
530   }
531   
532   @Test
533   public void testFloatRange_2bit() throws Exception {
534     testFloatRange(2);
535   }
536   
537   private void testSorting(int precisionStep) throws Exception {
538     String field="field"+precisionStep;
539     // 10 random tests, the index order is ascending,
540     // so using a reverse sort field should retun descending documents
541     int num = _TestUtil.nextInt(random, 10, 20);
542     for (int i = 0; i < num; i++) {
543       int lower=(int)(random.nextDouble()*noDocs*distance)+startOffset;
544       int upper=(int)(random.nextDouble()*noDocs*distance)+startOffset;
545       if (lower>upper) {
546         int a=lower; lower=upper; upper=a;
547       }
548       Query tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
549       TopDocs topDocs = searcher.search(tq, null, noDocs, new Sort(new SortField(field, SortField.INT, true)));
550       if (topDocs.totalHits==0) continue;
551       ScoreDoc[] sd = topDocs.scoreDocs;
552       assertNotNull(sd);
553       int last=Integer.parseInt(searcher.doc(sd[0].doc).get(field));
554       for (int j=1; j<sd.length; j++) {
555         int act=Integer.parseInt(searcher.doc(sd[j].doc).get(field));
556         assertTrue("Docs should be sorted backwards", last>act );
557         last=act;
558       }
559     }
560   }
561
562   @Test
563   public void testSorting_8bit() throws Exception {
564     testSorting(8);
565   }
566   
567   @Test
568   public void testSorting_4bit() throws Exception {
569     testSorting(4);
570   }
571   
572   @Test
573   public void testSorting_2bit() throws Exception {
574     testSorting(2);
575   }
576   
577   @Test
578   public void testEqualsAndHash() throws Exception {
579     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test1", 4, 10, 20, true, true));
580     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test2", 4, 10, 20, false, true));
581     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test3", 4, 10, 20, true, false));
582     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test4", 4, 10, 20, false, false));
583     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test5", 4, 10, null, true, true));
584     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test6", 4, null, 20, true, true));
585     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test7", 4, null, null, true, true));
586     QueryUtils.checkEqual(
587       NumericRangeQuery.newIntRange("test8", 4, 10, 20, true, true), 
588       NumericRangeQuery.newIntRange("test8", 4, 10, 20, true, true)
589     );
590     QueryUtils.checkUnequal(
591       NumericRangeQuery.newIntRange("test9", 4, 10, 20, true, true), 
592       NumericRangeQuery.newIntRange("test9", 8, 10, 20, true, true)
593     );
594     QueryUtils.checkUnequal(
595       NumericRangeQuery.newIntRange("test10a", 4, 10, 20, true, true), 
596       NumericRangeQuery.newIntRange("test10b", 4, 10, 20, true, true)
597     );
598     QueryUtils.checkUnequal(
599       NumericRangeQuery.newIntRange("test11", 4, 10, 20, true, true), 
600       NumericRangeQuery.newIntRange("test11", 4, 20, 10, true, true)
601     );
602     QueryUtils.checkUnequal(
603       NumericRangeQuery.newIntRange("test12", 4, 10, 20, true, true), 
604       NumericRangeQuery.newIntRange("test12", 4, 10, 20, false, true)
605     );
606     QueryUtils.checkUnequal(
607       NumericRangeQuery.newIntRange("test13", 4, 10, 20, true, true), 
608       NumericRangeQuery.newFloatRange("test13", 4, 10f, 20f, true, true)
609     );
610     // the following produces a hash collision, because Long and Integer have the same hashcode, so only test equality:
611     Query q1 = NumericRangeQuery.newIntRange("test14", 4, 10, 20, true, true);
612     Query q2 = NumericRangeQuery.newLongRange("test14", 4, 10L, 20L, true, true);
613     assertFalse(q1.equals(q2));
614     assertFalse(q2.equals(q1));
615   }
616   
617 }