diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java
index c5eb5904252..c7b7253fbce 100644
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java
+++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java
@@ -17,6 +17,9 @@ package org.apache.lucene.spatial.util;
* limitations under the License.
*/
+import java.io.IOException;
+import java.util.Map;
+
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.shape.Shape;
import org.apache.lucene.index.LeafReaderContext;
@@ -26,9 +29,6 @@ import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.IndexSearcher;
-import java.io.IOException;
-import java.util.Map;
-
/**
* The area of a Shape retrieved from a ValueSource via
* {@link org.apache.lucene.queries.function.FunctionValues#objectVal(int)}.
@@ -41,11 +41,13 @@ public class ShapeAreaValueSource extends ValueSource {
private final ValueSource shapeValueSource;
private final SpatialContext ctx;//not part of identity; should be associated with shapeValueSource indirectly
private final boolean geoArea;
+ private double multiplier;
- public ShapeAreaValueSource(ValueSource shapeValueSource, SpatialContext ctx, boolean geoArea) {
+ public ShapeAreaValueSource(ValueSource shapeValueSource, SpatialContext ctx, boolean geoArea, double multiplier) {
this.shapeValueSource = shapeValueSource;
this.ctx = ctx;
this.geoArea = geoArea;
+ this.multiplier = multiplier;
}
@Override
@@ -70,7 +72,7 @@ public class ShapeAreaValueSource extends ValueSource {
return 0;//or NaN?
//This part of Spatial4j API is kinda weird. Passing null means 2D area, otherwise geo
// assuming ctx.isGeo()
- return shape.getArea( geoArea ? ctx : null );
+ return shape.getArea( geoArea ? ctx : null ) * multiplier;
}
@Override
diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/bbox/TestBBoxStrategy.java b/lucene/spatial/src/test/org/apache/lucene/spatial/bbox/TestBBoxStrategy.java
index b708b5cd0d5..1a189f71a1c 100644
--- a/lucene/spatial/src/test/org/apache/lucene/spatial/bbox/TestBBoxStrategy.java
+++ b/lucene/spatial/src/test/org/apache/lucene/spatial/bbox/TestBBoxStrategy.java
@@ -19,6 +19,13 @@ package org.apache.lucene.spatial.bbox;
import java.io.IOException;
+import com.carrotsearch.randomizedtesting.annotations.Repeat;
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.context.SpatialContextFactory;
+import com.spatial4j.core.distance.DistanceUtils;
+import com.spatial4j.core.shape.Rectangle;
+import com.spatial4j.core.shape.Shape;
+import com.spatial4j.core.shape.impl.RectangleImpl;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexOptions;
@@ -30,13 +37,6 @@ import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.lucene.spatial.util.ShapeAreaValueSource;
import org.junit.Ignore;
import org.junit.Test;
-import com.carrotsearch.randomizedtesting.annotations.Repeat;
-import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.context.SpatialContextFactory;
-import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.shape.Rectangle;
-import com.spatial4j.core.shape.Shape;
-import com.spatial4j.core.shape.impl.RectangleImpl;
public class TestBBoxStrategy extends RandomSpatialOpStrategyTestCase {
@@ -301,9 +301,11 @@ public class TestBBoxStrategy extends RandomSpatialOpStrategyTestCase {
adoc("100", ctx.makeRectangle(0, 20, 40, 80));
adoc("999", (Shape) null);
commit();
- checkValueSource(new ShapeAreaValueSource(bboxStrategy.makeShapeValueSource(), ctx, false),
+ checkValueSource(new ShapeAreaValueSource(bboxStrategy.makeShapeValueSource(), ctx, false, 1.0),
new float[]{800f, 0f}, 0f);
- checkValueSource(new ShapeAreaValueSource(bboxStrategy.makeShapeValueSource(), ctx, true),//geo
+ checkValueSource(new ShapeAreaValueSource(bboxStrategy.makeShapeValueSource(), ctx, true, 1.0),//geo
new float[]{391.93f, 0f}, 0.01f);
+ checkValueSource(new ShapeAreaValueSource(bboxStrategy.makeShapeValueSource(), ctx, true, 2.0),
+ new float[]{783.86f, 0f}, 0.01f); // testing with a different multiplier
}
}
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index f0b83783796..57b267c760d 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -138,6 +138,13 @@ Upgrading from Solr 4.x
* SolrServer and associated classes have been deprecated. Applications using
SolrJ should use the equivalent SolrClient classes instead.
+* Spatial fields originating from Solr 4 (e.g. SpatialRecursivePrefixTreeFieldType, BBoxField)
+ have the 'units' attribute deprecated, now replaced with 'distanceUnits'. If you change it to
+ a unit other than 'degrees' (or if you don't specify it, which will default to kilometers if
+ geo=true), then be sure to update maxDistErr as it's in those units. If you keep units=degrees
+ then it should be backwards compatible but you'll get a deprecation warning on startup. See
+ SOLR-6797.
+
Detailed Change List
----------------------
@@ -271,6 +278,12 @@ New Features
* SOLR-6761: Ability to ignore commit and/or optimize requests from clients when running in
SolrCloud mode using the IgnoreCommitOptimizeUpdateProcessorFactory. (Timothy Potter)
+* SOLR-6797: Spatial fields that used to require units=degrees like
+ SpatialRecursivePrefixTreeFieldType (RPT) now take distanceUnits=degrees|kilometers|miles
+ instead. It is applied to nearly all distance measurements involving the field: maxDistErr,
+ distErr, d, geodist, score=distance|area|area2d. score now accepts these units as well. It does
+ NOT affect distances embedded in WKT strings like BUFFER(POINT(200 10),0.2)).
+ (Ishan Chattopadhyaya, David Smiley)
Bug Fixes
----------------------
diff --git a/solr/contrib/morphlines-core/src/test-files/solr/minimr/conf/schema.xml b/solr/contrib/morphlines-core/src/test-files/solr/minimr/conf/schema.xml
index aa7fe8f7312..5a865e1a470 100644
--- a/solr/contrib/morphlines-core/src/test-files/solr/minimr/conf/schema.xml
+++ b/solr/contrib/morphlines-core/src/test-files/solr/minimr/conf/schema.xml
@@ -579,7 +579,7 @@
http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4
-->
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.00001" distanceUnits="kilometers" />
diff --git a/solr/core/src/test/org/apache/solr/schema/SpatialRPTFieldTypeTest.java b/solr/core/src/test/org/apache/solr/schema/SpatialRPTFieldTypeTest.java
new file mode 100644
index 00000000000..07a6f8f7bd4
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/schema/SpatialRPTFieldTypeTest.java
@@ -0,0 +1,275 @@
+package org.apache.solr.schema;
+/*
+ * 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 java.io.File;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.solr.core.AbstractBadConfigTestBase;
+import org.junit.After;
+import org.junit.Before;
+
+public class SpatialRPTFieldTypeTest extends AbstractBadConfigTestBase {
+
+ private static File tmpSolrHome;
+ private static File tmpConfDir;
+
+ private static final String collection = "collection1";
+ private static final String confDir = collection + "/conf";
+
+ @Before
+ private void initManagedSchemaCore() throws Exception {
+ tmpSolrHome = createTempDir().toFile();
+ tmpConfDir = new File(tmpSolrHome, confDir);
+ File testHomeConfDir = new File(TEST_HOME(), confDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "solrconfig-managed-schema.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "solrconfig-basic.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "solrconfig.snippet.randomindexconfig.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "schema-one-field-no-dynamic-field.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "schema-one-field-no-dynamic-field-unique-key.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "schema-minimal.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "schema_codec.xml"), tmpConfDir);
+ FileUtils.copyFileToDirectory(new File(testHomeConfDir, "schema-bm25.xml"), tmpConfDir);
+
+ // initCore will trigger an upgrade to managed schema, since the solrconfig has
+ //
+ System.setProperty("managed.schema.mutable", "false");
+ System.setProperty("enable.update.log", "false");
+ initCore("solrconfig-managed-schema.xml", "schema-minimal.xml", tmpSolrHome.getPath());
+ }
+
+ @After
+ private void afterClass() throws Exception {
+ deleteCore();
+ System.clearProperty("managed.schema.mutable");
+ System.clearProperty("enable.update.log");
+ }
+
+ final String INDEXED_COORDINATES = "25,82";
+ final String QUERY_COORDINATES = "24,81";
+ final String DISTANCE_DEGREES = "1.3520328";
+ final String DISTANCE_KILOMETERS = "150.33939";
+ final String DISTANCE_MILES = "93.416565";
+
+ public void testUnitsDegrees() throws Exception { // test back compat behaviour
+ setupRPTField("degrees", null, "true");
+
+ assertU(adoc("str", "X", "geo", INDEXED_COORDINATES));
+ assertU(commit());
+ String q;
+
+ q = "geo:{!geofilt score=distance filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_DEGREES+"']");
+
+ q = "geo:{!geofilt score=degrees filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_DEGREES+"']");
+
+ q = "geo:{!geofilt score=kilometers filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_KILOMETERS+"']");
+
+ q = "geo:{!geofilt score=miles filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_MILES+"']");
+ }
+
+ public void testUnitsNonDegrees() throws Exception {
+ try {
+ setupRPTField("kilometers", null, "true");
+ fail("Expected exception for deprecated units parameter.");
+ } catch (Exception ex) {
+ if(!ex.getMessage().startsWith("units parameter is deprecated"))
+ throw ex;
+ }
+ }
+
+ public void testDistanceUnitsDegrees() throws Exception {
+ setupRPTField(null, "degrees", "true");
+
+ assertU(adoc("str", "X", "geo", INDEXED_COORDINATES));
+ assertU(commit());
+ String q;
+
+ q = "geo:{!geofilt score=distance filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_DEGREES+"']");
+
+ q = "geo:{!geofilt score=degrees filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_DEGREES+"']");
+
+ q = "geo:{!geofilt score=kilometers filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_KILOMETERS+"']");
+
+ q = "geo:{!geofilt score=miles filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_MILES+"']");
+ }
+
+ public void testDistanceUnitsKilometers() throws Exception {
+ setupRPTField(null, "kilometers", "true");
+
+ assertU(adoc("str", "X", "geo", INDEXED_COORDINATES));
+ assertU(commit());
+ String q;
+
+ q = "geo:{!geofilt score=distance filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_KILOMETERS+"']");
+
+ q = "geo:{!geofilt score=degrees filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_DEGREES+"']");
+
+ q = "geo:{!geofilt score=kilometers filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_KILOMETERS+"']");
+
+ q = "geo:{!geofilt score=miles filter=false sfield=geo pt="+QUERY_COORDINATES+" d=1000}";
+ assertQ(req("q", q, "fl", "*,score"), "//result/doc/float[@name='score'][.='"+DISTANCE_MILES+"']");
+ }
+
+ public void testBothUnitsAndDistanceUnits() throws Exception { // distanceUnits should take precedence
+ try {
+ setupRPTField("degrees", "kilometers", "true");
+ fail("Expected exception for deprecated units parameter.");
+ } catch (Exception ex) {
+ if(!ex.getMessage().startsWith("units parameter is deprecated"))
+ throw ex;
+ }
+ }
+
+ public void testJunkValuesForDistanceUnits() throws Exception {
+ try {
+ setupRPTField(null, "rose", "true");
+ fail("Expected exception for bad value of distanceUnits.");
+ } catch (Exception ex) {
+ if(!ex.getMessage().startsWith("Must specify distanceUnits as one of"))
+ throw ex;
+ }
+ }
+
+ public void testMaxDistErrConversion() throws Exception {
+ deleteCore();
+ File managedSchemaFile = new File(tmpConfDir, "managed-schema");
+ Files.delete(managedSchemaFile.toPath()); // Delete managed-schema so it won't block parsing a new schema
+ System.setProperty("managed.schema.mutable", "true");
+ initCore("solrconfig-managed-schema.xml", "schema-one-field-no-dynamic-field.xml", tmpSolrHome.getPath());
+
+ String fieldName = "new_text_field";
+ assertNull("Field '" + fieldName + "' is present in the schema",
+ h.getCore().getLatestSchema().getFieldOrNull(fieldName));
+
+ IndexSchema oldSchema = h.getCore().getLatestSchema();
+
+ SpatialRecursivePrefixTreeFieldType rptFieldType = new SpatialRecursivePrefixTreeFieldType();
+ Map rptMap = new HashMap();
+
+ rptFieldType.setTypeName("location_rpt");
+ rptMap.put("geo", "true");
+
+ // test km
+ rptMap.put("distanceUnits", "kilometers");
+ rptMap.put("maxDistErr", "0.001"); // 1 meter
+ rptFieldType.init(oldSchema, rptMap);
+ assertEquals(11, rptFieldType.grid.getMaxLevels());
+
+ // test miles
+ rptMap.put("distanceUnits", "miles");
+ rptMap.put("maxDistErr", "0.001");
+ rptFieldType.init(oldSchema, rptMap);
+ assertEquals(10, rptFieldType.grid.getMaxLevels());
+
+ // test degrees
+ rptMap.put("distanceUnits", "degrees");
+ rptMap.put("maxDistErr", "0.001");
+ rptFieldType.init(oldSchema, rptMap);
+ assertEquals(8, rptFieldType.grid.getMaxLevels());
+ }
+
+ public void testGeoDistanceFunctionWithBackCompat() throws Exception {
+ setupRPTField("degrees", null, "true");
+
+ assertU(adoc("str", "X", "geo", "1,2"));
+ assertU(commit());
+
+ // geodist() should return in km
+ assertJQ(req("defType","func",
+ "q","geodist(3,4)",
+ "sfield","geo",
+ "fl","score")
+ , 1e-5
+ ,"/response/docs/[0]/score==314.4033"
+ );
+ }
+
+ public void testGeoDistanceFunctionWithKilometers() throws Exception {
+ setupRPTField(null, "kilometers", "true");
+
+ assertU(adoc("str", "X", "geo", "1,2"));
+ assertU(commit());
+
+ assertJQ(req("defType","func",
+ "q","geodist(3,4)",
+ "sfield","geo",
+ "fl","score")
+ , 1e-5
+ ,"/response/docs/[0]/score==314.4033"
+ );
+ }
+
+ public void testGeoDistanceFunctionWithMiles() throws Exception {
+ setupRPTField(null, "miles", "true");
+
+ assertU(adoc("str", "X", "geo", "1,2"));
+ assertU(commit());
+
+ assertJQ(req("defType","func",
+ "q","geodist(3,4)",
+ "sfield","geo",
+ "fl","score")
+ , 1e-5
+ ,"/response/docs/[0]/score==195.36115"
+ );
+ }
+
+ private void setupRPTField(String units, String distanceUnits, String geo) throws Exception {
+ deleteCore();
+ File managedSchemaFile = new File(tmpConfDir, "managed-schema");
+ Files.delete(managedSchemaFile.toPath()); // Delete managed-schema so it won't block parsing a new schema
+ System.setProperty("managed.schema.mutable", "true");
+ initCore("solrconfig-managed-schema.xml", "schema-one-field-no-dynamic-field.xml", tmpSolrHome.getPath());
+
+ String fieldName = "new_text_field";
+ assertNull("Field '" + fieldName + "' is present in the schema",
+ h.getCore().getLatestSchema().getFieldOrNull(fieldName));
+
+ IndexSchema oldSchema = h.getCore().getLatestSchema();
+
+ SpatialRecursivePrefixTreeFieldType rptFieldType = new SpatialRecursivePrefixTreeFieldType();
+ Map rptMap = new HashMap();
+ if(units!=null)
+ rptMap.put("units", units);
+ if(distanceUnits!=null)
+ rptMap.put("distanceUnits", distanceUnits);
+ if(geo!=null)
+ rptMap.put("geo", geo);
+ rptFieldType.init(oldSchema, rptMap);
+ rptFieldType.setTypeName("location_rpt");
+ SchemaField newField = new SchemaField("geo", rptFieldType, SchemaField.STORED | SchemaField.INDEXED, null);
+ IndexSchema newSchema = oldSchema.addField(newField);
+
+ h.getCore().setLatestSchema(newSchema);
+
+ assertU(delQ("*:*"));
+ }
+}
diff --git a/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java b/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
index 12c57254a19..690ad742d21 100644
--- a/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
+++ b/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
@@ -17,6 +17,9 @@ package org.apache.solr.search;
* limitations under the License.
*/
+import java.text.ParseException;
+import java.util.Arrays;
+
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import com.spatial4j.core.context.SpatialContext;
@@ -33,9 +36,6 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import java.text.ParseException;
-import java.util.Arrays;
-
/**
* Test Solr 4's new spatial capabilities from the new Lucene spatial module. Don't thoroughly test it here because
* Lucene spatial has its own tests. Some of these tests were ported from Solr 3 spatial tests.
@@ -110,19 +110,20 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
@Test
public void testIntersectFilter() throws Exception {
setupDocs();
+
//Try some edge cases
- checkHits(fieldName, "1,1", 175, 3, 5, 6, 7);
- checkHits(fieldName, "0,179.8", 200, 2, 8, 9);
- checkHits(fieldName, "89.8, 50", 200, 2, 10, 11);//this goes over the north pole
- checkHits(fieldName, "-89.8, 50", 200, 2, 12, 13);//this goes over the south pole
+ checkHits(fieldName, "1,1", 175, DistanceUtils.EARTH_MEAN_RADIUS_KM, 3, 5, 6, 7);
+ checkHits(fieldName, "0,179.8", 200, DistanceUtils.EARTH_MEAN_RADIUS_KM, 2, 8, 9);
+ checkHits(fieldName, "89.8, 50", 200, DistanceUtils.EARTH_MEAN_RADIUS_KM, 2, 10, 11);//this goes over the north pole
+ checkHits(fieldName, "-89.8, 50", 200, DistanceUtils.EARTH_MEAN_RADIUS_KM, 2, 12, 13);//this goes over the south pole
//try some normal cases
- checkHits(fieldName, "33.0,-80.0", 300, 2);
+ checkHits(fieldName, "33.0,-80.0", 300, DistanceUtils.EARTH_MEAN_RADIUS_KM, 2);
//large distance
- checkHits(fieldName, "1,1", 5000, 3, 5, 6, 7);
+ checkHits(fieldName, "1,1", 5000, DistanceUtils.EARTH_MEAN_RADIUS_KM, 3, 5, 6, 7);
//Because we are generating a box based on the west/east longitudes and the south/north latitudes, which then
//translates to a range query, which is slightly more inclusive. Thus, even though 0.0 is 15.725 kms away,
//it will be included, b/c of the box calculation.
- checkHits(fieldName, false, "0.1,0.1", 15, 2, 5, 6);
+ checkHits(fieldName, false, "0.1,0.1", 15, DistanceUtils.EARTH_MEAN_RADIUS_KM, 2, 5, 6);
//try some more
clearIndex();
@@ -133,18 +134,18 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
assertU(adoc("id", "17", fieldName, "44.043900,-95.436643"));
assertU(commit());
- checkHits(fieldName, "0,0", 1000, 1, 14);
- checkHits(fieldName, "0,0", 2000, 2, 14, 15);
- checkHits(fieldName, false, "0,0", 3000, 3, 14, 15, 16);
- checkHits(fieldName, "0,0", 3001, 3, 14, 15, 16);
- checkHits(fieldName, "0,0", 3000.1, 3, 14, 15, 16);
+ checkHits(fieldName, "0,0", 1000, DistanceUtils.EARTH_MEAN_RADIUS_KM, 1, 14);
+ checkHits(fieldName, "0,0", 2000, DistanceUtils.EARTH_MEAN_RADIUS_KM, 2, 14, 15);
+ checkHits(fieldName, false, "0,0", 3000, DistanceUtils.EARTH_MEAN_RADIUS_KM, 3, 14, 15, 16);
+ checkHits(fieldName, "0,0", 3001, DistanceUtils.EARTH_MEAN_RADIUS_KM, 3, 14, 15, 16);
+ checkHits(fieldName, "0,0", 3000.1, DistanceUtils.EARTH_MEAN_RADIUS_KM, 3, 14, 15, 16);
//really fine grained distance and reflects some of the vagaries of how we are calculating the box
- checkHits(fieldName, "43.517030,-96.789603", 109, 0);
+ checkHits(fieldName, "43.517030,-96.789603", 109, DistanceUtils.EARTH_MEAN_RADIUS_KM, 0);
//falls outside of the real distance, but inside the bounding box
- checkHits(fieldName, true, "43.517030,-96.789603", 110, 0);
- checkHits(fieldName, false, "43.517030,-96.789603", 110, 1, 17);
+ checkHits(fieldName, true, "43.517030,-96.789603", 110, DistanceUtils.EARTH_MEAN_RADIUS_KM, 0);
+ checkHits(fieldName, false, "43.517030,-96.789603", 110, DistanceUtils.EARTH_MEAN_RADIUS_KM, 1, 17);
}
@Test
@@ -164,14 +165,14 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
@Test
public void checkQueryEmptyIndex() throws ParseException {
- checkHits(fieldName, "0,0", 100, 0);//doesn't error
+ checkHits(fieldName, "0,0", 100, DistanceUtils.EARTH_MEAN_RADIUS_KM, 0);//doesn't error
}
- private void checkHits(String fieldName, String pt, double distKM, int count, int ... docIds) throws ParseException {
- checkHits(fieldName, true, pt, distKM, count, docIds);
+ private void checkHits(String fieldName, String pt, double distKM, double sphereRadius, int count, int ... docIds) throws ParseException {
+ checkHits(fieldName, true, pt, distKM, sphereRadius, count, docIds);
}
- private void checkHits(String fieldName, boolean exact, String ptStr, double distKM, int count, int ... docIds) throws ParseException {
+ private void checkHits(String fieldName, boolean exact, String ptStr, double distKM, double sphereRadius, int count, int ... docIds) throws ParseException {
if (exact && fieldName.equalsIgnoreCase("bbox")) {
return; // bbox field only supports rectangular query
}
@@ -217,7 +218,7 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
{
assertQ(req(
"fl", "id", "q", "*:*", "rows", "1000",
- "fq", "{!" + (exact ? "geofilt" : "bbox") + " sfield=" + fieldName + " pt='" + ptStr + "' d=" + distKM + "}"),
+ "fq", "{!" + (exact ? "geofilt" : "bbox") + " sfield=" + fieldName + " pt='" + ptStr + "' d=" + distKM + " sphere_radius=" + sphereRadius + "}"),
tests);
}
@@ -332,7 +333,7 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
"sfield=" + fieldName + " "
+ (score != null ? "score="+score : "") + " "
+ (filter != null ? "filter="+filter : "") + " "
- + "pt=" + lat + "," + lon + " d=" + (dDEG * DistanceUtils.DEG_TO_KM) + "}";
+ + "pt=" + lat + "," + lon + " d=" + (dDEG /* DistanceUtils.DEG_TO_KM*/) + "}";
} else {
return "{! "
+ (score != null ? "score="+score : "") + " "
diff --git a/solr/core/src/test/org/apache/solr/util/DistanceUnitsTest.java b/solr/core/src/test/org/apache/solr/util/DistanceUnitsTest.java
new file mode 100644
index 00000000000..6b2b5a4d9bc
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/util/DistanceUnitsTest.java
@@ -0,0 +1,29 @@
+package org.apache.solr.util;
+
+import com.spatial4j.core.distance.DistanceUtils;
+import org.apache.lucene.util.LuceneTestCase;
+
+/*
+ * 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.
+ */
+
+public class DistanceUnitsTest extends LuceneTestCase {
+
+ public void testAddNewUnits() throws Exception {
+ DistanceUnits.addUnits("lightyears", 6.73430542e-12, 9.4605284e12 * DistanceUtils.KM_TO_DEG);
+ assertTrue(DistanceUnits.getSupportedUnits().contains("lightyears"));
+ }
+}
diff --git a/solr/example/example-DIH/solr/db/conf/schema.xml b/solr/example/example-DIH/solr/db/conf/schema.xml
index d0611fb3f1f..d407c5d0746 100755
--- a/solr/example/example-DIH/solr/db/conf/schema.xml
+++ b/solr/example/example-DIH/solr/db/conf/schema.xml
@@ -697,7 +697,7 @@
http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4
-->
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
diff --git a/solr/server/solr/configsets/basic_configs/conf/schema.xml b/solr/server/solr/configsets/basic_configs/conf/schema.xml
index c0be84efc73..f5612a530c7 100755
--- a/solr/server/solr/configsets/basic_configs/conf/schema.xml
+++ b/solr/server/solr/configsets/basic_configs/conf/schema.xml
@@ -504,7 +504,7 @@
http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4
-->
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+ geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />