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:
parent
cc83c2f848
commit
0dfc2169d7
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue