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
Dat via Mike McCandless)
* LUCENE-6560: BKDPointInBBoxQuery now handles "dateline crossing"
correctly (Nick Knize, Mike McCandless)
Changes in Runtime Behavior
* LUCENE-6501: The subreader structure in ParallelCompositeReader

View File

@ -17,13 +17,13 @@ package org.apache.lucene.bkdtree;
* limitations under the License.
*/
import java.io.IOException;
import java.util.Set;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedNumericDocValues;
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.DocIdSetIterator;
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.ToStringUtils;
import java.io.IOException;
import java.util.Set;
/** 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.
@ -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
public int hashCode() {
int hash = super.hashCode();

View File

@ -452,18 +452,27 @@ public class TestBKDTree extends LuceneTestCase {
lat1 = x;
}
boolean crossesDateLine;
if (lon1 < lon0) {
double x = lon0;
lon0 = lon1;
lon1 = x;
if (random().nextBoolean()) {
double x = lon0;
lon0 = lon1;
lon1 = x;
crossesDateLine = false;
} else {
crossesDateLine = true;
}
} else {
crossesDateLine = false;
}
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;
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);
} else {
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
} else {
// 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 pointLonEnc = BKDTreeWriter.encodeLon(pointLon);
return pointLatEnc >= rectLatMinEnc &&
pointLatEnc < rectLatMaxEnc &&
pointLonEnc >= rectLonMinEnc &&
pointLonEnc < rectLonMaxEnc;
if (rectLonMin < rectLonMax) {
return pointLatEnc >= rectLatMinEnc &&
pointLatEnc < rectLatMaxEnc &&
pointLonEnc >= rectLonMinEnc &&
pointLonEnc < rectLonMaxEnc;
} else {
// Rect crosses dateline:
return pointLatEnc >= rectLatMinEnc &&
pointLatEnc < rectLatMaxEnc &&
(pointLonEnc >= rectLonMinEnc ||
pointLonEnc < rectLonMaxEnc);
}
}
private static double randomLat() {