LUCENE-6780: add missing classes

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1709927 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Knize 2015-10-21 22:07:10 +00:00
parent d369057766
commit 91e6bef3c7
2 changed files with 826 additions and 0 deletions

View File

@ -0,0 +1,67 @@
package org.apache.lucene.util;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** Represents a lat/lon rectangle. */
public class GeoRect {
public final double minLon;
public final double maxLon;
public final double minLat;
public final double maxLat;
public GeoRect(double minLon, double maxLon, double minLat, double maxLat) {
if (GeoUtils.isValidLon(minLon) == false) {
throw new IllegalArgumentException("invalid minLon " + minLon);
}
if (GeoUtils.isValidLon(maxLon) == false) {
throw new IllegalArgumentException("invalid maxLon " + maxLon);
}
if (GeoUtils.isValidLat(minLat) == false) {
throw new IllegalArgumentException("invalid minLat " + minLat);
}
if (GeoUtils.isValidLat(maxLat) == false) {
throw new IllegalArgumentException("invalid maxLat " + maxLat);
}
this.minLon = minLon;
this.maxLon = maxLon;
this.minLat = minLat;
this.maxLat = maxLat;
assert maxLat >= minLat;
// NOTE: cannot assert maxLon >= minLon since this rect could cross the dateline
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("GeoRect(lon=");
b.append(minLon);
b.append(" TO ");
b.append(maxLon);
if (maxLon < minLon) {
b.append(" (crosses dateline!)");
}
b.append(" lat=");
b.append(minLat);
b.append(" TO ");
b.append(maxLat);
b.append(")");
return b.toString();
}
}

View File

@ -0,0 +1,759 @@
package org.apache.lucene.util;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.MultiDocValues;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SimpleCollector;
import org.apache.lucene.store.Directory;
import org.junit.BeforeClass;
// TODO: cutover TestGeoUtils too?
public abstract class BaseGeoPointTestCase extends LuceneTestCase {
protected static final String FIELD_NAME = "point";
private static final double LON_SCALE = (0x1L<<GeoUtils.BITS)/360.0D;
private static final double LAT_SCALE = (0x1L<<GeoUtils.BITS)/180.0D;
private static double originLat;
private static double originLon;
private static double lonRange;
private static double latRange;
@BeforeClass
public static void beforeClassBase() throws Exception {
// Between 1.0 and 3.0:
lonRange = 2 * (random().nextDouble() + 0.5);
latRange = 2 * (random().nextDouble() + 0.5);
originLon = GeoUtils.normalizeLon(GeoUtils.MIN_LON_INCL + lonRange + (GeoUtils.MAX_LON_INCL - GeoUtils.MIN_LON_INCL - 2 * lonRange) * random().nextDouble());
originLat = GeoUtils.normalizeLat(GeoUtils.MIN_LAT_INCL + latRange + (GeoUtils.MAX_LAT_INCL - GeoUtils.MIN_LAT_INCL - 2 * latRange) * random().nextDouble());
}
// A particularly tricky adversary for BKD tree:
@Nightly
public void testSamePointManyTimes() throws Exception {
int numPoints = atLeast(1000);
// TODO: GeoUtils are potentially slow if we use small=false with heavy testing
boolean small = random().nextBoolean();
// Every doc has 2 points:
double theLat = randomLat(small);
double theLon = randomLon(small);
double[] lats = new double[numPoints];
Arrays.fill(lats, theLat);
double[] lons = new double[numPoints];
Arrays.fill(lons, theLon);
verify(small, lats, lons);
}
@Nightly
public void testAllLatEqual() throws Exception {
int numPoints = atLeast(10000);
// TODO: GeoUtils are potentially slow if we use small=false with heavy testing
// boolean small = random().nextBoolean();
boolean small = true;
double lat = randomLat(small);
double[] lats = new double[numPoints];
double[] lons = new double[numPoints];
boolean haveRealDoc = false;
for(int docID=0;docID<numPoints;docID++) {
int x = random().nextInt(20);
if (x == 17) {
// Some docs don't have a point:
lats[docID] = Double.NaN;
if (VERBOSE) {
System.out.println(" doc=" + docID + " is missing");
}
continue;
}
if (docID > 0 && x == 14 && haveRealDoc) {
int oldDocID;
while (true) {
oldDocID = random().nextInt(docID);
if (Double.isNaN(lats[oldDocID]) == false) {
break;
}
}
// Fully identical point:
lons[docID] = lons[oldDocID];
if (VERBOSE) {
System.out.println(" doc=" + docID + " lat=" + lat + " lon=" + lons[docID] + " (same lat/lon as doc=" + oldDocID + ")");
}
} else {
lons[docID] = randomLon(small);
haveRealDoc = true;
if (VERBOSE) {
System.out.println(" doc=" + docID + " lat=" + lat + " lon=" + lons[docID]);
}
}
lats[docID] = lat;
}
verify(small, lats, lons);
}
@Nightly
public void testAllLonEqual() throws Exception {
int numPoints = atLeast(10000);
// TODO: GeoUtils are potentially slow if we use small=false with heavy testing
// boolean small = random().nextBoolean();
boolean small = true;
double theLon = randomLon(small);
double[] lats = new double[numPoints];
double[] lons = new double[numPoints];
boolean haveRealDoc = false;
//System.out.println("theLon=" + theLon);
for(int docID=0;docID<numPoints;docID++) {
int x = random().nextInt(20);
if (x == 17) {
// Some docs don't have a point:
lats[docID] = Double.NaN;
if (VERBOSE) {
System.out.println(" doc=" + docID + " is missing");
}
continue;
}
if (docID > 0 && x == 14 && haveRealDoc) {
int oldDocID;
while (true) {
oldDocID = random().nextInt(docID);
if (Double.isNaN(lats[oldDocID]) == false) {
break;
}
}
// Fully identical point:
lats[docID] = lats[oldDocID];
if (VERBOSE) {
System.out.println(" doc=" + docID + " lat=" + lats[docID] + " lon=" + theLon + " (same lat/lon as doc=" + oldDocID + ")");
}
} else {
lats[docID] = randomLat(small);
haveRealDoc = true;
if (VERBOSE) {
System.out.println(" doc=" + docID + " lat=" + lats[docID] + " lon=" + theLon);
}
}
lons[docID] = theLon;
}
verify(small, lats, lons);
}
@Nightly
public void testMultiValued() throws Exception {
int numPoints = atLeast(10000);
// Every doc has 2 points:
double[] lats = new double[2*numPoints];
double[] lons = new double[2*numPoints];
Directory dir = newDirectory();
IndexWriterConfig iwc = newIndexWriterConfig();
initIndexWriterConfig(FIELD_NAME, iwc);
// We rely on docID order:
iwc.setMergePolicy(newLogMergePolicy());
RandomIndexWriter w = new RandomIndexWriter(random(), dir, iwc);
// TODO: GeoUtils are potentially slow if we use small=false with heavy testing
boolean small = random().nextBoolean();
//boolean small = true;
for (int id=0;id<numPoints;id++) {
Document doc = new Document();
lats[2*id] = randomLat(small);
lons[2*id] = randomLon(small);
doc.add(newStringField("id", ""+id, Field.Store.YES));
addPointToDoc(FIELD_NAME, doc, lats[2*id], lons[2*id]);
lats[2*id+1] = randomLat(small);
lons[2*id+1] = randomLon(small);
addPointToDoc(FIELD_NAME, doc, lats[2*id+1], lons[2*id+1]);
if (VERBOSE) {
System.out.println("id=" + id);
System.out.println(" lat=" + lats[2*id] + " lon=" + lons[2*id]);
System.out.println(" lat=" + lats[2*id+1] + " lon=" + lons[2*id+1]);
}
w.addDocument(doc);
}
if (random().nextBoolean()) {
w.forceMerge(1);
}
IndexReader r = w.getReader();
w.close();
// We can't wrap with "exotic" readers because the BKD query must see the BKDDVFormat:
IndexSearcher s = newSearcher(r, false);
int iters = atLeast(75);
for (int iter=0;iter<iters;iter++) {
GeoRect rect = randomRect(small, small == false);
if (VERBOSE) {
System.out.println("\nTEST: iter=" + iter + " bbox=" + rect);
}
Query query = newBBoxQuery(FIELD_NAME, rect);
final FixedBitSet hits = new FixedBitSet(r.maxDoc());
s.search(query, new SimpleCollector() {
private int docBase;
@Override
public boolean needsScores() {
return false;
}
@Override
protected void doSetNextReader(LeafReaderContext context) throws IOException {
docBase = context.docBase;
}
@Override
public void collect(int doc) {
hits.set(docBase+doc);
}
});
boolean fail = false;
for(int docID=0;docID<lats.length/2;docID++) {
double latDoc1 = lats[2*docID];
double lonDoc1 = lons[2*docID];
double latDoc2 = lats[2*docID+1];
double lonDoc2 = lons[2*docID+1];
Boolean result1 = rectContainsPoint(rect, latDoc1, lonDoc1);
if (result1 == null) {
// borderline case: cannot test
continue;
}
Boolean result2 = rectContainsPoint(rect, latDoc2, lonDoc2);
if (result2 == null) {
// borderline case: cannot test
continue;
}
boolean expected = result1 == Boolean.TRUE || result2 == Boolean.TRUE;
if (hits.get(docID) != expected) {
String id = s.doc(docID).get("id");
if (expected) {
System.out.println(Thread.currentThread().getName() + ": id=" + id + " docID=" + docID + " should match but did not");
} else {
System.out.println(Thread.currentThread().getName() + ": id=" + id + " docID=" + docID + " should not match but did");
}
System.out.println(" rect=" + rect);
System.out.println(" lat=" + latDoc1 + " lon=" + lonDoc1 + "\n lat=" + latDoc2 + " lon=" + lonDoc2);
System.out.println(" result1=" + result1 + " result2=" + result2);
fail = true;
}
}
if (fail) {
fail("some hits were wrong");
}
}
r.close();
dir.close();
}
public void testRandomTiny() throws Exception {
// Make sure single-leaf-node case is OK:
doTestRandom(10);
}
public void testRandomMedium() throws Exception {
doTestRandom(10000);
}
@Nightly
public void testRandomBig() throws Exception {
doTestRandom(200000);
}
private void doTestRandom(int count) throws Exception {
int numPoints = atLeast(count);
if (VERBOSE) {
System.out.println("TEST: numPoints=" + numPoints);
}
double[] lats = new double[numPoints];
double[] lons = new double[numPoints];
// TODO: GeoUtils are potentially slow if we use small=false with heavy testing
boolean small = random().nextBoolean();
boolean haveRealDoc = false;
for (int id=0;id<numPoints;id++) {
int x = random().nextInt(20);
if (x == 17) {
// Some docs don't have a point:
lats[id] = Double.NaN;
if (VERBOSE) {
System.out.println(" id=" + id + " is missing");
}
continue;
}
if (id > 0 && x < 3 && haveRealDoc) {
int oldID;
while (true) {
oldID = random().nextInt(id);
if (Double.isNaN(lats[oldID]) == false) {
break;
}
}
if (x == 0) {
// Identical lat to old point
lats[id] = lats[oldID];
lons[id] = randomLon(small);
if (VERBOSE) {
System.out.println(" id=" + id + " lat=" + lats[id] + " lon=" + lons[id] + " (same lat as doc=" + oldID + ")");
}
} else if (x == 1) {
// Identical lon to old point
lats[id] = randomLat(small);
lons[id] = lons[oldID];
if (VERBOSE) {
System.out.println(" id=" + id + " lat=" + lats[id] + " lon=" + lons[id] + " (same lon as doc=" + oldID + ")");
}
} else {
assert x == 2;
// Fully identical point:
lats[id] = lats[oldID];
lons[id] = lons[oldID];
if (VERBOSE) {
System.out.println(" id=" + id + " lat=" + lats[id] + " lon=" + lons[id] + " (same lat/lon as doc=" + oldID + ")");
}
}
} else {
lats[id] = randomLat(small);
lons[id] = randomLon(small);
haveRealDoc = true;
if (VERBOSE) {
System.out.println(" id=" + id + " lat=" + lats[id] + " lon=" + lons[id]);
}
}
}
verify(small, lats, lons);
}
public long scaleLon(final double val) {
return (long) ((val-GeoUtils.MIN_LON_INCL) * LON_SCALE);
}
public long scaleLat(final double val) {
return (long) ((val-GeoUtils.MIN_LAT_INCL) * LAT_SCALE);
}
public double unscaleLon(final long val) {
return (val / LON_SCALE) + GeoUtils.MIN_LON_INCL;
}
public double unscaleLat(final long val) {
return (val / LAT_SCALE) + GeoUtils.MIN_LAT_INCL;
}
public double randomLat(boolean small) {
double result;
if (small) {
result = GeoUtils.normalizeLat(originLat + latRange * (random().nextDouble() - 0.5));
} else {
result = -90 + 180.0 * random().nextDouble();
}
return unscaleLat(scaleLat(result));
}
public double randomLon(boolean small) {
double result;
if (small) {
result = GeoUtils.normalizeLon(originLon + lonRange * (random().nextDouble() - 0.5));
} else {
result = -180 + 360.0 * random().nextDouble();
}
return unscaleLon(scaleLon(result));
}
protected GeoRect randomRect(boolean small, boolean canCrossDateLine) {
double lat0 = randomLat(small);
double lat1 = randomLat(small);
double lon0 = randomLon(small);
double lon1 = randomLon(small);
if (lat1 < lat0) {
double x = lat0;
lat0 = lat1;
lat1 = x;
}
if (canCrossDateLine == false && lon1 < lon0) {
double x = lon0;
lon0 = lon1;
lon1 = x;
}
return new GeoRect(lon0, lon1, lat0, lat1);
}
protected void initIndexWriterConfig(String field, IndexWriterConfig iwc) {
}
protected abstract void addPointToDoc(String field, Document doc, double lat, double lon);
protected abstract Query newBBoxQuery(String field, GeoRect bbox);
protected abstract Query newDistanceQuery(String field, double centerLat, double centerLon, double radiusMeters);
protected abstract Query newDistanceRangeQuery(String field, double centerLat, double centerLon, double minRadiusMeters, double radiusMeters);
protected abstract Query newPolygonQuery(String field, double[] lats, double[] lons);
/** Returns null if it's borderline case */
protected abstract Boolean rectContainsPoint(GeoRect rect, double pointLat, double pointLon);
/** Returns null if it's borderline case */
protected abstract Boolean polyRectContainsPoint(GeoRect rect, double pointLat, double pointLon);
/** Returns null if it's borderline case */
protected abstract Boolean circleContainsPoint(double centerLat, double centerLon, double radiusMeters, double pointLat, double pointLon);
protected abstract Boolean distanceRangeContainsPoint(double centerLat, double centerLon, double minRadiusMeters, double radiusMeters, double pointLat, double pointLon);
private static abstract class VerifyHits {
public void test(boolean small, IndexSearcher s, NumericDocValues docIDToID, Set<Integer> deleted, Query query, double[] lats, double[] lons) throws Exception {
int maxDoc = s.getIndexReader().maxDoc();
final FixedBitSet hits = new FixedBitSet(maxDoc);
s.search(query, new SimpleCollector() {
private int docBase;
@Override
public boolean needsScores() {
return false;
}
@Override
protected void doSetNextReader(LeafReaderContext context) throws IOException {
docBase = context.docBase;
}
@Override
public void collect(int doc) {
hits.set(docBase+doc);
}
});
boolean fail = false;
for(int docID=0;docID<maxDoc;docID++) {
int id = (int) docIDToID.get(docID);
Boolean expected;
if (deleted.contains(id)) {
expected = false;
} else if (Double.isNaN(lats[id])) {
expected = false;
} else {
expected = shouldMatch(lats[id], lons[id]);
}
// null means it's a borderline case which is allowed to be wrong:
if (expected != null && hits.get(docID) != expected) {
if (expected) {
System.out.println(Thread.currentThread().getName() + ": id=" + id + " should match but did not");
} else {
System.out.println(Thread.currentThread().getName() + ": id=" + id + " should not match but did");
}
System.out.println(" small=" + small + " query=" + query +
" docID=" + docID + "\n lat=" + lats[id] + " lon=" + lons[id] +
"\n deleted?=" + deleted.contains(id));
if (Double.isNaN(lats[id]) == false) {
describe(docID, lats[id], lons[id]);
}
fail = true;
}
}
if (fail) {
fail("some hits were wrong");
}
}
/** Return true if we definitely should match, false if we definitely
* should not match, and null if it's a borderline case which might
* go either way. */
protected abstract Boolean shouldMatch(double lat, double lon);
protected abstract void describe(int docID, double lat, double lon);
}
protected void verify(boolean small, double[] lats, double[] lons) throws Exception {
IndexWriterConfig iwc = newIndexWriterConfig();
// Else we can get O(N^2) merging:
int mbd = iwc.getMaxBufferedDocs();
if (mbd != -1 && mbd < lats.length/100) {
iwc.setMaxBufferedDocs(lats.length/100);
}
initIndexWriterConfig(FIELD_NAME, iwc);
Directory dir;
if (lats.length > 100000) {
dir = newFSDirectory(createTempDir(getClass().getSimpleName()));
} else {
dir = newDirectory();
}
Set<Integer> deleted = new HashSet<>();
// RandomIndexWriter is too slow here:
IndexWriter w = new IndexWriter(dir, iwc);
for(int id=0;id<lats.length;id++) {
Document doc = new Document();
doc.add(newStringField("id", ""+id, Field.Store.NO));
doc.add(new NumericDocValuesField("id", id));
if (Double.isNaN(lats[id]) == false) {
addPointToDoc(FIELD_NAME, doc, lats[id], lons[id]);
}
w.addDocument(doc);
if (id > 0 && random().nextInt(100) == 42) {
int idToDelete = random().nextInt(id);
w.deleteDocuments(new Term("id", ""+idToDelete));
deleted.add(idToDelete);
if (VERBOSE) {
System.out.println(" delete id=" + idToDelete);
}
}
}
if (random().nextBoolean()) {
w.forceMerge(1);
}
final IndexReader r = DirectoryReader.open(w, true);
w.close();
// We can't wrap with "exotic" readers because the BKD query must see the BKDDVFormat:
IndexSearcher s = newSearcher(r, false);
// Make sure queries are thread safe:
int numThreads = TestUtil.nextInt(random(), 2, 5);
List<Thread> threads = new ArrayList<>();
final int iters = atLeast(75);
final CountDownLatch startingGun = new CountDownLatch(1);
final AtomicBoolean failed = new AtomicBoolean();
for(int i=0;i<numThreads;i++) {
Thread thread = new Thread() {
@Override
public void run() {
try {
_run();
} catch (Exception e) {
failed.set(true);
throw new RuntimeException(e);
}
}
private void _run() throws Exception {
startingGun.await();
NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
for (int iter=0;iter<iters && failed.get() == false;iter++) {
if (VERBOSE) {
System.out.println("\nTEST: iter=" + iter + " s=" + s);
}
Query query;
VerifyHits verifyHits;
if (random().nextBoolean()) {
// BBox: don't allow dateline crossing when testing small:
final GeoRect bbox = randomRect(small, small == false);
query = newBBoxQuery(FIELD_NAME, bbox);
verifyHits = new VerifyHits() {
@Override
protected Boolean shouldMatch(double pointLat, double pointLon) {
return rectContainsPoint(bbox, pointLat, pointLon);
}
@Override
protected void describe(int docID, double lat, double lon) {
}
};
} else if (random().nextBoolean()) {
// Distance
final boolean rangeQuery = random().nextBoolean();
final double centerLat = randomLat(small);
final double centerLon = randomLon(small);
double radiusMeters;
double minRadiusMeters;
if (small) {
// Approx 3 degrees lon at the equator:
radiusMeters = random().nextDouble() * 333000 + 1.0;
} else {
// So the query can cover at most 50% of the earth's surface:
radiusMeters = random().nextDouble() * GeoProjectionUtils.SEMIMAJOR_AXIS * Math.PI / 2.0 + 1.0;
}
// generate a random minimum radius between 1% and 95% the max radius
minRadiusMeters = (0.01 + 0.94 * random().nextDouble()) * radiusMeters;
if (VERBOSE) {
final DecimalFormat df = new DecimalFormat("#,###.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
System.out.println(" radiusMeters = " + df.format(radiusMeters)
+ ((rangeQuery == true) ? " minRadiusMeters = " + df.format(minRadiusMeters) : ""));
}
try {
if (rangeQuery == true) {
query = newDistanceRangeQuery(FIELD_NAME, centerLat, centerLon, minRadiusMeters, radiusMeters);
} else {
query = newDistanceQuery(FIELD_NAME, centerLat, centerLon, radiusMeters);
}
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("exceeds maxRadius")) {
continue;
}
throw e;
}
verifyHits = new VerifyHits() {
@Override
protected Boolean shouldMatch(double pointLat, double pointLon) {
if (rangeQuery == false) {
return circleContainsPoint(centerLat, centerLon, radiusMeters, pointLat, pointLon);
} else {
return distanceRangeContainsPoint(centerLat, centerLon, minRadiusMeters, radiusMeters, pointLat, pointLon);
}
}
@Override
protected void describe(int docID, double pointLat, double pointLon) {
double distanceKM = SloppyMath.haversin(centerLat, centerLon, pointLat, pointLon);
System.out.println(" docID=" + docID + " centerLon=" + centerLon + " centerLat=" + centerLat
+ " pointLon=" + pointLon + " pointLat=" + pointLat + " distanceMeters=" + (distanceKM * 1000)
+ " vs" + ((rangeQuery == true) ? " minRadiusMeters=" + minRadiusMeters : "") + " radiusMeters=" + radiusMeters);
}
};
// TODO: get poly query working with dateline crossing too (how?)!
} else {
// TODO: poly query can't handle dateline crossing yet:
final GeoRect bbox = randomRect(small, false);
// Polygon
double[] lats = new double[5];
double[] lons = new double[5];
lats[0] = bbox.minLat;
lons[0] = bbox.minLon;
lats[1] = bbox.maxLat;
lons[1] = bbox.minLon;
lats[2] = bbox.maxLat;
lons[2] = bbox.maxLon;
lats[3] = bbox.minLat;
lons[3] = bbox.maxLon;
lats[4] = bbox.minLat;
lons[4] = bbox.minLon;
query = newPolygonQuery(FIELD_NAME, lats, lons);
verifyHits = new VerifyHits() {
@Override
protected Boolean shouldMatch(double pointLat, double pointLon) {
return polyRectContainsPoint(bbox, pointLat, pointLon);
}
@Override
protected void describe(int docID, double lat, double lon) {
}
};
}
if (query != null) {
if (VERBOSE) {
System.out.println(" query=" + query);
}
verifyHits.test(small, s, docIDToID, deleted, query, lats, lons);
}
}
}
};
thread.setName("T" + i);
thread.start();
threads.add(thread);
}
startingGun.countDown();
for(Thread thread : threads) {
thread.join();
}
IOUtils.close(r, dir);
}
}