lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kwri...@apache.org
Subject lucene-solr:master: LUCENE-7212: Add outside distance classes and methods.
Date Wed, 18 May 2016 13:04:02 GMT
Repository: lucene-solr
Updated Branches:
  refs/heads/master 2a810938b -> cc2634134


LUCENE-7212: Add outside distance classes and methods.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/cc263413
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/cc263413
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/cc263413

Branch: refs/heads/master
Commit: cc263413457c826914c3f3c1c26f885330a931aa
Parents: 2a81093
Author: Karl Wright <DaddyWri@gmail.com>
Authored: Wed May 18 09:03:52 2016 -0400
Committer: Karl Wright <DaddyWri@gmail.com>
Committed: Wed May 18 09:03:52 2016 -0400

----------------------------------------------------------------------
 .../lucene/spatial3d/Geo3DDocValuesField.java   | 132 +++++++++++++++++-
 .../org/apache/lucene/spatial3d/Geo3DPoint.java |   3 -
 .../Geo3DPointOutsideDistanceComparator.java    | 137 +++++++++++++++++++
 .../spatial3d/Geo3DPointOutsideSortField.java   |  96 +++++++++++++
 .../org/apache/lucene/spatial3d/Geo3DUtil.java  |   3 +
 5 files changed, 363 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc263413/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
index 3fdefb5..dd171ec 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
@@ -22,10 +22,12 @@ import org.apache.lucene.search.FieldDoc;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.FieldType;
+import org.apache.lucene.geo.Polygon;
 
 import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.apache.lucene.spatial3d.geom.GeoPoint;
 import org.apache.lucene.spatial3d.geom.GeoDistanceShape;
+import org.apache.lucene.spatial3d.geom.GeoOutsideDistance;
 
 /** 
  * An per-document 3D location field.
@@ -256,7 +258,7 @@ public class Geo3DDocValuesField extends Field {
   }
 
   /**
-   * Creates a SortField for sorting by distance from a point.
+   * Creates a SortField for sorting by distance within a circle.
    * <p>
    * This sort orders documents by ascending distance from the location. The value returned
in {@link FieldDoc} for
    * the hits contains a Double instance with the distance in meters.
@@ -264,14 +266,14 @@ public class Geo3DDocValuesField extends Field {
    * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
    * (missing values sort last).
    * <p>
-   * If a document contains multiple values for the field, the <i>closest</i>
distance to the location is used.
+   * If a document contains multiple values for the field, the <i>closest</i>
distance from the circle center is used.
    * 
    * @param field field name. must not be null.
    * @param latitude latitude at the center: must be within standard +/-90 coordinate bounds.
    * @param longitude longitude at the center: must be within standard +/-180 coordinate
bounds.
    * @param maxRadiusMeters is the maximum radius in meters.
    * @return SortField ordering documents by distance
-   * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates.
+   * @throws IllegalArgumentException if {@code field} is null or circle has invalid coordinates.
    */
   public static SortField newDistanceSort(final String field, final double latitude, final
double longitude, final double maxRadiusMeters) {
     final GeoDistanceShape shape = Geo3DUtil.fromDistance(latitude, longitude, maxRadiusMeters);
@@ -287,18 +289,138 @@ public class Geo3DDocValuesField extends Field {
    * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
    * (missing values sort last).
    * <p>
-   * If a document contains multiple values for the field, the <i>closest</i>
distance to the location is used.
+   * If a document contains multiple values for the field, the <i>closest</i>
distance along the path is used.
    * 
    * @param field field name. must not be null.
    * @param pathLatitudes latitude values for points of the path: must be within standard
+/-90 coordinate bounds.
    * @param pathLongitudes longitude values for points of the path: must be within standard
+/-180 coordinate bounds.
    * @param pathWidthMeters width of the path in meters.
    * @return SortField ordering documents by distance
-   * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates.
+   * @throws IllegalArgumentException if {@code field} is null or path has invalid coordinates.
    */
   public static SortField newPathSort(final String field, final double[] pathLatitudes, final
double[] pathLongitudes, final double pathWidthMeters) {
     final GeoDistanceShape shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters);
     return new Geo3DPointSortField(field, shape);
   }
 
+  // Outside distances
+  
+  /**
+   * Creates a SortField for sorting by outside distance from a circle.
+   * <p>
+   * This sort orders documents by ascending outside distance from the circle.  Points within
the circle have distance 0.0.
+   * The value returned in {@link FieldDoc} for
+   * the hits contains a Double instance with the distance in meters.
+   * <p>
+   * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
+   * (missing values sort last).
+   * <p>
+   * If a document contains multiple values for the field, the <i>closest</i>
distance to the circle is used.
+   * 
+   * @param field field name. must not be null.
+   * @param latitude latitude at the center: must be within standard +/-90 coordinate bounds.
+   * @param longitude longitude at the center: must be within standard +/-180 coordinate
bounds.
+   * @param maxRadiusMeters is the maximum radius in meters.
+   * @return SortField ordering documents by distance
+   * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates.
+   */
+  public static SortField newOutsideDistanceSort(final String field, final double latitude,
final double longitude, final double maxRadiusMeters) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromDistance(latitude, longitude, maxRadiusMeters);
+    return new Geo3DPointOutsideSortField(field, shape);
+  }
+
+  /**
+   * Creates a SortField for sorting by outside distance from a box.
+   * <p>
+   * This sort orders documents by ascending outside distance from the box.  Points within
the box have distance 0.0.
+   * The value returned in {@link FieldDoc} for
+   * the hits contains a Double instance with the distance in meters.
+   * <p>
+   * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
+   * (missing values sort last).
+   * <p>
+   * If a document contains multiple values for the field, the <i>closest</i>
distance to the box is used.
+   * 
+   * @param field field name. must not be null.
+   * @param minLatitude latitude lower bound: must be within standard +/-90 coordinate bounds.
+   * @param maxLatitude latitude upper bound: must be within standard +/-90 coordinate bounds.
+   * @param minLongitude longitude lower bound: must be within standard +/-180 coordinate
bounds.
+   * @param maxLongitude longitude upper bound: must be within standard +/-180 coordinate
bounds.
+   * @return SortField ordering documents by distance
+   * @throws IllegalArgumentException if {@code field} is null or box has invalid coordinates.
+   */
+  public static SortField newOutsideBoxSort(final String field, final double minLatitude,
final double maxLatitude, final double minLongitude, final double maxLongitude) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromBox(minLatitude, maxLatitude, minLongitude,
maxLongitude);
+    return new Geo3DPointOutsideSortField(field, shape);
+  }
+
+  /**
+   * Creates a SortField for sorting by outside distance from a polygon.
+   * <p>
+   * This sort orders documents by ascending outside distance from the polygon.  Points within
the polygon have distance 0.0.
+   * The value returned in {@link FieldDoc} for
+   * the hits contains a Double instance with the distance in meters.
+   * <p>
+   * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
+   * (missing values sort last).
+   * <p>
+   * If a document contains multiple values for the field, the <i>closest</i>
distance to the polygon is used.
+   * 
+   * @param field field name. must not be null.
+   * @param polygons is the list of polygons to use to construct the query; must be at least
one.
+   * @return SortField ordering documents by distance
+   * @throws IllegalArgumentException if {@code field} is null or polygon has invalid coordinates.
+   */
+  public static SortField newOutsidePolygonSort(final String field, final Polygon... polygons)
{
+    final GeoOutsideDistance shape = Geo3DUtil.fromPolygon(polygons);
+    return new Geo3DPointOutsideSortField(field, shape);
+  }
+
+  /**
+   * Creates a SortField for sorting by outside distance from a large polygon.  This differs
from the related newOutsideLargePolygonSort in that it
+   * does little or no legality checking and is optimized for very large numbers of polygon
edges.
+   * <p>
+   * This sort orders documents by ascending outside distance from the polygon.  Points within
the polygon have distance 0.0.
+   * The value returned in {@link FieldDoc} for
+   * the hits contains a Double instance with the distance in meters.
+   * <p>
+   * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
+   * (missing values sort last).
+   * <p>
+   * If a document contains multiple values for the field, the <i>closest</i>
distance to the polygon is used.
+   * 
+   * @param field field name. must not be null.
+   * @param polygons is the list of polygons to use to construct the query; must be at least
one.
+   * @return SortField ordering documents by distance
+   * @throws IllegalArgumentException if {@code field} is null or polygon has invalid coordinates.
+   */
+  public static SortField newOutsideLargePolygonSort(final String field, final Polygon...
polygons) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromLargePolygon(polygons);
+    return new Geo3DPointOutsideSortField(field, shape);
+  }
+
+  /**
+   * Creates a SortField for sorting by outside distance from a path.
+   * <p>
+   * This sort orders documents by ascending outside distance from the described path. Points
within the path
+   * are given the distance of 0.0.  The value returned in {@link FieldDoc} for
+   * the hits contains a Double instance with the distance in meters.
+   * <p>
+   * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY}
distance
+   * (missing values sort last).
+   * <p>
+   * If a document contains multiple values for the field, the <i>closest</i>
distance from the path is used.
+   * 
+   * @param field field name. must not be null.
+   * @param pathLatitudes latitude values for points of the path: must be within standard
+/-90 coordinate bounds.
+   * @param pathLongitudes longitude values for points of the path: must be within standard
+/-180 coordinate bounds.
+   * @param pathWidthMeters width of the path in meters.
+   * @return SortField ordering documents by distance
+   * @throws IllegalArgumentException if {@code field} is null or path has invalid coordinates.
+   */
+  public static SortField newOutsidePathSort(final String field, final double[] pathLatitudes,
final double[] pathLongitudes, final double pathWidthMeters) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters);
+    return new Geo3DPointOutsideSortField(field, shape);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc263413/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
index 2ff1286..15426e6 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
@@ -129,9 +129,6 @@ public final class Geo3DPoint extends Field {
    * @return query matching points within this polygon
    */
   public static Query newLargePolygonQuery(final String field, final Polygon... polygons)
{
-    if (polygons.length < 1) {
-      throw new IllegalArgumentException("need at least one polygon");
-    }
     final GeoShape shape = Geo3DUtil.fromLargePolygon(polygons);
     return newShapeQuery(field, shape);
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc263413/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
new file mode 100644
index 0000000..10e0010
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+package org.apache.lucene.spatial3d;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.search.FieldComparator;
+import org.apache.lucene.search.LeafFieldComparator;
+import org.apache.lucene.search.Scorer;
+
+import org.apache.lucene.spatial3d.geom.GeoOutsideDistance;
+import org.apache.lucene.spatial3d.geom.DistanceStyle;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+
+/**
+ * Compares documents by outside distance, using a GeoOutsideDistance to compute the distance
+ */
+class Geo3DPointOutsideDistanceComparator extends FieldComparator<Double> implements
LeafFieldComparator {
+  final String field;
+  
+  final GeoOutsideDistance distanceShape;
+
+  final double[] values;
+  double bottomDistance;
+  double topValue;
+  SortedNumericDocValues currentDocs;
+  
+  public Geo3DPointOutsideDistanceComparator(String field, final GeoOutsideDistance distanceShape,
int numHits) {
+    this.field = field;
+    this.distanceShape = distanceShape;
+    this.values = new double[numHits];
+  }
+  
+  @Override
+  public void setScorer(Scorer scorer) {}
+
+  @Override
+  public int compare(int slot1, int slot2) {
+    return Double.compare(values[slot1], values[slot2]);
+  }
+  
+  @Override
+  public void setBottom(int slot) {
+    bottomDistance = values[slot];
+  }
+  
+  @Override
+  public void setTopValue(Double value) {
+    topValue = value.doubleValue();
+  }
+  
+  @Override
+  public int compareBottom(int doc) throws IOException {
+    currentDocs.setDocument(doc);
+
+    int numValues = currentDocs.count();
+    if (numValues == 0) {
+      return Double.compare(bottomDistance, Double.POSITIVE_INFINITY);
+    }
+
+    int cmp = -1;
+    for (int i = 0; i < numValues; i++) {
+      long encoded = currentDocs.valueAt(i);
+
+      // Test against bounds.
+      // First we need to decode...
+      final double x = Geo3DDocValuesField.decodeXValue(encoded);
+      final double y = Geo3DDocValuesField.decodeYValue(encoded);
+      final double z = Geo3DDocValuesField.decodeZValue(encoded);
+      
+      cmp = Math.max(cmp, Double.compare(bottomDistance, distanceShape.computeOutsideDistance(DistanceStyle.ARC,
x, y, z)));
+    }
+    return cmp;
+  }
+  
+  @Override
+  public void copy(int slot, int doc) throws IOException {
+    values[slot] = computeMinimumDistance(doc);
+  }
+  
+  @Override
+  public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException
{
+    LeafReader reader = context.reader();
+    FieldInfo info = reader.getFieldInfos().fieldInfo(field);
+    if (info != null) {
+      Geo3DDocValuesField.checkCompatible(info);
+    }
+    currentDocs = DocValues.getSortedNumeric(reader, field);
+    return this;
+  }
+  
+  @Override
+  public Double value(int slot) {
+    // Return the arc distance
+    return Double.valueOf(values[slot] * PlanetModel.WGS84_MEAN);
+  }
+  
+  @Override
+  public int compareTop(int doc) throws IOException {
+    return Double.compare(topValue, computeMinimumDistance(doc));
+  }
+
+  double computeMinimumDistance(final int doc) {
+    currentDocs.setDocument(doc);
+    double minValue = Double.POSITIVE_INFINITY;
+    final int numValues = currentDocs.count();
+    for (int i = 0; i < numValues; i++) {
+      final long encoded = currentDocs.valueAt(i);
+      final double distance = distanceShape.computeOutsideDistance(DistanceStyle.ARC,
+        Geo3DDocValuesField.decodeXValue(encoded),
+        Geo3DDocValuesField.decodeYValue(encoded),
+        Geo3DDocValuesField.decodeZValue(encoded));
+      minValue = Math.min(minValue, distance);
+    }
+    return minValue;
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc263413/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
new file mode 100644
index 0000000..b48984c
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+package org.apache.lucene.spatial3d;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.FieldComparator;
+import org.apache.lucene.search.SortField;
+
+import org.apache.lucene.spatial3d.geom.GeoOutsideDistance;
+
+/**
+ * Sorts by outside distance from an origin location.
+ */
+final class Geo3DPointOutsideSortField extends SortField {
+  final GeoOutsideDistance distanceShape;
+
+  Geo3DPointOutsideSortField(final String field, final GeoOutsideDistance distanceShape)
{
+    super(field, SortField.Type.CUSTOM);
+    if (field == null) {
+      throw new IllegalArgumentException("field must not be null");
+    }
+    if (distanceShape == null) {
+      throw new IllegalArgumentException("distanceShape must not be null");
+    }
+    this.distanceShape = distanceShape;
+    setMissingValue(Double.POSITIVE_INFINITY);
+  }
+  
+  @Override
+  public FieldComparator<?> getComparator(int numHits, int sortPos) throws IOException
{
+    return new Geo3DPointOutsideDistanceComparator(getField(), distanceShape, numHits);
+  }
+
+  @Override
+  public Double getMissingValue() {
+    return (Double) super.getMissingValue();
+  }
+
+  @Override
+  public void setMissingValue(Object missingValue) {
+    if (Double.valueOf(Double.POSITIVE_INFINITY).equals(missingValue) == false) {
+      throw new IllegalArgumentException("Missing value can only be Double.POSITIVE_INFINITY
(missing values last), but got " + missingValue);
+    }
+    this.missingValue = missingValue;
+  }
+  
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = super.hashCode();
+    long temp;
+    temp = distanceShape.hashCode();
+    result = prime * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) return true;
+    if (!super.equals(obj)) return false;
+    if (getClass() != obj.getClass()) return false;
+    final Geo3DPointSortField other = (Geo3DPointSortField) obj;
+    return distanceShape.equals(other.distanceShape);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder builder = new StringBuilder();
+    builder.append("<outsideDistanceShape:");
+    builder.append('"');
+    builder.append(getField());
+    builder.append('"');
+    builder.append(" shape=");
+    builder.append(distanceShape);
+    if (Double.POSITIVE_INFINITY != getMissingValue()) {
+      builder.append(" missingValue=" + getMissingValue());
+    }
+    builder.append('>');
+    return builder.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc263413/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
index a413c06..2e37b27 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
@@ -136,6 +136,9 @@ class Geo3DUtil {
    * @return the large GeoPolygon.
    */
   static GeoPolygon fromLargePolygon(final Polygon... polygons) {
+    if (polygons.length < 1) {
+      throw new IllegalArgumentException("need at least one polygon");
+    }
     return GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.WGS84, convertToDescription(polygons));
   }
   


Mime
View raw message