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 d34dc47c82
commit 0b0e442010
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.BasePlanetObject;
import org.apache.lucene.spatial3d.geom.GeoShape; import org.apache.lucene.spatial3d.geom.GeoShape;
import org.apache.lucene.spatial3d.geom.PlanetModel; 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.PointValues;
import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
@ -41,11 +42,14 @@ import org.apache.lucene.util.DocIdSetBuilder;
final class PointInGeo3DShapeQuery extends Query { final class PointInGeo3DShapeQuery extends Query {
final String field; final String field;
final GeoShape shape; final GeoShape shape;
final XYZBounds shapeBounds;
/** The lats/lons must be clockwise or counter-clockwise. */ /** The lats/lons must be clockwise or counter-clockwise. */
public PointInGeo3DShapeQuery(String field, GeoShape shape) { public PointInGeo3DShapeQuery(String field, GeoShape shape) {
this.field = field; this.field = field;
this.shape = shape; this.shape = shape;
this.shapeBounds = new XYZBounds();
shape.getBounds(shapeBounds);
if (shape instanceof BasePlanetObject) { if (shape instanceof BasePlanetObject) {
BasePlanetObject planetObject = (BasePlanetObject) shape; BasePlanetObject planetObject = (BasePlanetObject) shape;
@ -95,7 +99,7 @@ final class PointInGeo3DShapeQuery extends Query {
DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc()); 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()); 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.GeoAreaFactory;
import org.apache.lucene.spatial3d.geom.GeoShape; import org.apache.lucene.spatial3d.geom.GeoShape;
import org.apache.lucene.spatial3d.geom.PlanetModel; 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.DocIdSetBuilder;
import org.apache.lucene.util.NumericUtils; import org.apache.lucene.util.NumericUtils;
class PointInShapeIntersectVisitor implements IntersectVisitor { class PointInShapeIntersectVisitor implements IntersectVisitor {
private final DocIdSetBuilder hits; private final DocIdSetBuilder hits;
private final GeoShape shape; 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.hits = hits;
this.shape = shape; this.shape = shape;
this.shapeBounds = shapeBounds;
} }
@Override @Override
@ -46,10 +49,14 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
double x = Geo3DPoint.decodeDimension(packedValue, 0); double x = Geo3DPoint.decodeDimension(packedValue, 0);
double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES); double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
double z = Geo3DPoint.decodeDimension(packedValue, 2 * 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)) { if (shape.isWithin(x, y, z)) {
hits.add(docID); hits.add(docID);
} }
} }
}
@Override @Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) { public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
@ -69,6 +76,14 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
assert yMin <= yMax; assert yMin <= yMax;
assert zMin <= zMax; 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); GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
switch(xyzSolid.getRelationship(shape)) { switch(xyzSolid.getRelationship(shape)) {