LUCENE-6560: BKDPointInBBOxQuery now handles dateline crossing correctly

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1685526 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2015-06-15 10:22:16 +00:00
parent a1876da5ee
commit 0ef770fcd0
3 changed files with 58 additions and 13 deletions

View File

@ -122,6 +122,9 @@ Bug fixes
* LUCENE-6558: Highlighters now work with CustomScoreQuery (Cao Manh * LUCENE-6558: Highlighters now work with CustomScoreQuery (Cao Manh
Dat via Mike McCandless) Dat via Mike McCandless)
* LUCENE-6560: BKDPointInBBoxQuery now handles "dateline crossing"
correctly (Nick Knize, Mike McCandless)
Changes in Runtime Behavior Changes in Runtime Behavior
* LUCENE-6501: The subreader structure in ParallelCompositeReader * LUCENE-6501: The subreader structure in ParallelCompositeReader

View File

@ -17,13 +17,13 @@ package org.apache.lucene.bkdtree;
* limitations under the License. * limitations under the License.
*/ */
import java.io.IOException; import org.apache.lucene.index.IndexReader;
import java.util.Set;
import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Explanation; import org.apache.lucene.search.Explanation;
@ -34,6 +34,9 @@ import org.apache.lucene.search.Weight;
import org.apache.lucene.util.Bits; import org.apache.lucene.util.Bits;
import org.apache.lucene.util.ToStringUtils; import org.apache.lucene.util.ToStringUtils;
import java.io.IOException;
import java.util.Set;
/** Finds all previously indexed points that fall within the specified boundings box. /** Finds all previously indexed points that fall within the specified boundings box.
* *
* <p>The field must be indexed with {@link BKDTreeDocValuesFormat}, and {@link BKDPointField} added per document. * <p>The field must be indexed with {@link BKDTreeDocValuesFormat}, and {@link BKDPointField} added per document.
@ -163,6 +166,28 @@ public class BKDPointInBBoxQuery extends Query {
} }
}; };
} }
@Override
public Query rewrite(IndexReader reader) throws IOException {
// Crosses date line: we just rewrite into OR of two bboxes:
if (maxLon < minLon) {
// Disable coord here because a multi-valued doc could match both rects and get unfairly boosted:
BooleanQuery q = new BooleanQuery(true);
// E.g.: maxLon = -179, minLon = 179
BKDPointInBBoxQuery left = new BKDPointInBBoxQuery(field, minLat, maxLat, BKDTreeWriter.MIN_LON_INCL, maxLon);
left.setBoost(getBoost());
q.add(new BooleanClause(left, BooleanClause.Occur.SHOULD));
BKDPointInBBoxQuery right = new BKDPointInBBoxQuery(field, minLat, maxLat, minLon, BKDTreeWriter.MAX_LON_INCL);
right.setBoost(getBoost());
q.add(new BooleanClause(right, BooleanClause.Occur.SHOULD));
return q;
} else {
return this;
}
}
@Override @Override
public int hashCode() { public int hashCode() {
int hash = super.hashCode(); int hash = super.hashCode();

View File

@ -452,18 +452,27 @@ public class TestBKDTree extends LuceneTestCase {
lat1 = x; lat1 = x;
} }
boolean crossesDateLine;
if (lon1 < lon0) { if (lon1 < lon0) {
double x = lon0; if (random().nextBoolean()) {
lon0 = lon1; double x = lon0;
lon1 = x; lon0 = lon1;
lon1 = x;
crossesDateLine = false;
} else {
crossesDateLine = true;
}
} else {
crossesDateLine = false;
} }
if (VERBOSE) { if (VERBOSE) {
System.out.println("\nTEST: iter=" + iter + " lat=" + lat0 + " TO " + lat1 + " lon=" + lon0 + " TO " + lon1); System.out.println("\nTEST: iter=" + iter + " lat=" + lat0 + " TO " + lat1 + " lon=" + lon0 + " TO " + lon1 + " crossesDateLine=" + crossesDateLine);
} }
Query query; Query query;
if (random().nextBoolean()) { // TODO: get poly query working with dateline crossing too (how?)!
if (crossesDateLine || random().nextBoolean()) {
query = new BKDPointInBBoxQuery("point", lat0, lat1, lon0, lon1); query = new BKDPointInBBoxQuery("point", lat0, lat1, lon0, lon1);
} else { } else {
double[] lats = new double[5]; double[] lats = new double[5];
@ -522,7 +531,7 @@ public class TestBKDTree extends LuceneTestCase {
// The poly check quantizes slightly differently, so we allow for boundary cases to disagree // The poly check quantizes slightly differently, so we allow for boundary cases to disagree
} else { } else {
// We do exact quantized comparison so the bbox query should never disagree: // We do exact quantized comparison so the bbox query should never disagree:
fail(Thread.currentThread().getName() + ": iter=" + iter + " id=" + id + " docID=" + docID + " lat=" + lats[id] + " lon=" + lons[id] + " (bbox: lat=" + lat0 + " TO " + lat1 + " lon=" + lon0 + " TO " + lon1 + ") expected " + expected + " but got: " + hits.get(docID) + " deleted?=" + deleted.contains(id) + " query=" + query); fail(Thread.currentThread().getName() + ": iter=" + iter + " id=" + id + " docID=" + docID + " lat=" + lats[id] + " lon=" + lons[id] + " (bbox: lat=" + lat0 + " TO " + lat1 + " lon=" + lon0 + " TO " + lon1 + ") expected " + expected + " but got: " + hits.get(docID) + " deleted?=" + deleted.contains(id) + " query=" + query + " crossesDateLine=" + crossesDateLine);
} }
} }
} }
@ -553,10 +562,18 @@ public class TestBKDTree extends LuceneTestCase {
int pointLatEnc = BKDTreeWriter.encodeLat(pointLat); int pointLatEnc = BKDTreeWriter.encodeLat(pointLat);
int pointLonEnc = BKDTreeWriter.encodeLon(pointLon); int pointLonEnc = BKDTreeWriter.encodeLon(pointLon);
return pointLatEnc >= rectLatMinEnc && if (rectLonMin < rectLonMax) {
pointLatEnc < rectLatMaxEnc && return pointLatEnc >= rectLatMinEnc &&
pointLonEnc >= rectLonMinEnc && pointLatEnc < rectLatMaxEnc &&
pointLonEnc < rectLonMaxEnc; pointLonEnc >= rectLonMinEnc &&
pointLonEnc < rectLonMaxEnc;
} else {
// Rect crosses dateline:
return pointLatEnc >= rectLatMinEnc &&
pointLatEnc < rectLatMaxEnc &&
(pointLonEnc >= rectLonMinEnc ||
pointLonEnc < rectLonMaxEnc);
}
} }
private static double randomLat() { private static double randomLat() {