LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic (#2059)

This commit is contained in:
Ignacio Vera 2020-11-23 09:36:35 +01:00 committed by GitHub
parent a5d0654a24
commit 44be9f903d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 104 additions and 7 deletions

View File

@ -253,6 +253,9 @@ Bug Fixes
* LUCENE-9581: Japanese tokenizer should discard the compound token instead of disabling the decomposition * LUCENE-9581: Japanese tokenizer should discard the compound token instead of disabling the decomposition
of long tokens when discardCompoundToken is activated. (Jim Ferenczi) of long tokens when discardCompoundToken is activated. (Jim Ferenczi)
* LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic.
(Ignacio Vera)
Other Other
--------------------- ---------------------

View File

@ -125,7 +125,8 @@ final class LatLonShapeBoundingBoxQuery extends ShapeQuery {
switch (scratchTriangle.type) { switch (scratchTriangle.type) {
case POINT: { case POINT: {
return Component2D.WithinRelation.DISJOINT; return encodedRectangle.contains(scratchTriangle.aX, scratchTriangle.aY)
? Component2D.WithinRelation.NOTWITHIN : Component2D.WithinRelation.DISJOINT;
} }
case LINE: { case LINE: {
return encodedRectangle.withinLine(scratchTriangle.aX, scratchTriangle.aY, scratchTriangle.ab, return encodedRectangle.withinLine(scratchTriangle.aX, scratchTriangle.aY, scratchTriangle.ab,

View File

@ -110,7 +110,7 @@ class Circle2D implements Component2D {
@Override @Override
public WithinRelation withinPoint(double x, double y) { public WithinRelation withinPoint(double x, double y) {
return WithinRelation.DISJOINT; return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
} }
@Override @Override

View File

@ -129,13 +129,15 @@ final class Line2D implements Component2D {
@Override @Override
public WithinRelation withinPoint(double x, double y) { public WithinRelation withinPoint(double x, double y) {
return WithinRelation.DISJOINT; return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
} }
@Override @Override
public WithinRelation withinLine(double minX, double maxX, double minY, double maxY, public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
double aX, double aY, boolean ab, double bX, double bY) { 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; return WithinRelation.DISJOINT;
} }

View File

@ -181,7 +181,7 @@ final class Polygon2D implements Component2D {
@Override @Override
public WithinRelation withinPoint(double x, double y) { public WithinRelation withinPoint(double x, double y) {
return WithinRelation.DISJOINT; return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
} }
@Override @Override

View File

@ -118,13 +118,13 @@ final class Rectangle2D implements Component2D {
@Override @Override
public WithinRelation withinPoint(double x, double y) { public WithinRelation withinPoint(double x, double y) {
return WithinRelation.DISJOINT; return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
} }
@Override @Override
public WithinRelation withinLine(double minX, double maxX, double minY, double maxY, public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
double aX, double aY, boolean ab, double bX, double bY) { 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)) { edgesIntersect(aX, aY, bX, bY)) {
return WithinRelation.NOTWITHIN; return WithinRelation.NOTWITHIN;
} }

View File

@ -26,6 +26,7 @@ import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.geo.LatLonGeometry; import org.apache.lucene.geo.LatLonGeometry;
import org.apache.lucene.geo.Line; import org.apache.lucene.geo.Line;
import org.apache.lucene.geo.Polygon; import org.apache.lucene.geo.Polygon;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.geo.Tessellator; import org.apache.lucene.geo.Tessellator;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
@ -827,4 +828,49 @@ public class TestLatLonShape extends LuceneTestCase {
IOUtils.close(r, dir); 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);
}
} }

View File

@ -202,6 +202,51 @@ public class TestXYShape extends LuceneTestCase {
IOUtils.close(r, dir); 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) { 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); return ( r1.minX <= r2.minX && r1.minY <= r2.minY && r1.maxX >= r2.maxX && r1.maxY >= r2.maxY);
} }