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 2014/07/08 22:18:47 UTC

svn commit: r1608939 - in /lucene/dev/branches/branch_4x: ./ lucene/ lucene/spatial/ lucene/spatial/src/java/org/apache/lucene/spatial/query/ lucene/spatial/src/test-files/ lucene/spatial/src/test/org/apache/lucene/spatial/query/

Author: dsmiley
Date: Tue Jul  8 20:18:47 2014
New Revision: 1608939

URL: http://svn.apache.org/r1608939
Log:
LUCENE-5771: SpatialOperation refactoring: (OGC alias names, removed area requirement, fixed overlap definition)

Modified:
    lucene/dev/branches/branch_4x/   (props changed)
    lucene/dev/branches/branch_4x/lucene/   (props changed)
    lucene/dev/branches/branch_4x/lucene/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_4x/lucene/spatial/   (props changed)
    lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialArgs.java
    lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialOperation.java
    lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/simple-Queries-BBox.txt   (contents, props changed)
    lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java

Modified: lucene/dev/branches/branch_4x/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/CHANGES.txt?rev=1608939&r1=1608938&r2=1608939&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_4x/lucene/CHANGES.txt Tue Jul  8 20:18:47 2014
@@ -23,6 +23,11 @@ API Changes
 * LUCENE-5692: DisjointSpatialFilter is deprecated (used by RecursivePrefixTreeStrategy)
   (David Smiley)
 
+* LUCENE-5771: SpatialOperation's predicate names are now aliased to OGC standard names.
+  Thus you can use: Disjoint, Equals, Intersects, Overlaps, Within, Contains, Covers,
+  CoveredBy. The area requirement on the predicates was removed, and Overlaps' definition
+  was fixed. (David Smiley)
+
 Optimizations
 
 * LUCENE-5780: Make OrdinalMap more memory-efficient, especially in case the

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialArgs.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialArgs.java?rev=1608939&r1=1608938&r2=1608939&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialArgs.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialArgs.java Tue Jul  8 20:18:47 2014
@@ -87,9 +87,6 @@ public class SpatialArgs {
 
   /** Check if the arguments make sense -- throw an exception if not */
   public void validate() throws IllegalArgumentException {
-    if (operation.isTargetNeedsArea() && !shape.hasArea()) {
-      throw new IllegalArgumentException(operation + " only supports geometry with area");
-    }
     if (distErr != null && distErrPct != null)
       throw new IllegalArgumentException("Only distErr or distErrPct can be specified.");
   }

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialOperation.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialOperation.java?rev=1608939&r1=1608938&r2=1608939&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialOperation.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/query/SpatialOperation.java Tue Jul  8 20:18:47 2014
@@ -29,88 +29,114 @@ import java.util.Locale;
 import java.util.Map;
 
 /**
- * A clause that compares a stored geometry to a supplied geometry. For more
- * explanation of each operation, consider looking at the source implementation
- * of {@link #evaluate(com.spatial4j.core.shape.Shape, com.spatial4j.core.shape.Shape)}.
+ * A predicate that compares a stored geometry to a supplied geometry. It's enum-like. For more
+ * explanation of each predicate, consider looking at the source implementation
+ * of {@link #evaluate(com.spatial4j.core.shape.Shape, com.spatial4j.core.shape.Shape)}. It's important
+ * to be aware that Lucene-spatial makes no distinction of shape boundaries, unlike many standardized
+ * definitions. Nor does it make dimensional distinctions (e.g. line vs polygon).
+ * You can lookup a predicate by "Covers" or "Contains", for example, and you will get the
+ * same underlying predicate implementation.
  *
+ * @see <a href="http://en.wikipedia.org/wiki/DE-9IM">DE-9IM at Wikipedia, based on OGC specs</a>
  * @see <a href="http://edndoc.esri.com/arcsde/9.1/general_topics/understand_spatial_relations.htm">
  *   ESRIs docs on spatial relations</a>
  *
  * @lucene.experimental
  */
 public abstract class SpatialOperation implements Serializable {
+  //TODO rename to SpatialPredicate. Use enum?  LUCENE-5771
+
   // Private registry
-  private static final Map<String, SpatialOperation> registry = new HashMap<>();
+  private static final Map<String, SpatialOperation> registry = new HashMap<>();//has aliases
   private static final List<SpatialOperation> list = new ArrayList<>();
 
   // Geometry Operations
 
-  /** Bounding box of the *indexed* shape. */
-  public static final SpatialOperation BBoxIntersects = new SpatialOperation("BBoxIntersects", true, false, false) {
+  /** Bounding box of the *indexed* shape, then {@link #Intersects}. */
+  public static final SpatialOperation BBoxIntersects = new SpatialOperation("BBoxIntersects") {
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
       return indexedShape.getBoundingBox().relate(queryShape).intersects();
     }
   };
-  /** Bounding box of the *indexed* shape. */
-  public static final SpatialOperation BBoxWithin     = new SpatialOperation("BBoxWithin", true, false, false) {
+  /** Bounding box of the *indexed* shape, then {@link #IsWithin}. */
+  public static final SpatialOperation BBoxWithin     = new SpatialOperation("BBoxWithin") {
+    {
+      register("BBoxCoveredBy");//alias -- the better name
+    }
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
       Rectangle bbox = indexedShape.getBoundingBox();
       return bbox.relate(queryShape) == SpatialRelation.WITHIN || bbox.equals(queryShape);
     }
   };
-  public static final SpatialOperation Contains       = new SpatialOperation("Contains", true, true, false) {
+  /** Meets the "Covers" OGC definition (boundary-neutral). */
+  public static final SpatialOperation Contains       = new SpatialOperation("Contains") {
+    {
+      register("Covers");//alias -- the better name
+    }
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
-      return indexedShape.hasArea() && indexedShape.relate(queryShape) == SpatialRelation.CONTAINS || indexedShape.equals(queryShape);
+      return indexedShape.relate(queryShape) == SpatialRelation.CONTAINS || indexedShape.equals(queryShape);
     }
   };
-  public static final SpatialOperation Intersects     = new SpatialOperation("Intersects", true, false, false) {
+  /** Meets the "Intersects" OGC definition. */
+  public static final SpatialOperation Intersects     = new SpatialOperation("Intersects") {
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
       return indexedShape.relate(queryShape).intersects();
     }
   };
-  public static final SpatialOperation IsEqualTo      = new SpatialOperation("IsEqualTo", false, false, false) {
+  /** Meets the "Equals" OGC definition. */
+  public static final SpatialOperation IsEqualTo      = new SpatialOperation("Equals") {
+    {
+      register("IsEqualTo");//alias (deprecated)
+    }
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
       return indexedShape.equals(queryShape);
     }
   };
-  public static final SpatialOperation IsDisjointTo   = new SpatialOperation("IsDisjointTo", false, false, false) {
+  /** Meets the "Disjoint" OGC definition. */
+  public static final SpatialOperation IsDisjointTo   = new SpatialOperation("Disjoint") {
+    {
+      register("IsDisjointTo");//alias (deprecated)
+    }
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
       return ! indexedShape.relate(queryShape).intersects();
     }
   };
-  public static final SpatialOperation IsWithin       = new SpatialOperation("IsWithin", true, false, true) {
+  /** Meets the "CoveredBy" OGC definition (boundary-neutral). */
+  public static final SpatialOperation IsWithin       = new SpatialOperation("Within") {
+    {
+      register("IsWithin");//alias (deprecated)
+      register("CoveredBy");//alias -- the more appropriate name.
+    }
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
-      return queryShape.hasArea() && (indexedShape.relate(queryShape) == SpatialRelation.WITHIN || indexedShape.equals(queryShape));
+      return indexedShape.relate(queryShape) == SpatialRelation.WITHIN || indexedShape.equals(queryShape);
     }
   };
-  public static final SpatialOperation Overlaps       = new SpatialOperation("Overlaps", true, false, true) {
+  /** Almost meets the "Overlaps" OGC definition, but boundary-neutral (boundary==interior). */
+  public static final SpatialOperation Overlaps       = new SpatialOperation("Overlaps") {
     @Override
     public boolean evaluate(Shape indexedShape, Shape queryShape) {
-      return queryShape.hasArea() && indexedShape.relate(queryShape).intersects();
+      return indexedShape.relate(queryShape) == SpatialRelation.INTERSECTS;//not Contains or Within or Disjoint
     }
   };
 
-  // Member variables
-  private final boolean scoreIsMeaningful;
-  private final boolean sourceNeedsArea;
-  private final boolean targetNeedsArea;
   private final String name;
 
-  protected SpatialOperation(String name, boolean scoreIsMeaningful, boolean sourceNeedsArea, boolean targetNeedsArea) {
+  protected SpatialOperation(String name) {
     this.name = name;
-    this.scoreIsMeaningful = scoreIsMeaningful;
-    this.sourceNeedsArea = sourceNeedsArea;
-    this.targetNeedsArea = targetNeedsArea;
+    register(name);
+    list.add( this );
+  }
+
+  protected void register(String name) {
     registry.put(name, this);
     registry.put(name.toUpperCase(Locale.ROOT), this);
-    list.add( this );
   }
 
   public static SpatialOperation get( String v ) {
@@ -143,20 +169,6 @@ public abstract class SpatialOperation i
    */
   public abstract boolean evaluate(Shape indexedShape, Shape queryShape);
 
-  // ================================================= Getters / Setters =============================================
-
-  public boolean isScoreIsMeaningful() {
-    return scoreIsMeaningful;
-  }
-
-  public boolean isSourceNeedsArea() {
-    return sourceNeedsArea;
-  }
-
-  public boolean isTargetNeedsArea() {
-    return targetNeedsArea;
-  }
-
   public String getName() {
     return name;
   }

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/simple-Queries-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/simple-Queries-BBox.txt?rev=1608939&r1=1608938&r2=1608939&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/simple-Queries-BBox.txt (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/simple-Queries-BBox.txt Tue Jul  8 20:18:47 2014
@@ -3,6 +3,7 @@ C5 @ BBoxWithin(ENVELOPE(-6, 6, 6, -6))
 C10 @ Contains(ENVELOPE(-6, 6, 6, -6))
 C10 @ IsEqualTo(ENVELOPE(-10, 10, 10, -10))
 C5 C10 @ Intersects(ENVELOPE(-2, 2, 2, -2))
-C5 C10 @ Overlaps(ENVELOPE(-2, 2, 2, -2))
+ @ Overlaps(ENVELOPE(-2, 2, 2, -2))
+C5 @ Overlaps(ENVELOPE(-2, 2, 8, -2))
 C5 C10 @ BBoxIntersects(ENVELOPE(-2, 2, 2, -2))
 NW15 @ IsDisjointTo(ENVELOPE(-10, 10, 10, -10))
\ No newline at end of file

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java?rev=1608939&r1=1608938&r2=1608939&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java Tue Jul  8 20:18:47 2014
@@ -22,7 +22,9 @@ import com.spatial4j.core.shape.Rectangl
 import org.apache.lucene.util.LuceneTestCase;
 import org.junit.Test;
 
+import java.text.ParseException;
 
+//Tests SpatialOperation somewhat too
 public class SpatialArgsParserTest extends LuceneTestCase {
 
   private SpatialContext ctx = SpatialContext.GEO;
@@ -59,6 +61,22 @@ public class SpatialArgsParserTest exten
     }
     catch (Exception ex) {//expected
     }
+
+    assertAlias(SpatialOperation.IsWithin, "CoveredBy");
+    assertAlias(SpatialOperation.IsWithin, "COVEREDBY");
+    assertAlias(SpatialOperation.IsWithin, "coveredBy");
+    assertAlias(SpatialOperation.IsWithin, "Within");
+    assertAlias(SpatialOperation.IsEqualTo, "Equals");
+    assertAlias(SpatialOperation.IsDisjointTo, "disjoint");
+    assertAlias(SpatialOperation.Contains, "Covers");
+  }
+
+  private void assertAlias(SpatialOperation op, final String name) throws ParseException {
+    String arg;
+    SpatialArgs out;
+    arg = name + "(Point(0 0))";
+    out = new SpatialArgsParser().parse(arg, ctx);
+    assertEquals(op, out.getOperation());
   }
 
 }