You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2013/07/26 21:37:14 UTC

svn commit: r1507409 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/search/function/distance/ core/src/test-files/solr/collection1/conf/ core/src/test/org/apache/solr/search/function/distance/

Author: dsmiley
Date: Fri Jul 26 19:37:14 2013
New Revision: 1507409

URL: http://svn.apache.org/r1507409
Log:
SOLR-2345: geodist support for RPT

Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java
    lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema12.xml
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1507409&r1=1507408&r2=1507409&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Fri Jul 26 19:37:14 2013
@@ -64,13 +64,20 @@ Upgrading from Solr 4.4.0
 Detailed Change List
 ----------------------
 
+New Features
+----------------------
+
+* SOLR-2345: Enhanced geodist() to work with an RPT field, provided that the
+  field is referenced via 'sfield' and the query point is constant.
+  (David Smiley)
+
 Bug Fixes
 ----------------------
 
-* SOLR-3633 - web UI reports an error if CoreAdminHandler says there are no 
+* SOLR-3633: web UI reports an error if CoreAdminHandler says there are no
   SolrCores (steffkes)
   
-* SOLR-4489 - SpellCheckComponent can throw StringIndexOutOfBoundsException
+* SOLR-4489: SpellCheckComponent can throw StringIndexOutOfBoundsException
   when generating collations involving multiple word-break corrections.
   (James Dyer)
 

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java?rev=1507409&r1=1507408&r2=1507409&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java Fri Jul 26 19:37:14 2013
@@ -20,28 +20,37 @@ package org.apache.solr.search.function.
 import com.spatial4j.core.distance.DistanceUtils;
 import com.spatial4j.core.exception.InvalidShapeException;
 import com.spatial4j.core.io.ParseUtils;
+import com.spatial4j.core.shape.Point;
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.queries.function.valuesource.ConstNumberSource;
 import org.apache.lucene.queries.function.valuesource.DoubleConstValueSource;
 import org.apache.lucene.queries.function.valuesource.MultiValueSource;
 import org.apache.lucene.queries.function.valuesource.VectorValueSource;
+import org.apache.lucene.spatial.SpatialStrategy;
 import org.apache.solr.common.params.SpatialParams;
+import org.apache.solr.schema.AbstractSpatialFieldType;
+import org.apache.solr.schema.FieldType;
 import org.apache.solr.schema.SchemaField;
 import org.apache.solr.search.FunctionQParser;
 import org.apache.solr.search.SyntaxError;
 import org.apache.solr.search.ValueSourceParser;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
- * Parses "geodist" creating {@link HaversineConstFunction} or {@link HaversineFunction}.
+ * Parses "geodist" creating {@link HaversineConstFunction} or {@link HaversineFunction}
+ * or calling {@link SpatialStrategy#makeDistanceValueSource(com.spatial4j.core.shape.Point,double)}.
  */
 public class GeoDistValueSourceParser extends ValueSourceParser {
 
   @Override
   public ValueSource parse(FunctionQParser fp) throws SyntaxError {
     // TODO: dispatch through SpatialQueryable in the future?
+
+    //note: parseValueSourceList can't handle a field reference to an AbstractSpatialFieldType,
+    // so those fields are expressly handled via sfield=
     List<ValueSource> sources = fp.parseValueSourceList();
 
     // "m" is a multi-value source, "x" is a single-value source
@@ -104,7 +113,7 @@ public class GeoDistValueSourceParser ex
     }
 
     // We have all the parameters at this point, now check if one of the points is constant
-    double[] constants;
+    double[] constants;//latLon
     constants = getConstants(mv1);
     MultiValueSource other = mv2;
     if (constants == null) {
@@ -112,6 +121,24 @@ public class GeoDistValueSourceParser ex
       other = mv1;
     }
 
+    // At this point we dispatch to one of:
+    // * SpatialStrategy.makeDistanceValueSource
+    // * HaversineConstFunction
+    // * HaversineFunction
+
+    // sfield can only be in mv2, according to the logic above
+    if (mv2 instanceof SpatialStrategyMultiValueSource) {
+      if (constants == null)
+        throw new SyntaxError("When using AbstractSpatialFieldType (e.g. RPT not LatLonType)," +
+            " the point must be supplied as constants");
+      // note: uses Haversine by default but can be changed via distCalc=...
+      SpatialStrategy strategy = ((SpatialStrategyMultiValueSource) mv2).strategy;
+      Point queryPoint = strategy.getSpatialContext().makePoint(constants[1], constants[0]);
+      //TODO Spatial4j 0.4 will have a direct constant
+      double multiplier = DistanceUtils.degrees2Dist(1, DistanceUtils.EARTH_MEAN_RADIUS_KM);
+      return strategy.makeDistanceValueSource(queryPoint, multiplier);
+    }
+
     if (constants != null && other instanceof VectorValueSource) {
       return new HaversineConstFunction(constants[0], constants[1], (VectorValueSource)other);
     }
@@ -155,11 +182,33 @@ public class GeoDistValueSourceParser ex
     String sfield = fp.getParam(SpatialParams.FIELD);
     if (sfield == null) return null;
     SchemaField sf = fp.getReq().getSchema().getField(sfield);
-    ValueSource vs = sf.getType().getValueSource(sf, fp);
-    if (!(vs instanceof MultiValueSource)) {
-      throw new SyntaxError("Spatial field must implement MultiValueSource:" + sf);
+    FieldType type = sf.getType();
+    if (type instanceof AbstractSpatialFieldType) {
+      AbstractSpatialFieldType asft = (AbstractSpatialFieldType) type;
+      return new SpatialStrategyMultiValueSource(asft.getStrategy(sfield));
+    }
+    ValueSource vs = type.getValueSource(sf, fp);
+    if (vs instanceof MultiValueSource) {
+      return (MultiValueSource)vs;
+    }
+    throw new SyntaxError("Spatial field must implement MultiValueSource or extend AbstractSpatialFieldType:" + sf);
+  }
+
+  /** An unfortunate hack to use a {@link SpatialStrategy} instead of
+   * a ValueSource. */
+  private static class SpatialStrategyMultiValueSource extends VectorValueSource {
+
+    final SpatialStrategy strategy;
+
+    public SpatialStrategyMultiValueSource(SpatialStrategy strategy) {
+      super(Collections.EMPTY_LIST);
+      this.strategy = strategy;
+    }
+
+    @Override
+    public List<ValueSource> getSources() {
+      throw new IllegalStateException();
     }
-    return (MultiValueSource)vs;
   }
 
 }

Modified: lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema12.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema12.xml?rev=1507409&r1=1507408&r2=1507409&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema12.xml (original)
+++ lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema12.xml Fri Jul 26 19:37:14 2013
@@ -420,6 +420,9 @@
    <fieldType name="point" class="solr.PointType" dimension="2" subFieldSuffix="_d"/>
     <!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. -->
     <fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>
+    <!-- sub-centimeter accuracy for RPT; distance calcs -->
+    <fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
+      geo="true" distErrPct="0.025" maxDistErr="0.00000009" units="degrees" />
 
   <fieldType name="currency" class="solr.CurrencyField" currencyConfig="currency.xml" multiValued="false" />
  </types>
@@ -517,6 +520,7 @@
    <field name="pointD" type="xyd" indexed="true" stored="true" multiValued="false"/>
    <field name="point_hash" type="geohash" indexed="true" stored="true" multiValued="false"/>
    <field name="store" type="location" indexed="true" stored="true"/>
+   <field name="store_rpt" type="location_rpt" indexed="true" stored="false" />
    
    <!-- Test currency field -->
    <field name="amount_c" type="currency" indexed="true" stored="true" multiValued="false"/>
@@ -609,5 +613,6 @@
    <copyField source="subject" dest="text"/>
 
    <copyField source="foo_copysource_*" dest="bar_copydest_*" />
+   <copyField source="store" dest="store_rpt" />
  
 </schema>

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java?rev=1507409&r1=1507408&r2=1507409&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java Fri Jul 26 19:37:14 2013
@@ -76,7 +76,7 @@ public class DistanceFunctionTest extend
 
   @Test
   public void testLatLon() throws Exception {
-    assertU(adoc("id", "100", "store", "1,2"));
+    assertU(adoc("id", "100", "store", "1,2"));//copied to store_rpt
     assertU(commit());
    
     assertJQ(req("defType","func", 
@@ -126,6 +126,16 @@ public class DistanceFunctionTest extend
              , 1e-5
              ,"/response/docs/[0]/score==314.40338"
              );
+
+    // if pt missing, use sfield (RPT)
+    assertJQ(req("defType","func",
+        "q","geodist(3,4)",
+        "sfield","store_rpt",
+        "fq","id:100",
+        "fl","id,score")
+        , 1e-5
+        ,"/response/docs/[0]/score==314.40338"
+    );
     
     // read both pt and sfield
     assertJQ(req("defType","func", 
@@ -137,6 +147,16 @@ public class DistanceFunctionTest extend
              ,"/response/docs/[0]/score==314.40338"
              );
 
+    // read both pt and sfield (RPT)
+    assertJQ(req("defType","func",
+        "q","geodist()","pt","3,4",
+        "sfield","store_rpt",
+        "fq","id:100",
+        "fl","id,score")
+        , 1e-5
+        ,"/response/docs/[0]/score==314.40338"
+    );
+
     // param substitution
     assertJQ(req("defType","func", 
                  "q","geodist($a,$b)",