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