You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by iv...@apache.org on 2020/11/23 08:37:49 UTC

[lucene-solr] branch branch_8x updated: LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic (#2059)

This is an automated email from the ASF dual-hosted git repository.

ivera pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new 2d7d315  LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic (#2059)
2d7d315 is described below

commit 2d7d315f970ae413b27d5a11c10de1cb643b089d
Author: Ignacio Vera <iv...@apache.org>
AuthorDate: Mon Nov 23 09:36:35 2020 +0100

    LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic (#2059)
---
 lucene/CHANGES.txt                                 |  3 ++
 .../document/LatLonShapeBoundingBoxQuery.java      |  3 +-
 .../src/java/org/apache/lucene/geo/Circle2D.java   |  2 +-
 .../src/java/org/apache/lucene/geo/Line2D.java     |  6 ++-
 .../src/java/org/apache/lucene/geo/Polygon2D.java  |  2 +-
 .../java/org/apache/lucene/geo/Rectangle2D.java    |  4 +-
 .../apache/lucene/document/TestLatLonShape.java    | 46 ++++++++++++++++++++++
 .../org/apache/lucene/document/TestXYShape.java    | 45 +++++++++++++++++++++
 8 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index fc32c40..5aeccb3 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -45,6 +45,9 @@ Bug Fixes
 * LUCENE-9581: Japanese tokenizer should discard the compound token instead of disabling the decomposition
   of long tokens when discardCompoundToken is activated. (Jim Ferenczi)
 
+* LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic.
+  (Ignacio Vera)   
+  
 Other
 ---------------------
 
diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonShapeBoundingBoxQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonShapeBoundingBoxQuery.java
index d7077e6..be3c7d3 100644
--- a/lucene/core/src/java/org/apache/lucene/document/LatLonShapeBoundingBoxQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/LatLonShapeBoundingBoxQuery.java
@@ -124,7 +124,8 @@ final class LatLonShapeBoundingBoxQuery extends ShapeQuery {
 
     switch (scratchTriangle.type) {
       case POINT: {
-        return Component2D.WithinRelation.DISJOINT;
+        return  encodedRectangle.contains(scratchTriangle.aX, scratchTriangle.aY) 
+                ? Component2D.WithinRelation.NOTWITHIN : Component2D.WithinRelation.DISJOINT;
       }
       case LINE: {
         return encodedRectangle.withinLine(scratchTriangle.aX, scratchTriangle.aY, scratchTriangle.ab,
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Circle2D.java b/lucene/core/src/java/org/apache/lucene/geo/Circle2D.java
index 1717846..4cc64ed 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Circle2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Circle2D.java
@@ -110,7 +110,7 @@ class Circle2D implements Component2D {
 
   @Override
   public WithinRelation withinPoint(double x, double y) {
-    return WithinRelation.DISJOINT;
+    return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Line2D.java b/lucene/core/src/java/org/apache/lucene/geo/Line2D.java
index 313728e..97b2a49 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Line2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Line2D.java
@@ -129,13 +129,15 @@ final class Line2D implements Component2D {
 
   @Override
   public WithinRelation withinPoint(double x, double y) {
-    return WithinRelation.DISJOINT;
+    return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
   }
 
   @Override
   public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
                                    double aX, double aY, boolean ab, double bX, double bY) {
-    // can be improved?
+    if (ab && intersectsLine(minX, maxX, minY, maxY, aX, aY, bX, bY)) {
+      return  WithinRelation.NOTWITHIN;
+    }
     return WithinRelation.DISJOINT;
   }
 
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java b/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java
index 438756d..a601f46 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java
@@ -181,7 +181,7 @@ final class Polygon2D implements Component2D {
 
   @Override
   public WithinRelation withinPoint(double x, double y) {
-    return WithinRelation.DISJOINT;
+    return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Rectangle2D.java b/lucene/core/src/java/org/apache/lucene/geo/Rectangle2D.java
index 37b5f03..e0f1858 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Rectangle2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Rectangle2D.java
@@ -118,13 +118,13 @@ final class Rectangle2D implements Component2D {
 
   @Override
   public WithinRelation withinPoint(double x, double y) {
-    return WithinRelation.DISJOINT;
+    return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
   }
 
   @Override
   public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
                                    double aX, double aY, boolean ab, double bX, double bY) {
-    if (ab == true && Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY) ==false &&
+    if (ab == true && Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY) == false &&
         edgesIntersect(aX, aY, bX, bY)) {
       return WithinRelation.NOTWITHIN;
     }
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java b/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java
index 53b1ead..9773ffb 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java
@@ -26,6 +26,7 @@ import org.apache.lucene.geo.GeoUtils;
 import org.apache.lucene.geo.LatLonGeometry;
 import org.apache.lucene.geo.Line;
 import org.apache.lucene.geo.Polygon;
+import org.apache.lucene.geo.Rectangle;
 import org.apache.lucene.geo.Tessellator;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
@@ -827,4 +828,49 @@ public class TestLatLonShape extends LuceneTestCase {
 
     IOUtils.close(r, dir);
   }
+
+  public void testContainsIndexedGeometryCollection() throws Exception {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    Polygon polygon = new Polygon(new double[] {-64, -64, 64, 64, -64}, new double[] {-132, 132, 132, -132, -132});
+    Field[] polygonFields = LatLonShape.createIndexableFields(FIELDNAME, polygon);
+    // POINT(5, 5) inside the indexed polygon
+    Field[] pointFields = LatLonShape.createIndexableFields(FIELDNAME, 5, 5);
+    int numDocs = random().nextInt(1000);
+    // index the same multi geometry many times
+    for (int i = 0; i < numDocs; i++) {
+      Document doc = new Document();
+      for (Field f : polygonFields) {
+        doc.add(f);
+      }
+      for(int j = 0; j < 10; j++) {
+        for (Field f : pointFields) {
+          doc.add(f);
+        }
+      }
+      w.addDocument(doc);
+    }
+    w.forceMerge(1);
+
+    ///// search //////
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+    // Contains is only true if the query geometry is inside a geometry and does not intersect with any other geometry 
+    // belonging to the same document. In this case the query geometry contains the indexed polygon but the point is 
+    // inside the query as well, hence the result is 0.
+    Polygon polygonQuery = new Polygon(new double[] {4, 4, 6, 6, 4}, new double[] {4, 6, 6, 4, 4});
+    Query query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, polygonQuery);
+    assertEquals(0, searcher.count(query));
+
+    Rectangle rectangle = new Rectangle(4.0, 6.0, 4.0, 6.0);
+    query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, rectangle);
+    assertEquals(0, searcher.count(query));
+    
+    Circle circle = new Circle(5, 5, 10000);
+    query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, circle);
+    assertEquals(0, searcher.count(query));
+    
+    IOUtils.close(w, reader, dir);
+  }
 }
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYShape.java b/lucene/core/src/test/org/apache/lucene/document/TestXYShape.java
index 5cfdf07..3a90977 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYShape.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYShape.java
@@ -202,6 +202,51 @@ public class TestXYShape extends LuceneTestCase {
     IOUtils.close(r, dir);
   }
 
+  public void testContainsIndexedGeometryCollection() throws Exception {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    XYPolygon polygon = new XYPolygon(new float[] {-132, 132, 132, -132, -132}, new float[] {-64, -64, 64, 64, -64});
+    Field[] polygonFields = XYShape.createIndexableFields(FIELDNAME, polygon);
+    // POINT(5, 5) inside the indexed polygon
+    Field[] pointFields = XYShape.createIndexableFields(FIELDNAME, 5, 5);
+    int numDocs = random().nextInt(1000);
+    // index the same multi geometry many times
+    for (int i = 0; i < numDocs; i++) {
+      Document doc = new Document();
+      for (Field f : polygonFields) {
+        doc.add(f);
+      }
+      for(int j = 0; j < 10; j++) {
+        for (Field f : pointFields) {
+          doc.add(f);
+        }
+      }
+      w.addDocument(doc);
+    }
+    w.forceMerge(1);
+
+    ///// search //////
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+    // Contains is only true if the query geometry is inside a geometry and does not intersect with any other geometry 
+    // belonging to the same document. In this case the query geometry contains the indexed polygon but the point is 
+    // inside the query as well, hence the result is 0.
+    XYPolygon polygonQuery = new XYPolygon(new float[] {4, 6, 6, 4, 4}, new float[] {4, 4, 6, 6, 4});
+    Query query = XYShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, polygonQuery);
+    assertEquals(0, searcher.count(query));
+
+    XYRectangle rectangle = new XYRectangle(4, 6, 4, 6);
+    query = XYShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, rectangle);
+    assertEquals(0, searcher.count(query));
+
+    XYCircle circle = new XYCircle(5, 5, 1);
+    query = XYShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, circle);
+    assertEquals(0, searcher.count(query));
+
+    IOUtils.close(w, reader, dir);
+  }
+
   private static boolean areBoxDisjoint(XYRectangle r1, XYRectangle r2) {
     return ( r1.minX <=  r2.minX &&  r1.minY <= r2.minY && r1.maxX >= r2.maxX && r1.maxY >= r2.maxY);
   }