LUCENE-7221: Limit the number of requests to getRelationship() and isWithin() using bounds.

This commit is contained in:
Karl Wright 2016-04-14 20:46:38 -04:00
parent 43b8456cdf
commit 1d76b2c49b
2 changed files with 26 additions and 7 deletions

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import org.apache.lucene.spatial3d.geom.BasePlanetObject;
import org.apache.lucene.spatial3d.geom.GeoShape;
import org.apache.lucene.spatial3d.geom.PlanetModel;
import org.apache.lucene.spatial3d.geom.XYZBounds;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
@ -41,11 +42,14 @@ import org.apache.lucene.util.DocIdSetBuilder;
final class PointInGeo3DShapeQuery extends Query {
final String field;
final GeoShape shape;
final XYZBounds shapeBounds;
/** The lats/lons must be clockwise or counter-clockwise. */
public PointInGeo3DShapeQuery(String field, GeoShape shape) {
this.field = field;
this.shape = shape;
this.shapeBounds = new XYZBounds();
shape.getBounds(shapeBounds);
if (shape instanceof BasePlanetObject) {
BasePlanetObject planetObject = (BasePlanetObject) shape;
@ -95,7 +99,7 @@ final class PointInGeo3DShapeQuery extends Query {
DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc());
values.intersect(field, new PointInShapeIntersectVisitor(result, shape));
values.intersect(field, new PointInShapeIntersectVisitor(result, shape, shapeBounds));
return new ConstantScoreScorer(this, score(), result.build().iterator());
}

View File

@ -23,16 +23,19 @@ import org.apache.lucene.spatial3d.geom.GeoArea;
import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
import org.apache.lucene.spatial3d.geom.GeoShape;
import org.apache.lucene.spatial3d.geom.PlanetModel;
import org.apache.lucene.spatial3d.geom.XYZBounds;
import org.apache.lucene.util.DocIdSetBuilder;
import org.apache.lucene.util.NumericUtils;
class PointInShapeIntersectVisitor implements IntersectVisitor {
private final DocIdSetBuilder hits;
private final GeoShape shape;
private final XYZBounds shapeBounds;
public PointInShapeIntersectVisitor(DocIdSetBuilder hits, GeoShape shape) {
public PointInShapeIntersectVisitor(DocIdSetBuilder hits, GeoShape shape, XYZBounds shapeBounds) {
this.hits = hits;
this.shape = shape;
this.shapeBounds = shapeBounds;
}
@Override
@ -46,10 +49,14 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
double x = Geo3DPoint.decodeDimension(packedValue, 0);
double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
if (x >= shapeBounds.getMinimumX() && x <= shapeBounds.getMaximumX() &&
y >= shapeBounds.getMinimumY() && y <= shapeBounds.getMaximumY() &&
z >= shapeBounds.getMinimumZ() && z <= shapeBounds.getMaximumZ()) {
if (shape.isWithin(x, y, z)) {
hits.add(docID);
}
}
}
@Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
@ -69,6 +76,14 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
assert yMin <= yMax;
assert zMin <= zMax;
// First, check bounds. If the shape is entirely contained, return CELL_CROSSES_QUERY.
if (shapeBounds.getMinimumX() >= xMin && shapeBounds.getMaximumX() <= xMax &&
shapeBounds.getMinimumY() >= yMin && shapeBounds.getMaximumY() <= yMax &&
shapeBounds.getMinimumZ() >= zMin && shapeBounds.getMaximumZ() <= zMax) {
return Relation.CELL_CROSSES_QUERY;
}
// Quick test failed so do slower one...
GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
switch(xyzSolid.getRelationship(shape)) {