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
of long tokens when discardCompoundToken is activated. (Jim Ferenczi)
* LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic.
(Ignacio Vera)
Other
---------------------

View File

@ -125,7 +125,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,

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}