Added Testcase and BugFix fixing #2626 where GeoShape intersects filter omitted matching docs.

SpatialPrefixTree#recursiveGetNodes uses an optimization that prevents
recursion into the deepest tree level if a parent node in the penultimate
level covers all its children.  This produces a bug if the optimization
happens both at indexing and at query/filter time.

This patch fixes the bug by disabling the optimization at indexing time
(to avoid adding overhead for query-heavy workloads).

See LUCENE-4770 for reference
This commit is contained in:
Jeffrey Gerard 2013-02-06 13:04:50 -08:00 committed by Simon Willnauer
parent cc83c2f848
commit 0dfc2169d7
2 changed files with 49 additions and 4 deletions

View File

@ -153,16 +153,19 @@ public abstract class SpatialPrefixTree {
}
final Collection<Node> subCells = node.getSubCells(shape);
if (node.getLevel() == detailLevel - 1) {
if (subCells.size() < node.getSubCellsSize()) {
if (subCells.size() == node.getSubCellsSize() && !inclParents) {
// A bottom level (i.e. detail level) optimization where all boxes intersect, so use parent cell.
// Can optimize at only one of index time or query/filter time; the !inclParents
// condition above means we do not optimize at index time.
node.setLeaf();
result.add(node);
} else {
if (inclParents)
result.add(node);
for (Node subCell : subCells) {
subCell.setLeaf();
}
result.addAll(subCells);
} else {//a bottom level (i.e. detail level) optimization where all boxes intersect, so use parent cell.
node.setLeaf();
result.add(node);
}
} else {
if (inclParents) {

View File

@ -110,6 +110,48 @@ public class GeoShapeIntegrationTests extends AbstractNodesTests {
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1"));
}
@Test
public void testEdgeCases() throws Exception {
client.admin().indices().prepareDelete().execute().actionGet();
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type1")
.startObject("properties").startObject("location")
.field("type", "geo_shape")
.field("tree", "quadtree")
.endObject().endObject()
.endObject().endObject().string();
client.admin().indices().prepareCreate("test").addMapping("type1", mapping).execute().actionGet();
client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet();
client.prepareIndex("test", "type1", "blakely").setSource(jsonBuilder().startObject()
.field("name", "Blakely Island")
.startObject("location")
.field("type", "polygon")
.startArray("coordinates").startArray()
.startArray().value(-122.83).value(48.57).endArray()
.startArray().value(-122.77).value(48.56).endArray()
.startArray().value(-122.79).value(48.53).endArray()
.startArray().value(-122.83).value(48.57).endArray() // close the polygon
.endArray().endArray()
.endObject()
.endObject()).execute().actionGet();
client.admin().indices().prepareRefresh().execute().actionGet();
Shape query = newRectangle().topLeft(-122.88, 48.62).bottomRight(-122.82, 48.54).build();
// This search would fail if both geoshape indexing and geoshape filtering
// used the bottom-level optimization in SpatialPrefixTree#recursiveGetNodes.
SearchResponse searchResponse = client.prepareSearch()
.setQuery(filteredQuery(matchAllQuery(),
geoShapeFilter("location", query).relation(ShapeRelation.INTERSECTS)))
.execute().actionGet();
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
assertThat(searchResponse.hits().hits().length, equalTo(1));
assertThat(searchResponse.hits().getAt(0).id(), equalTo("blakely"));
}
@Test
public void testIndexedShapeReference() throws Exception {
client.admin().indices().prepareDelete().execute().actionGet();