add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / spatial / src / test / org / apache / lucene / spatial / tier / TestCartesian.java
1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.lucene.spatial.tier;
18
19 import java.io.IOException;
20 import java.util.LinkedList;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.lucene.analysis.MockAnalyzer;
25 import org.apache.lucene.document.Document;
26 import org.apache.lucene.document.Field;
27 import org.apache.lucene.index.IndexWriter;
28 import org.apache.lucene.index.IndexReader;
29 import org.apache.lucene.index.Term;
30 import org.apache.lucene.search.IndexSearcher;
31 import org.apache.lucene.search.Query;
32 import org.apache.lucene.search.ScoreDoc;
33 import org.apache.lucene.search.Sort;
34 import org.apache.lucene.search.SortField;
35 import org.apache.lucene.search.TermQuery;
36 import org.apache.lucene.search.TopDocs;
37 import org.apache.lucene.search.function.CustomScoreQuery;
38 import org.apache.lucene.search.function.CustomScoreProvider;
39 import org.apache.lucene.search.function.FieldScoreQuery;
40 import org.apache.lucene.search.function.FieldScoreQuery.Type;
41 import org.apache.lucene.spatial.DistanceUtils;
42 import org.apache.lucene.spatial.geohash.GeoHashUtils;
43 import org.apache.lucene.spatial.geometry.DistanceUnits;
44 import org.apache.lucene.spatial.geometry.FloatLatLng;
45 import org.apache.lucene.spatial.geometry.LatLng;
46 import org.apache.lucene.spatial.tier.projections.CartesianTierPlotter;
47 import org.apache.lucene.spatial.tier.projections.IProjector;
48 import org.apache.lucene.spatial.tier.projections.SinusoidalProjector;
49 import org.apache.lucene.store.Directory;
50 import org.apache.lucene.util.LuceneTestCase;
51 import org.apache.lucene.util.NumericUtils;
52
53 public class TestCartesian extends LuceneTestCase {
54
55   private Directory directory;
56   private IndexSearcher searcher;
57   // reston va
58   private double lat = 38.969398; 
59   private double lng= -77.386398;
60   private String latField = "lat";
61   private String lngField = "lng";
62   private List<CartesianTierPlotter> ctps = new LinkedList<CartesianTierPlotter>();
63   private String geoHashPrefix = "_geoHash_";
64   
65   private IProjector project = new SinusoidalProjector();
66   
67
68
69   @Override
70   public void setUp() throws Exception {
71     super.setUp();
72     directory = newDirectory();
73
74     IndexWriter writer = new IndexWriter(directory, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
75     
76     setUpPlotter( 2, 15);
77     
78     addData(writer);
79     
80   }
81   
82   @Override
83   public void tearDown() throws Exception {
84     directory.close();
85     super.tearDown();
86   }
87   
88   
89   private void setUpPlotter(int base, int top) {
90     
91     for (; base <= top; base ++){
92       ctps.add(new CartesianTierPlotter(base,project,
93           CartesianTierPlotter.DEFALT_FIELD_PREFIX));
94     }
95   }
96   
97   private void addPoint(IndexWriter writer, String name, double lat, double lng) throws IOException{
98     
99     Document doc = new Document();
100     
101     doc.add(newField("name", name,Field.Store.YES, Field.Index.ANALYZED));
102     
103     // convert the lat / long to lucene fields
104     doc.add(new Field(latField, NumericUtils.doubleToPrefixCoded(lat),Field.Store.YES, Field.Index.NOT_ANALYZED));
105     doc.add(new Field(lngField, NumericUtils.doubleToPrefixCoded(lng),Field.Store.YES, Field.Index.NOT_ANALYZED));
106     
107     // add a default meta field to make searching all documents easy 
108     doc.add(newField("metafile", "doc",Field.Store.YES, Field.Index.ANALYZED));
109     
110     int ctpsize = ctps.size();
111     for (int i =0; i < ctpsize; i++){
112       CartesianTierPlotter ctp = ctps.get(i);
113       doc.add(new Field(ctp.getTierFieldName(), 
114           NumericUtils.doubleToPrefixCoded(ctp.getTierBoxId(lat,lng)),
115           Field.Store.YES, 
116           Field.Index.NOT_ANALYZED_NO_NORMS));
117       
118       doc.add(newField(geoHashPrefix, GeoHashUtils.encode(lat,lng), 
119                   Field.Store.YES, 
120                   Field.Index.NOT_ANALYZED_NO_NORMS));
121     }
122     writer.addDocument(doc);
123     
124   }
125   
126   
127   
128   private void addData(IndexWriter writer) throws IOException {
129     addPoint(writer,"McCormick &amp; Schmick's Seafood Restaurant",38.9579000,-77.3572000);
130     addPoint(writer,"Jimmy's Old Town Tavern",38.9690000,-77.3862000);
131     addPoint(writer,"Ned Devine's",38.9510000,-77.4107000);
132     addPoint(writer,"Old Brogue Irish Pub",38.9955000,-77.2884000);
133     addPoint(writer,"Alf Laylah Wa Laylah",38.8956000,-77.4258000);
134     addPoint(writer,"Sully's Restaurant &amp; Supper",38.9003000,-77.4467000);
135     addPoint(writer,"TGIFriday",38.8725000,-77.3829000);
136     addPoint(writer,"Potomac Swing Dance Club",38.9027000,-77.2639000);
137     addPoint(writer,"White Tiger Restaurant",38.9027000,-77.2638000);
138     addPoint(writer,"Jammin' Java",38.9039000,-77.2622000);
139     addPoint(writer,"Potomac Swing Dance Club",38.9027000,-77.2639000);
140     addPoint(writer,"WiseAcres Comedy Club",38.9248000,-77.2344000);
141     addPoint(writer,"Glen Echo Spanish Ballroom",38.9691000,-77.1400000);
142     addPoint(writer,"Whitlow's on Wilson",38.8889000,-77.0926000);
143     addPoint(writer,"Iota Club and Cafe",38.8890000,-77.0923000);
144     addPoint(writer,"Hilton Washington Embassy Row",38.9103000,-77.0451000);
145     addPoint(writer,"HorseFeathers, Bar & Grill", 39.01220000000001, -77.3942);
146     addPoint(writer,"Marshall Island Airfield",7.06, 171.2);
147     addPoint(writer, "Wonga Wongue Reserve, Gabon", -0.546562,9.459229);
148     addPoint(writer,"Midway Island",25.7, -171.7);
149     addPoint(writer,"North Pole Way",55.0, 4.0);
150    
151     writer.commit();
152     // TODO: fix CustomScoreQuery usage in testRange/testGeoHashRange so we don't need this.
153     writer.optimize();
154     writer.close();
155   }
156
157
158   public void testDistances() throws IOException, InvalidGeoException {
159     LatLng p1 = new FloatLatLng( 7.06, 171.2 );
160     LatLng p2 = new FloatLatLng( 21.6032207, -158.0 );
161     double miles = p1.arcDistance( p2, DistanceUnits.MILES );
162     if (VERBOSE) {
163       System.out.println("testDistances");
164       System.out.println("miles:" + miles);
165     }
166     assertEquals(2288.82495932794, miles); 
167     LatLng p3 = new FloatLatLng( 41.6032207, -73.087749);
168     LatLng p4 = new FloatLatLng( 55.0, 4.0 );
169     miles = p3.arcDistance( p4, DistanceUnits.MILES );
170     if (VERBOSE) System.out.println("miles:" + miles);
171     assertEquals(3474.331719997617, miles); 
172   }
173
174   /*public void testCartesianPolyFilterBuilder() throws Exception {
175     CartesianPolyFilterBuilder cpfb = new CartesianPolyFilterBuilder(CartesianTierPlotter.DEFALT_FIELD_PREFIX, 2, 15);
176     //try out some shapes
177     final double miles = 20.0;
178         // Hawaii
179         // 2300 miles to Marshall Island Airfield
180     //Hawaii to Midway is 911 miles
181     lat = 0;
182     lng = -179.9;
183     Shape shape;
184     shape = cpfb.getBoxShape(lat, lng, miles);
185     System.out.println("Tier: " + shape.getTierLevel());
186     System.out.println("area: " + shape.getArea().size());
187     lat = 30;
188     lng = -100;
189     shape = cpfb.getBoxShape(lat, lng, miles);
190     System.out.println("Tier: " + shape.getTierLevel());
191     System.out.println("area: " + shape.getArea().size());
192
193     lat = 30;
194     lng = 100;
195     shape = cpfb.getBoxShape(lat, lng, miles);
196     System.out.println("Tier: " + shape.getTierLevel());
197     System.out.println("area: " + shape.getArea().size());
198   }
199 */
200
201
202   public void testAntiM() throws IOException, InvalidGeoException {
203     searcher = new IndexSearcher(directory, true);
204
205     final double miles = 2800.0;
206         // Hawaii
207         // 2300 miles to Marshall Island Airfield
208     //Hawaii to Midway is 911 miles
209     lat = 21.6032207;
210     lng = -158.0;
211
212     if (VERBOSE) System.out.println("testAntiM");
213     // create a distance query
214     final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
215         latField, lngField, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true, 2, 15);
216
217     if (VERBOSE) System.out.println(dq);
218     //create a term query to search against all documents
219     Query tq = new TermQuery(new Term("metafile", "doc"));
220
221     FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
222
223     CustomScoreQuery customScore = new CustomScoreQuery(dq.getQuery(tq),fsQuery){
224
225       @Override
226       protected CustomScoreProvider getCustomScoreProvider(IndexReader reader) {
227         return new CustomScoreProvider(reader) {
228           @Override // TODO: broken, as reader is not used!
229           public float customScore(int doc, float subQueryScore, float valSrcScore){
230             if (VERBOSE) System.out.println(doc);
231             if (dq.distanceFilter.getDistance(doc) == null)
232               return 0;
233
234             double distance = dq.distanceFilter.getDistance(doc);
235             // boost score shouldn't exceed 1
236             if (distance < 1.0d)
237               distance = 1.0d;
238             //boost by distance is invertly proportional to
239             // to distance from center point to location
240             float score = (float) ((miles - distance) / miles );
241             return score * subQueryScore;
242           }
243         };
244       }
245       
246     };
247     // Create a distance sort
248     // As the radius filter has performed the distance calculations
249     // already, pass in the filter to reuse the results.
250     //
251     DistanceFieldComparatorSource dsort = new DistanceFieldComparatorSource(dq.distanceFilter);
252     Sort sort = new Sort(new SortField("foo", dsort,false));
253
254     // Perform the search, using the term query, the serial chain filter, and the
255     // distance sort
256     TopDocs hits = searcher.search(customScore.createWeight(searcher),null, 1000, sort);
257     int results = hits.totalHits;
258     ScoreDoc[] scoreDocs = hits.scoreDocs; 
259     
260     // Get a list of distances
261     Map<Integer,Double> distances = dq.distanceFilter.getDistances();
262
263     // distances calculated from filter first pass must be less than total
264     // docs, from the above test of 20 items, 12 will come from the boundary box
265     // filter, but only 5 are actually in the radius of the results.
266
267     // Note Boundary Box filtering, is not accurate enough for most systems.
268
269
270     if (VERBOSE) {
271       System.out.println("Distance Filter filtered: " + distances.size());
272       System.out.println("Results: " + results);
273       System.out.println("=============================");
274       System.out.println("Distances should be 2 "+ distances.size());
275       System.out.println("Results should be 2 "+ results);
276     }
277
278     assertEquals(2, distances.size()); // fixed a store of only needed distances
279     assertEquals(2, results);
280     double lastDistance = 0;
281     for(int i =0 ; i < results; i++){
282       Document d = searcher.doc(scoreDocs[i].doc);
283
284       String name = d.get("name");
285       double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField));
286       double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField));
287       Double geo_distance = distances.get(scoreDocs[i].doc);
288
289       double distance = DistanceUtils.getDistanceMi(lat, lng, rsLat, rsLng);
290       double llm = DistanceUtils.getLLMDistance(lat, lng, rsLat, rsLng);
291       if (VERBOSE) System.out.println("Name: "+ name +", Distance "+ distance); //(res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i));
292       assertTrue(Math.abs((distance - llm)) < 1);
293       assertTrue((distance < miles ));
294       assertTrue(geo_distance >= lastDistance);
295       lastDistance = geo_distance;
296     }
297     searcher.close();
298   }
299
300   public void testPoleFlipping() throws IOException, InvalidGeoException {
301     searcher = new IndexSearcher(directory, true);
302
303     final double miles = 3500.0;
304     lat = 41.6032207;
305     lng = -73.087749;
306
307     if (VERBOSE) System.out.println("testPoleFlipping");
308
309     // create a distance query
310     final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
311         latField, lngField, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true, 2, 15);
312
313     if (VERBOSE) System.out.println(dq);
314     //create a term query to search against all documents
315     Query tq = new TermQuery(new Term("metafile", "doc"));
316
317     FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
318
319     CustomScoreQuery customScore = new CustomScoreQuery(dq.getQuery(tq),fsQuery){
320
321       @Override
322       protected CustomScoreProvider getCustomScoreProvider(IndexReader reader) {
323         return new CustomScoreProvider(reader) {
324           @Override // TODO: broken, as reader is not used!
325           public float customScore(int doc, float subQueryScore, float valSrcScore){
326             if (VERBOSE) System.out.println(doc);
327             if (dq.distanceFilter.getDistance(doc) == null)
328               return 0;
329
330             double distance = dq.distanceFilter.getDistance(doc);
331             // boost score shouldn't exceed 1
332             if (distance < 1.0d)
333               distance = 1.0d;
334             //boost by distance is invertly proportional to
335             // to distance from center point to location
336             float score = (float) ((miles - distance) / miles );
337             return score * subQueryScore;
338           }
339         };
340       }
341       
342     };
343     // Create a distance sort
344     // As the radius filter has performed the distance calculations
345     // already, pass in the filter to reuse the results.
346     //
347     DistanceFieldComparatorSource dsort = new DistanceFieldComparatorSource(dq.distanceFilter);
348     Sort sort = new Sort(new SortField("foo", dsort,false));
349
350     // Perform the search, using the term query, the serial chain filter, and the
351     // distance sort
352     TopDocs hits = searcher.search(customScore.createWeight(searcher),null, 1000, sort);
353     int results = hits.totalHits;
354     ScoreDoc[] scoreDocs = hits.scoreDocs; 
355
356     // Get a list of distances
357     Map<Integer,Double> distances = dq.distanceFilter.getDistances();
358
359     // distances calculated from filter first pass must be less than total
360     // docs, from the above test of 20 items, 12 will come from the boundary box
361     // filter, but only 5 are actually in the radius of the results.
362
363     // Note Boundary Box filtering, is not accurate enough for most systems.
364
365
366     if (VERBOSE) {
367       System.out.println("Distance Filter filtered: " + distances.size());
368       System.out.println("Results: " + results);
369       System.out.println("=============================");
370       System.out.println("Distances should be 18 "+ distances.size());
371       System.out.println("Results should be 18 "+ results);
372     }
373
374     assertEquals(18, distances.size()); // fixed a store of only needed distances
375     assertEquals(18, results);
376     double lastDistance = 0;
377     for(int i =0 ; i < results; i++){
378       Document d = searcher.doc(scoreDocs[i].doc);
379       String name = d.get("name");
380       double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField));
381       double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField));
382       Double geo_distance = distances.get(scoreDocs[i].doc);
383
384       double distance = DistanceUtils.getDistanceMi(lat, lng, rsLat, rsLng);
385       double llm = DistanceUtils.getLLMDistance(lat, lng, rsLat, rsLng);
386       if (VERBOSE) System.out.println("Name: "+ name +", Distance "+ distance); //(res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i));
387       assertTrue(Math.abs((distance - llm)) < 1);
388       if (VERBOSE) System.out.println("checking limit "+ distance + " < " + miles);
389       assertTrue((distance < miles ));
390       if (VERBOSE) System.out.println("checking sort "+ geo_distance + " >= " + lastDistance);
391       assertTrue(geo_distance >= lastDistance);
392       lastDistance = geo_distance;
393     }
394     searcher.close();
395   }
396   
397   public void testRange() throws IOException, InvalidGeoException {
398     searcher = new IndexSearcher(directory, true);
399
400     final double[] milesToTest = new double[] {6.0, 0.5, 0.001, 0.0};
401     final int[] expected = new int[] {7, 1, 0, 0};
402
403     for(int x=0;x<expected.length;x++) {
404     
405       final double miles = milesToTest[x];
406     
407       // create a distance query
408       final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles, 
409                                                                latField, lngField, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true, 2, 15);
410      
411       if (VERBOSE) System.out.println(dq);
412       //create a term query to search against all documents
413       Query tq = new TermQuery(new Term("metafile", "doc"));
414     
415       FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
416     
417       CustomScoreQuery customScore = new CustomScoreQuery(dq.getQuery(tq),fsQuery){
418         @Override
419         protected CustomScoreProvider getCustomScoreProvider(IndexReader reader) {
420           return new CustomScoreProvider(reader) {
421             @Override // TODO: broken, as reader is not used!
422             public float customScore(int doc, float subQueryScore, float valSrcScore){
423               if (VERBOSE) System.out.println(doc);
424               if (dq.distanceFilter.getDistance(doc) == null)
425                 return 0;
426           
427               double distance = dq.distanceFilter.getDistance(doc);
428               // boost score shouldn't exceed 1
429               if (distance < 1.0d)
430                 distance = 1.0d;
431               //boost by distance is invertly proportional to
432               // to distance from center point to location
433               float score = (float) ( (miles - distance) / miles );
434               return score * subQueryScore;
435             }
436           };
437         }
438       };
439       // Create a distance sort
440       // As the radius filter has performed the distance calculations
441       // already, pass in the filter to reuse the results.
442       // 
443       DistanceFieldComparatorSource dsort = new DistanceFieldComparatorSource(dq.distanceFilter);
444       Sort sort = new Sort(new SortField("foo", dsort,false));
445     
446       // Perform the search, using the term query, the serial chain filter, and the
447       // distance sort
448       TopDocs hits = searcher.search(customScore.createWeight(searcher),null, 1000, sort);
449       int results = hits.totalHits;
450       ScoreDoc[] scoreDocs = hits.scoreDocs; 
451     
452       // Get a list of distances 
453       Map<Integer,Double> distances = dq.distanceFilter.getDistances();
454     
455       // distances calculated from filter first pass must be less than total
456       // docs, from the above test of 20 items, 12 will come from the boundary box
457       // filter, but only 5 are actually in the radius of the results.
458     
459       // Note Boundary Box filtering, is not accurate enough for most systems.
460     
461       if (VERBOSE) {
462         System.out.println("Distance Filter filtered: " + distances.size());
463         System.out.println("Results: " + results);
464         System.out.println("=============================");
465         System.out.println("Distances should be 7 "+ expected[x] + ":" + distances.size());
466         System.out.println("Results should be 7 "+ expected[x] + ":" + results);
467       }
468
469       assertEquals(expected[x], distances.size()); // fixed a store of only needed distances
470       assertEquals(expected[x], results);
471       double lastDistance = 0;
472       for(int i =0 ; i < results; i++){
473         Document d = searcher.doc(scoreDocs[i].doc);
474       
475         String name = d.get("name");
476         double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField));
477         double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField)); 
478         Double geo_distance = distances.get(scoreDocs[i].doc);
479       
480         double distance = DistanceUtils.getDistanceMi(lat, lng, rsLat, rsLng);
481         double llm = DistanceUtils.getLLMDistance(lat, lng, rsLat, rsLng);
482         if (VERBOSE) System.out.println("Name: "+ name +", Distance "+ distance); //(res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i));
483         assertTrue(Math.abs((distance - llm)) < 1);
484         assertTrue((distance < miles ));
485         assertTrue(geo_distance > lastDistance);
486         lastDistance = geo_distance;
487       }
488     }
489     searcher.close();
490   }
491   
492   
493   
494   public void testGeoHashRange() throws IOException, InvalidGeoException {
495     searcher = new IndexSearcher(directory, true);
496             
497     final double[] milesToTest = new double[] {6.0, 0.5, 0.001, 0.0};
498     final int[] expected = new int[] {7, 1, 0, 0};
499
500     for(int x=0;x<expected.length;x++) {
501       final double miles = milesToTest[x];
502             
503       // create a distance query
504       final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles, 
505                                                                geoHashPrefix, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true, 2, 15);
506              
507       if (VERBOSE) System.out.println(dq);
508       //create a term query to search against all documents
509       Query tq = new TermQuery(new Term("metafile", "doc"));
510             
511       FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
512       CustomScoreQuery customScore = new CustomScoreQuery(tq,fsQuery){
513         @Override
514         protected CustomScoreProvider getCustomScoreProvider(IndexReader reader) {
515           return new CustomScoreProvider(reader) {
516               @Override // TODO: broken, as reader is not used!
517               public float customScore(int doc, float subQueryScore, float valSrcScore){
518               if (VERBOSE) System.out.println(doc);
519               if (dq.distanceFilter.getDistance(doc) == null)
520                 return 0;
521             
522               double distance = dq.distanceFilter.getDistance(doc);
523               // boost score shouldn't exceed 1
524               if (distance < 1.0d)
525                 distance = 1.0d;
526               //boost by distance is invertly proportional to
527               // to distance from center point to location
528               float score = (float) ( (miles - distance) / miles );
529               return score * subQueryScore;
530             }
531           };
532         }
533       };
534       // Create a distance sort
535       // As the radius filter has performed the distance calculations
536       // already, pass in the filter to reuse the results.
537       // 
538       //DistanceFieldComparatorSource dsort = new DistanceFieldComparatorSource(dq.distanceFilter);
539       //Sort sort = new Sort(new SortField("foo", dsort));
540             
541       // Perform the search, using the term query, the serial chain filter, and the
542       // distance sort
543       TopDocs hits = searcher.search(customScore.createWeight(searcher),dq.getFilter(), 1000); //,sort);
544       int results = hits.totalHits;
545       ScoreDoc[] scoreDocs = hits.scoreDocs; 
546             
547       // Get a list of distances 
548       Map<Integer,Double> distances = dq.distanceFilter.getDistances();
549             
550       // distances calculated from filter first pass must be less than total
551       // docs, from the above test of 20 items, 12 will come from the boundary box
552       // filter, but only 5 are actually in the radius of the results.
553             
554       // Note Boundary Box filtering, is not accurate enough for most systems.
555             
556             if (VERBOSE) {
557         System.out.println("Distance Filter filtered: " + distances.size());
558         System.out.println("Results: " + results);
559         System.out.println("=============================");
560         System.out.println("Distances should be 14 "+ expected[x] + ":" + distances.size());
561         System.out.println("Results should be 7 "+ expected[x] + ":" + results);
562       }
563
564       assertEquals(expected[x], distances.size());
565       assertEquals(expected[x], results);
566             
567       for(int i =0 ; i < results; i++){
568         Document d = searcher.doc(scoreDocs[i].doc);
569               
570         String name = d.get("name");
571         double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField));
572         double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField)); 
573         Double geo_distance = distances.get(scoreDocs[i].doc);
574               
575         double distance = DistanceUtils.getDistanceMi(lat, lng, rsLat, rsLng);
576         double llm = DistanceUtils.getLLMDistance(lat, lng, rsLat, rsLng);
577         if (VERBOSE) System.out.println("Name: "+ name +", Distance (res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ scoreDocs[i].score);
578         assertTrue(Math.abs((distance - llm)) < 1);
579         assertTrue((distance < miles ));
580               
581       }
582     }
583     searcher.close();
584   }
585 }