blob: 1ee77f810a145e019eeedecf966cdb0cab888fad [file] [log] [blame]
Index: lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/RecursivePrefixTreeStrategy.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/RecursivePrefixTreeStrategy.java (revision 0aea8cbc72859f49edabc410a1061911362592be)
+++ lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/RecursivePrefixTreeStrategy.java (revision )
@@ -20,9 +20,9 @@
import java.util.Iterator;
import java.util.List;
-import org.locationtech.spatial4j.shape.Point;
-import org.locationtech.spatial4j.shape.Shape;
+import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.CellIterator;
import org.apache.lucene.spatial.prefix.tree.LegacyCell;
@@ -30,6 +30,7 @@
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
+import org.locationtech.spatial4j.shape.Shape;
/**
* A {@link PrefixTreeStrategy} which uses {@link AbstractVisitingPrefixTreeQuery}.
@@ -121,7 +122,7 @@
@Override
protected Iterator<Cell> createCellIteratorToIndex(Shape shape, int detailLevel, Iterator<Cell> reuse) {
- if (shape instanceof Point || !pruneLeafyBranches)
+ if (!pruneLeafyBranches || isGridAlignedShape(shape))
return super.createCellIteratorToIndex(shape, detailLevel, reuse);
List<Cell> cells = new ArrayList<>(4096);
@@ -177,6 +178,9 @@
int detailLevel = grid.getLevelForDistance(args.resolveDistErr(ctx, distErrPct));
if (op == SpatialOperation.Intersects) {
+ if (isGridAlignedShape(args.getShape())) {
+ return makeGridShapeIntersectsQuery(args.getShape());
+ }
return new IntersectsPrefixTreeQuery(
shape, getFieldName(), grid, detailLevel, prefixGridScanLevel);
} else if (op == SpatialOperation.IsWithin) {
@@ -189,4 +193,35 @@
}
throw new UnsupportedSpatialOperation(op);
}
+
+ /**
+ * A quick check of the shape to see if it is perfectly aligned to a grid.
+ * Points always are as they are indivisible. It's okay to return false
+ * if the shape actually is aligned; this is an optimization hint.
+ */
+ protected boolean isGridAlignedShape(Shape shape) {
+ return isPointShape(shape);
+ }
+
+ /** {@link #makeQuery(SpatialArgs)} specialized for the query being a grid square. */
+ protected Query makeGridShapeIntersectsQuery(Shape gridShape) {
+ assert isGridAlignedShape(gridShape);
+ if (isPointsOnly()) {
+ // Awesome; this will be equivalent to a TermQuery.
+ Iterator<Cell> cellIterator = grid.getTreeCellIterator(gridShape, grid.getMaxLevels());
+ // get last cell
+ Cell cell = cellIterator.next();
+ while (cellIterator.hasNext()) {
+ int prevLevel = cell.getLevel();
+ cell = cellIterator.next();
+ assert prevLevel < cell.getLevel();
+ }
+ return new TermQuery(new Term(getFieldName(), cell.getTokenBytesWithLeaf(null)));
+ } else {
+ // Well there could be parent cells. But we can reduce the "scan level" which will be slower for a point query.
+ // TODO: AVPTQ will still scan the bottom nonetheless; file an issue to eliminate that
+ return new IntersectsPrefixTreeQuery(
+ gridShape, getFieldName(), grid, getGrid().getMaxLevels(), getGrid().getMaxLevels() + 1);
+ }
+ }
}
Index: lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/PrefixTreeStrategy.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/PrefixTreeStrategy.java (revision 0aea8cbc72859f49edabc410a1061911362592be)
+++ lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/PrefixTreeStrategy.java (revision )
@@ -21,8 +21,6 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import org.locationtech.spatial4j.shape.Point;
-import org.locationtech.spatial4j.shape.Shape;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
@@ -34,6 +32,10 @@
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.util.ShapeFieldCacheDistanceValueSource;
import org.apache.lucene.util.Bits;
+import org.locationtech.spatial4j.shape.Circle;
+import org.locationtech.spatial4j.shape.Point;
+import org.locationtech.spatial4j.shape.Rectangle;
+import org.locationtech.spatial4j.shape.Shape;
/**
* An abstract SpatialStrategy based on {@link SpatialPrefixTree}. The two
@@ -163,7 +165,7 @@
}
protected Iterator<Cell> createCellIteratorToIndex(Shape shape, int detailLevel, Iterator<Cell> reuse) {
- if (pointsOnly && !(shape instanceof Point)) {
+ if (pointsOnly && !isPointShape(shape)) {
throw new IllegalArgumentException("pointsOnly is true yet a " + shape.getClass() + " is given for indexing");
}
return grid.getTreeCellIterator(shape, detailLevel);//TODO should take a re-use iterator
@@ -205,4 +207,16 @@
Shape inputShape, final int facetLevel, int maxCells) throws IOException {
return HeatmapFacetCounter.calcFacets(this, context, topAcceptDocs, inputShape, facetLevel, maxCells);
}
+
+ protected boolean isPointShape(Shape shape) {
+ if (shape instanceof Point) {
+ return true;
+ } else if (shape instanceof Circle) {
+ return ((Circle) shape).getRadius() == 0.0;
+ } else if (shape instanceof Rectangle) {
+ Rectangle rect = (Rectangle) shape;
+ return rect.getWidth() == 0.0 && rect.getHeight() == 0.0;
+ }
+ return false;
+ }
}
Index: lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/NumberRangePrefixTreeStrategy.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/NumberRangePrefixTreeStrategy.java (revision 0aea8cbc72859f49edabc410a1061911362592be)
+++ lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/NumberRangePrefixTreeStrategy.java (revision )
@@ -18,18 +18,17 @@
import java.io.IOException;
import java.util.Arrays;
-import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
-import org.locationtech.spatial4j.shape.Point;
-import org.locationtech.spatial4j.shape.Shape;
import org.apache.lucene.index.IndexReaderContext;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.NumberRangePrefixTree;
import org.apache.lucene.util.Bits;
+import org.locationtech.spatial4j.shape.Point;
+import org.locationtech.spatial4j.shape.Shape;
import static org.apache.lucene.spatial.prefix.tree.NumberRangePrefixTree.UnitNRShape;
@@ -57,9 +56,22 @@
}
@Override
- protected Iterator<Cell> createCellIteratorToIndex(Shape shape, int detailLevel, Iterator<Cell> reuse) {
- //levels doesn't actually matter; NumberRange based Shapes have their own "level".
- return super.createCellIteratorToIndex(shape, grid.getMaxLevels(), reuse);
+ protected boolean isPointShape(Shape shape) {
+ if (shape instanceof NumberRangePrefixTree.UnitNRShape) {
+ return ((NumberRangePrefixTree.UnitNRShape)shape).getLevel() == grid.getMaxLevels();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected boolean isGridAlignedShape(Shape shape) {
+ // any UnitNRShape other than the world is a single cell/term
+ if (shape instanceof NumberRangePrefixTree.UnitNRShape) {
+ return ((NumberRangePrefixTree.UnitNRShape)shape).getLevel() > 0;
+ } else {
+ return false;
+ }
}
/** Unsupported. */
Index: lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/DateNRStrategyTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/DateNRStrategyTest.java (revision 0aea8cbc72859f49edabc410a1061911362592be)
+++ lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/DateNRStrategyTest.java (revision )
@@ -27,7 +27,7 @@
import org.junit.Test;
import org.locationtech.spatial4j.shape.Shape;
-import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean;
+import static com.carrotsearch.randomizedtesting.RandomizedTest.randomInt;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomIntBetween;
public class DateNRStrategyTest extends RandomSpatialOpStrategyTestCase {
@@ -42,17 +42,8 @@
public void setUp() throws Exception {
super.setUp();
tree = DateRangePrefixTree.INSTANCE;
- if (randomBoolean()) {
- strategy = new NumberRangePrefixTreeStrategy(tree, "dateRange");
- } else {
- //Test the format that existed <= Lucene 5.0
- strategy = new NumberRangePrefixTreeStrategy(tree, "dateRange") {
- @Override
- protected CellToBytesRefIterator newCellToBytesRefIterator() {
- return new CellToBytesRefIterator50();
- }
- };
- }
+ strategy = new NumberRangePrefixTreeStrategy(tree, "dateRange");
+ ((NumberRangePrefixTreeStrategy)strategy).setPointsOnly(randomInt() % 5 == 0);
Calendar tmpCal = tree.newCal();
int randomCalWindowField = randomIntBetween(Calendar.YEAR, Calendar.MILLISECOND);
tmpCal.add(randomCalWindowField, 2_000);
@@ -79,15 +70,16 @@
@Test
public void testWithinSame() throws IOException {
- final Calendar cal = tree.newCal();
+ Shape shape = randomIndexedShape();
testOperation(
- tree.toShape(cal),
+ shape,
SpatialOperation.IsWithin,
- tree.toShape(cal), true);//is within itself
+ shape, true);//is within itself
}
@Test
public void testWorld() throws IOException {
+ ((NumberRangePrefixTreeStrategy)strategy).setPointsOnly(false);
testOperation(
tree.toShape(tree.newCal()),//world matches everything
SpatialOperation.Contains,
@@ -96,6 +88,7 @@
@Test
public void testBugInitIterOptimization() throws Exception {
+ ((NumberRangePrefixTreeStrategy)strategy).setPointsOnly(false);
//bug due to fast path initIter() optimization
testOperation(
tree.parseShape("[2014-03-27T23 TO 2014-04-01T01]"),
@@ -114,6 +107,21 @@
@Override
protected Shape randomIndexedShape() {
+ if (((NumberRangePrefixTreeStrategy)strategy).isPointsOnly()) {
+ Calendar cal = tree.newCal();
+ cal.setTimeInMillis(random().nextLong());
+ return tree.toShape(cal);
+ } else {
+ return randomShape();
+ }
+ }
+
+ @Override
+ protected Shape randomQueryShape() {
+ return randomShape();
+ }
+
+ private Shape randomShape() {
Calendar cal1 = randomCalendar();
UnitNRShape s1 = tree.toShape(cal1);
if (rarely()) {
@@ -144,9 +152,4 @@
}
return cal;
}
-
- @Override
- protected Shape randomQueryShape() {
- return randomIndexedShape();
- }
}