Index: lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java (revision 1384483)
+++ lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java (revision )
@@ -20,6 +20,7 @@
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.io.ShapeReadWriter;
+import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Shape;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
@@ -45,7 +46,6 @@
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.util.Version;
import java.io.IOException;
@@ -75,8 +75,9 @@
/**
* The Lucene spatial {@link SpatialStrategy} encapsulates an approach to
- * indexing and searching shapes, and providing relevancy scores for them.
- * It's a simple API to unify different approaches.
+ * indexing and searching shapes, and providing distance values for them.
+ * It's a simple API to unify different approaches. You might use more than
+ * one strategy for a shape as each strategy has its strengths and weaknesses.
*
* Note that these are initialized with a field name.
*/
@@ -85,13 +86,13 @@
private Directory directory;
protected void init() {
- //Typical geospatial context with kilometer units.
- // These can also be constructed from a factory: SpatialContextFactory
+ //Typical geospatial context
+ // These can also be constructed from SpatialContextFactory
this.ctx = SpatialContext.GEO;
- int maxLevels = 10;//results in sub-meter precision for geohash
+ int maxLevels = 11;//results in sub-meter precision for geohash
//TODO demo lookup by detail distance
- // This can also be constructed from a factory: SpatialPrefixTreeFactory
+ // This can also be constructed from SpatialPrefixTreeFactory
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels);
this.strategy = new RecursivePrefixTreeStrategy(grid, "myGeoField");
@@ -151,9 +152,8 @@
}
//--Match all, order by distance
{
- SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects,//doesn't matter
- ctx.makePoint(60, -50));
- ValueSource valueSource = strategy.makeValueSource(args);//the distance (in degrees)
+ Point pt = ctx.makePoint(60, -50);
+ ValueSource valueSource = strategy.makeDistanceValueSource(pt);//the distance (in degrees)
Sort reverseDistSort = new Sort(valueSource.getSortField(false)).rewrite(indexSearcher);//true=asc dist
TopDocs docs = indexSearcher.search(new MatchAllDocsQuery(), 10, reverseDistSort);
assertDocMatchedIds(indexSearcher, docs, 4, 20, 2);
Index: lucene/spatial/src/test/org/apache/lucene/spatial/vector/TestTwoDoublesStrategy.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial/src/test/org/apache/lucene/spatial/vector/TestTwoDoublesStrategy.java (revision 1384483)
+++ lucene/spatial/src/test/org/apache/lucene/spatial/vector/TestTwoDoublesStrategy.java (revision )
@@ -27,6 +27,7 @@
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
@@ -41,7 +42,7 @@
this.strategy = new TwoDoublesStrategy(ctx, getClass().getSimpleName());
}
- @Test
+ @Test @Ignore
public void testCircleShapeSupport() {
Circle circle = ctx.makeCircle(ctx.makePoint(0, 0), 10);
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle);
Index: lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java (revision 1384483)
+++ lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java (revision )
@@ -18,13 +18,15 @@
*/
import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.Rectangle;
import com.spatial4j.core.shape.Shape;
import org.apache.lucene.document.Field;
-import org.apache.lucene.queries.function.FunctionQuery;
import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.valuesource.ReciprocalFloatFunction;
+import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Filter;
-import org.apache.lucene.search.FilteredQuery;
-import org.apache.lucene.search.Query;
+import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.spatial.query.SpatialArgs;
/**
@@ -50,6 +52,11 @@
* values of shapes, which is immaterial to indexing & search.
*
* Thread-safe.
+ *
+ * Implementation note: subclasses must override at least one of
+ * {@link #makeFilter(org.apache.lucene.spatial.query.SpatialArgs)} or
+ * {@link #makeQuery(org.apache.lucene.spatial.query.SpatialArgs)} since
+ * the default implementations of each call the other.
*
* @lucene.experimental
*/
@@ -99,25 +106,47 @@
public abstract Field[] createIndexableFields(Shape shape);
/**
- * The value source yields a number that is proportional to the distance between the query shape and indexed data.
+ * Make a ValueSource returning the closest distance between the center of the
+ * indexed shape and {@code queryPoint}.
+ * @param queryPoint
*/
- public abstract ValueSource makeValueSource(SpatialArgs args);
+ public abstract ValueSource makeDistanceValueSource(Point queryPoint);
/**
- * Make a query which has a score based on the distance from the data to the query shape.
- * The default implementation constructs a {@link FilteredQuery} based on
- * {@link #makeFilter(org.apache.lucene.spatial.query.SpatialArgs)} and
- * {@link #makeValueSource(org.apache.lucene.spatial.query.SpatialArgs)}.
+ * Make a (ConstantScore) Query based principally on {@link org.apache.lucene.spatial.query.SpatialOperation}
+ * and {@link Shape} from the supplied {@code args}.
+ * The default implementation is
+ *
return new ConstantScoreQuery(makeFilter(args));
*/
- public Query makeQuery(SpatialArgs args) {
- Filter filter = makeFilter(args);
- ValueSource vs = makeValueSource(args);
- return new FilteredQuery(new FunctionQuery(vs), filter);
+ public ConstantScoreQuery makeQuery(SpatialArgs args) {
+ return new ConstantScoreQuery(makeFilter(args));
}
+
/**
- * Make a Filter
+ * Make a Filter based principally on {@link org.apache.lucene.spatial.query.SpatialOperation}
+ * and {@link Shape} from the supplied {@code args}.
+ * The default implementation is
+ *
return new QueryWrapperFilter(makeQuery(args).getQuery());
*/
- public abstract Filter makeFilter(SpatialArgs args);
+ public Filter makeFilter(SpatialArgs args) {
+ return new QueryWrapperFilter(makeQuery(args).getQuery());
+ }
+
+ /**
+ * Returns a ValueSource useful as a score. It is c/(d + c) where 'd' is the
+ * distance retrieved from {@link #makeDistanceValueSource(com.spatial4j.core.shape.Point)}
+ * and 'c' is one tenth the distance to the farthest edge from the center.
+ * Thus the scores will be as high as 1 for matching points in the center of
+ * the query shape and as low as ~0.1 at its furthest edges.
+ */
+ public final ValueSource makeRecipDistanceValueSource(Shape queryShape) {
+ Rectangle bbox = queryShape.getBoundingBox();
+ double diagonalDist = ctx.getDistCalc().distance(
+ ctx.makePoint(bbox.getMinX(), bbox.getMinY()), bbox.getMaxX(), bbox.getMaxY());
+ double distToEdge = diagonalDist * 0.5;
+ float c = (float)distToEdge * 0.1f;//one tenth
+ return new ReciprocalFloatFunction(makeDistanceValueSource(queryShape.getCenter()), 1f, c, c);
+ }
@Override
public String toString() {
Index: lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java (revision )
+++ lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java (revision )
@@ -0,0 +1,129 @@
+package org.apache.lucene.spatial;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.carrotsearch.randomizedtesting.annotations.Name;
+import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.Shape;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.spatial.bbox.BBoxStrategy;
+import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
+import org.apache.lucene.spatial.prefix.TermQueryPrefixTreeStrategy;
+import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
+import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
+import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
+import org.apache.lucene.spatial.vector.TwoDoublesStrategy;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author David Smiley - dsmiley@mitre.org
+ */
+public class DistanceStrategyTest extends StrategyTestCase {
+
+ @ParametersFactory
+ public static Iterable