lucene-solr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gsing...@apache.org
Subject svn commit: r881340 - in /lucene/solr/trunk: ./ src/common/org/apache/solr/common/params/ src/java/org/apache/solr/search/ src/java/org/apache/solr/search/function/distance/ src/test/org/apache/solr/search/function/distance/
Date Tue, 17 Nov 2009 15:36:27 GMT
Author: gsingers
Date: Tue Nov 17 15:36:25 2009
New Revision: 881340

URL: http://svn.apache.org/viewvc?rev=881340&view=rev
Log:
SOLR-1302: more distance functions and helpers

Added:
    lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashFunction.java
  (with props)
    lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java
  (with props)
Modified:
    lucene/solr/trunk/CHANGES.txt
    lucene/solr/trunk/src/common/org/apache/solr/common/params/SolrParams.java
    lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java
    lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java

Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=881340&r1=881339&r2=881340&view=diff
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Tue Nov 17 15:36:25 2009
@@ -35,7 +35,7 @@
 ----------------------
 
 1. SOLR-1302: Added several new distance based functions, including Great Circle (haversine),
Manhattan and Euclidean.
-  Also added deg() and rad() convenience functions. (gsingers)
+  Also added geohash(), deg() and rad() convenience functions. See http://wiki.apache.org/solr/FunctionQuery.
(gsingers)
 
 Optimizations
 ----------------------

Modified: lucene/solr/trunk/src/common/org/apache/solr/common/params/SolrParams.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/common/org/apache/solr/common/params/SolrParams.java?rev=881340&r1=881339&r2=881340&view=diff
==============================================================================
--- lucene/solr/trunk/src/common/org/apache/solr/common/params/SolrParams.java (original)
+++ lucene/solr/trunk/src/common/org/apache/solr/common/params/SolrParams.java Tue Nov 17
15:36:25 2009
@@ -180,6 +180,29 @@
     }
   }
 
+  /** Returns the Float value of the param, or null if not set */
+  public Double getDouble(String param) {
+    String val = get(param);
+    try {
+      return val==null ? null : Double.valueOf(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, ex.getMessage(), ex );
+    }
+  }
+
+  /** Returns the float value of the param, or def if not set */
+  public double getDouble(String param, double def) {
+    String val = get(param);
+    try {
+      return val==null ? def : Double.parseDouble(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, ex.getMessage(), ex );
+    }
+  }
+
+
   /** Returns the float value of the field param. */
   public Float getFieldFloat(String field, String param) {
     String val = getFieldParam(field, param);
@@ -202,6 +225,30 @@
       throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, ex.getMessage(), ex );
     }
   }
+
+  /** Returns the float value of the field param. */
+  public Double getFieldDouble(String field, String param) {
+    String val = getFieldParam(field, param);
+    try {
+      return val==null ? null : Double.valueOf(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, ex.getMessage(), ex );
+    }
+  }
+
+  /** Returns the float value of the field param,
+  or the value for param, or def if neither is set. */
+  public double getFieldDouble(String field, String param, double def) {
+    String val = getFieldParam(field, param);
+    try {
+      return val==null ? def : Double.parseDouble(val);
+    }
+    catch( Exception ex ) {
+      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, ex.getMessage(), ex );
+    }
+  }
+
   
   /** how to transform a String into a boolean... more flexible than
    * Boolean.parseBoolean() to enable easier integration with html forms.

Modified: lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java?rev=881340&r1=881339&r2=881340&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java Tue Nov 17 15:36:25
2009
@@ -45,11 +45,14 @@
 import org.apache.solr.search.function.SumFloatFunction;
 import org.apache.solr.search.function.TopValueSource;
 import org.apache.solr.search.function.ValueSource;
+import org.apache.solr.search.function.LiteralValueSource;
 
 import org.apache.solr.search.function.distance.HaversineFunction;
 
 import org.apache.solr.search.function.distance.SquaredEuclideanFunction;
 import org.apache.solr.search.function.distance.VectorDistanceFunction;
+import org.apache.solr.search.function.distance.GeohashHaversineFunction;
+import org.apache.solr.search.function.distance.GeohashFunction;
 import org.apache.solr.util.plugin.NamedListInitializedPlugin;
 
 import java.io.IOException;
@@ -92,6 +95,15 @@
       }
 
     });
+    standardValueSourceParsers.put("literal", new ValueSourceParser() {
+      public ValueSource parse(FunctionQParser fp) throws ParseException {
+        return new LiteralValueSource(fp.getString());
+      }
+
+      public void init(NamedList args) {
+      }
+
+    });
     standardValueSourceParsers.put("rord", new ValueSourceParser() {
       public ValueSource parse(FunctionQParser fp) throws ParseException {
         String field = fp.parseId();
@@ -333,6 +345,36 @@
 
     });
 
+    standardValueSourceParsers.put("ghhsin", new ValueSourceParser() {
+      public ValueSource parse(FunctionQParser fp) throws ParseException {
+
+        ValueSource gh1 = fp.parseValueSource();
+        ValueSource gh2 = fp.parseValueSource();
+        double radius = fp.parseDouble();
+
+        return new GeohashHaversineFunction(gh1, gh2, radius);
+      }
+
+      public void init(NamedList args) {
+      }
+
+    });
+
+    standardValueSourceParsers.put("geohash", new ValueSourceParser() {
+      public ValueSource parse(FunctionQParser fp) throws ParseException {
+
+        ValueSource lat = fp.parseValueSource();
+        ValueSource lon = fp.parseValueSource();
+
+        return new GeohashFunction(lat, lon);
+      }
+
+      public void init(NamedList args) {
+      }
+
+    });
+
+
     standardValueSourceParsers.put("rad", new ValueSourceParser() {
       public ValueSource parse(FunctionQParser fp) throws ParseException {
         return new RadianFunction(fp.parseValueSource());

Added: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashFunction.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashFunction.java?rev=881340&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashFunction.java
(added)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashFunction.java
Tue Nov 17 15:36:25 2009
@@ -0,0 +1,100 @@
+package org.apache.solr.search.function.distance;
+/**
+ * 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 org.apache.solr.search.function.ValueSource;
+import org.apache.solr.search.function.DocValues;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geohash.GeoHashUtils;
+
+import java.util.Map;
+import java.io.IOException;
+
+
+/**
+ * Takes in a latitude and longitude ValueSource and produces a GeoHash.
+ * <p/>
+ * Ex: geohash(lat, lon)
+ *
+ * <p/>
+ * Note, there is no reciprocal function for this.
+ **/
+public class GeohashFunction extends ValueSource {
+  protected ValueSource lat, lon;
+
+  public GeohashFunction(ValueSource lat, ValueSource lon) {
+    this.lat = lat;
+    this.lon = lon;
+  }
+
+  protected String name() {
+    return "geohash";
+  }
+
+  @Override
+  public DocValues getValues(Map context, IndexReader reader) throws IOException {
+    final DocValues latDV = lat.getValues(context, reader);
+    final DocValues lonDV = lon.getValues(context, reader);
+
+
+    return new DocValues() {
+
+      @Override
+      public String strVal(int doc) {
+        return GeoHashUtils.encode(latDV.doubleVal(doc), lonDV.doubleVal(doc));
+      }
+
+      @Override
+      public String toString(int doc) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(name()).append('(');
+        sb.append(latDV.toString(doc)).append(',').append(lonDV.toString(doc));
+        sb.append(')');
+        return sb.toString();
+      }
+    };
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof GeohashFunction)) return false;
+
+    GeohashFunction that = (GeohashFunction) o;
+
+    if (!lat.equals(that.lat)) return false;
+    if (!lon.equals(that.lon)) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = lat.hashCode();
+    result = 31 * result + lon.hashCode();
+    result = 31 * name().hashCode();
+    return result;
+  }
+
+  public String description() {
+    StringBuilder sb = new StringBuilder();
+    sb.append(name()).append('(');
+    sb.append(lat).append(',').append(lon);
+    sb.append(')');
+    return sb.toString();
+  }
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java?rev=881340&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java
(added)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java
Tue Nov 17 15:36:25 2009
@@ -0,0 +1,139 @@
+package org.apache.solr.search.function.distance;
+/**
+ * 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 org.apache.solr.search.function.ValueSource;
+import org.apache.solr.search.function.DocValues;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.spatial.geohash.GeoHashUtils;
+
+import java.util.Map;
+import java.io.IOException;
+
+
+/**
+ *  Calculate the Haversine distance between two geo hash codes.
+ *
+ * <p/>
+ * Ex: ghhsin(ValueSource, ValueSource, radius)
+ * <p/>
+ *
+ * @see org.apache.solr.search.function.distance.HaversineFunction for more details on the
implementation
+ *
+ **/
+public class GeohashHaversineFunction extends ValueSource {
+
+  private ValueSource geoHash1, geoHash2;
+  private double radius;
+
+  public GeohashHaversineFunction(ValueSource geoHash1, ValueSource geoHash2, double radius)
{
+    this.geoHash1 = geoHash1;
+    this.geoHash2 = geoHash2;
+    this.radius = radius;
+  }
+
+  protected String name() {
+    return "ghhsin";
+  }
+
+  @Override
+  public DocValues getValues(Map context, IndexReader reader) throws IOException {
+    final DocValues gh1DV = geoHash1.getValues(context, reader);
+    final DocValues gh2DV = geoHash2.getValues(context, reader);
+
+    return new DocValues() {
+      public float floatVal(int doc) {
+        return (float) doubleVal(doc);
+      }
+
+      public int intVal(int doc) {
+        return (int) doubleVal(doc);
+      }
+
+      public long longVal(int doc) {
+        return (long) doubleVal(doc);
+      }
+
+      public double doubleVal(int doc) {
+        return (double) distance(doc, gh1DV, gh2DV);
+      }
+
+      public String strVal(int doc) {
+        return Double.toString(doubleVal(doc));
+      }
+
+      @Override
+      public String toString(int doc) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(name()).append('(');
+        sb.append(gh1DV.toString(doc)).append(',').append(gh2DV.toString(doc));
+        sb.append(')');
+        return sb.toString();
+      }
+    };
+  }
+
+  protected double distance(int doc, DocValues gh1DV, DocValues gh2DV) {
+    double result = 0;
+    String h1 = gh1DV.strVal(doc);
+    String h2 = gh2DV.strVal(doc);
+    if (h1.equals(h2) == false){
+      double[] h1Pair = GeoHashUtils.decode(h1);
+      double[] h2Pair = GeoHashUtils.decode(h2);
+      result = DistanceUtils.haversine(Math.toRadians(h1Pair[0]), Math.toRadians(h1Pair[1]),
+              Math.toRadians(h2Pair[0]), Math.toRadians(h2Pair[1]), radius);
+    }
+    return result;
+  }
+
+  @Override
+  public void createWeight(Map context, Searcher searcher) throws IOException {
+    geoHash1.createWeight(context, searcher);
+    geoHash2.createWeight(context, searcher);
+  }
+
+  public boolean equals(Object o) {
+    if (this.getClass() != o.getClass()) return false;
+    GeohashHaversineFunction other = (GeohashHaversineFunction) o;
+    return this.name().equals(other.name())
+            && geoHash1.equals(other.geoHash1) &&
+            geoHash2.equals(other.geoHash2) &&
+            radius == other.radius;
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    result = geoHash1.hashCode();
+    result = 31 * result + geoHash2.hashCode();
+    result = 31 * result + name().hashCode();
+    temp = radius != +0.0d ? Double.doubleToLongBits(radius) : 0L;
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  public String description() {
+    StringBuilder sb = new StringBuilder();
+    sb.append(name()).append('(');
+    sb.append(geoHash1).append(',').append(geoHash2);
+    sb.append(')');
+    return sb.toString();
+  }
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java?rev=881340&r1=881339&r2=881340&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java
(original)
+++ lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java
Tue Nov 17 15:36:25 2009
@@ -18,6 +18,7 @@
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.util.AbstractSolrTestCase;
+import org.apache.lucene.spatial.geohash.GeoHashUtils;
 
 
 /**
@@ -39,16 +40,24 @@
 
 
   public void testHaversine() throws Exception {
-    assertU(adoc("id", "1", "x_td", "0", "y_td", "0"));
-    assertU(adoc("id", "2", "x_td", "0", "y_td", String.valueOf(Math.PI / 2)));
-    assertU(adoc("id", "3", "x_td", String.valueOf(Math.PI / 2), "y_td", String.valueOf(Math.PI
/ 2)));
-    assertU(adoc("id", "4", "x_td", String.valueOf(Math.PI / 4), "y_td", String.valueOf(Math.PI
/ 4)));
+    assertU(adoc("id", "1", "x_td", "0", "y_td", "0", "gh_s", GeoHashUtils.encode(32.7693246,
-79.9289094)));
+    assertU(adoc("id", "2", "x_td", "0", "y_td", String.valueOf(Math.PI / 2), "gh_s", GeoHashUtils.encode(32.7693246,
-78.9289094)));
+    assertU(adoc("id", "3", "x_td", String.valueOf(Math.PI / 2), "y_td", String.valueOf(Math.PI
/ 2), "gh_s", GeoHashUtils.encode(32.7693246, -80.9289094)));
+    assertU(adoc("id", "4", "x_td", String.valueOf(Math.PI / 4), "y_td", String.valueOf(Math.PI
/ 4), "gh_s", GeoHashUtils.encode(32.7693246, -81.9289094)));
     assertU(commit());
     //Get the haversine distance between the point 0,0 and the docs above assuming a radius
of 1
     assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:1"),
"//float[@name='score']='0.0'");
     assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:2"),
"//float[@name='score']='" + (float) (Math.PI / 2) + "'");
     assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:3"),
"//float[@name='score']='" + (float) (Math.PI / 2) + "'");
     assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:4"),
"//float[@name='score']='1.0471976'");
+
+    //Geo Hash Haversine
+    //Can verify here: http://www.movable-type.co.uk/scripts/latlong.html, but they use a
slightly different radius for the earth, so just be close
+    assertQ(req("fl", "*,score", "q", "{!func}ghhsin(gh_s, \"" + GeoHashUtils.encode(32,
-79) +
+            "\"," + Constants.EARTH_RADIUS_KM +
+            ")", "fq", "id:1"), "//float[@name='score']='122.30894'");
+    assertQ(req("fl", "*,score", "q", "{!func}ghhsin(gh_s, geohash(32, -79)," + Constants.EARTH_RADIUS_KM
+
+            ")", "fq", "id:1"), "//float[@name='score']='122.30894'");
   }
 
   public void testVector() throws Exception {



Mime
View raw message