From 105d60ac9c28b1be4ab1e8d04a39c13cf9641c18 Mon Sep 17 00:00:00 2001 From: kimchy Date: Mon, 4 Apr 2011 17:44:38 +0300 Subject: [PATCH] Geo Distance / Range Facets might count documents several times for a range entry if the field is multi valued, closes #824. --- .../xcontent/geo/GeoPointFieldData.java | 6 ++ .../geo/MultiValueGeoPointFieldData.java | 9 ++ .../geo/SingleValueGeoPointFieldData.java | 8 ++ .../facet/geodistance/GeoDistanceFacet.java | 5 + .../GeoDistanceFacetCollector.java | 57 +++++++---- .../ScriptGeoDistanceFacetCollector.java | 59 +++++++----- .../ValueGeoDistanceFacetCollector.java | 68 +++++++------ .../range/KeyValueRangeFacetCollector.java | 95 +++++++++---------- .../search/facet/range/RangeFacet.java | 5 + .../facet/range/RangeFacetCollector.java | 7 ++ .../search/facet/SimpleFacetsTests.java | 4 +- .../search/geo/GeoDistanceFacetTests.java | 60 ++++++++++++ 12 files changed, 254 insertions(+), 129 deletions(-) diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/GeoPointFieldData.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/GeoPointFieldData.java index fb553110f73..7ac78ddcb8c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/GeoPointFieldData.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/GeoPointFieldData.java @@ -142,6 +142,12 @@ public abstract class GeoPointFieldData extends FieldData void onValue(double lat, double lon); } + public abstract void forEachValueInDoc(int docId, ValueInDocProc proc); + + public static interface ValueInDocProc { + void onValue(int docId, double lat, double lon); + } + public static GeoPointFieldData load(IndexReader reader, String field) throws IOException { return FieldDataLoader.load(reader, field, new StringTypeLoader()); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/MultiValueGeoPointFieldData.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/MultiValueGeoPointFieldData.java index 73d69bdde4d..739c816b0c8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/MultiValueGeoPointFieldData.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/MultiValueGeoPointFieldData.java @@ -108,6 +108,15 @@ public class MultiValueGeoPointFieldData extends GeoPointFieldData { } } + @Override public void forEachValueInDoc(int docId, ValueInDocProc proc) { + for (int[] ordinal : ordinals) { + int loc = ordinal[docId]; + if (loc != 0) { + proc.onValue(docId, lat[loc], lon[loc]); + } + } + } + @Override public void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc) { for (int[] ordinal : ordinals) { proc.onOrdinal(docId, ordinal[docId]); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/SingleValueGeoPointFieldData.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/SingleValueGeoPointFieldData.java index a3e88655ab6..25d00a68c1d 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/SingleValueGeoPointFieldData.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/geo/SingleValueGeoPointFieldData.java @@ -84,6 +84,14 @@ public class SingleValueGeoPointFieldData extends GeoPointFieldData { proc.onOrdinal(docId, ordinals[docId]); } + @Override public void forEachValueInDoc(int docId, ValueInDocProc proc) { + int loc = ordinals[docId]; + if (loc == 0) { + return; + } + proc.onValue(docId, lat[loc], lon[loc]); + } + @Override public GeoPoint value(int docId) { int loc = ordinals[docId]; if (loc == 0) { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/GeoDistanceFacet.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/GeoDistanceFacet.java index b706b572f80..a8d8ce066ef 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/GeoDistanceFacet.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/GeoDistanceFacet.java @@ -53,6 +53,11 @@ public interface GeoDistanceFacet extends Facet, Iterable= entry.getFrom() && distance < entry.getTo()) { - entry.count++; - entry.total += distance; - } - } - } - } else { - double distance = geoDistance.calculate(lat, lon, fieldData.latValue(doc), fieldData.lonValue(doc), unit); + @Override public void onValue(int docId, double lat, double lon) { + double distance = geoDistance.calculate(this.lat, this.lon, lat, lon, unit); for (GeoDistanceFacet.Entry entry : entries) { + if (entry.foundInDoc) { + continue; + } if (distance >= entry.getFrom() && distance < entry.getTo()) { + entry.foundInDoc = true; entry.count++; entry.total += distance; } } } } - - @Override public Facet facet() { - return new InternalGeoDistanceFacet(facetName, entries); - } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ScriptGeoDistanceFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ScriptGeoDistanceFacetCollector.java index 6799abbec9b..969d7e4830c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ScriptGeoDistanceFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ScriptGeoDistanceFacetCollector.java @@ -22,7 +22,7 @@ package org.elasticsearch.search.facet.geodistance; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.Scorer; import org.elasticsearch.common.unit.DistanceUnit; -import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint; +import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData; import org.elasticsearch.index.search.geo.GeoDistance; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.internal.SearchContext; @@ -37,12 +37,16 @@ public class ScriptGeoDistanceFacetCollector extends GeoDistanceFacetCollector { private final SearchScript script; + private Aggregator scriptAggregator; + public ScriptGeoDistanceFacetCollector(String facetName, String fieldName, double lat, double lon, DistanceUnit unit, GeoDistance geoDistance, GeoDistanceFacet.Entry[] entries, SearchContext context, String scriptLang, String script, Map params) { super(facetName, fieldName, lat, lon, unit, geoDistance, entries, context); this.script = context.scriptService().search(context.lookup(), scriptLang, script, params); + this.aggregator = new Aggregator(lat, lon, geoDistance, unit, entries); + this.scriptAggregator = (Aggregator) this.aggregator; } @Override public void setScorer(Scorer scorer) throws IOException { @@ -55,32 +59,43 @@ public class ScriptGeoDistanceFacetCollector extends GeoDistanceFacetCollector { } @Override protected void doCollect(int doc) throws IOException { - if (!fieldData.hasValue(doc)) { - return; + script.setNextDocId(doc); + this.scriptAggregator.scriptValue = script.runAsDouble(); + super.doCollect(doc); + } + + public static class Aggregator implements GeoPointFieldData.ValueInDocProc { + + protected final double lat; + + protected final double lon; + + private final GeoDistance geoDistance; + + private final DistanceUnit unit; + + private final GeoDistanceFacet.Entry[] entries; + + double scriptValue; + + public Aggregator(double lat, double lon, GeoDistance geoDistance, DistanceUnit unit, GeoDistanceFacet.Entry[] entries) { + this.lat = lat; + this.lon = lon; + this.geoDistance = geoDistance; + this.unit = unit; + this.entries = entries; } - script.setNextDocId(doc); - - double value = script.runAsDouble(); - - if (fieldData.multiValued()) { - GeoPoint[] points = fieldData.values(doc); - for (GeoPoint point : points) { - double distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit); - for (GeoDistanceFacet.Entry entry : entries) { - if (distance >= entry.getFrom() && distance < entry.getTo()) { - entry.count++; - entry.total += value; - } - } - } - } else { - GeoPoint point = fieldData.value(doc); - double distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit); + @Override public void onValue(int docId, double lat, double lon) { + double distance = geoDistance.calculate(this.lat, this.lon, lat, lon, unit); for (GeoDistanceFacet.Entry entry : entries) { + if (entry.foundInDoc) { + continue; + } if (distance >= entry.getFrom() && distance < entry.getTo()) { + entry.foundInDoc = true; entry.count++; - entry.total += value; + entry.total += scriptValue; } } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ValueGeoDistanceFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ValueGeoDistanceFacetCollector.java index 9466e7274b6..0f53294e9e9 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ValueGeoDistanceFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/geodistance/ValueGeoDistanceFacetCollector.java @@ -24,9 +24,8 @@ import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.index.field.data.FieldDataType; import org.elasticsearch.index.field.data.NumericFieldData; import org.elasticsearch.index.mapper.FieldMapper; -import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint; +import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData; import org.elasticsearch.index.search.geo.GeoDistance; -import org.elasticsearch.search.facet.Facet; import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.internal.SearchContext; @@ -41,8 +40,6 @@ public class ValueGeoDistanceFacetCollector extends GeoDistanceFacetCollector { private final FieldDataType valueFieldDataType; - private NumericFieldData valueFieldData; - public ValueGeoDistanceFacetCollector(String facetName, String fieldName, double lat, double lon, DistanceUnit unit, GeoDistance geoDistance, GeoDistanceFacet.Entry[] entries, SearchContext context, String valueFieldName) { super(facetName, fieldName, lat, lon, unit, geoDistance, entries, context); @@ -53,56 +50,55 @@ public class ValueGeoDistanceFacetCollector extends GeoDistanceFacetCollector { } this.indexValueFieldName = valueFieldName; this.valueFieldDataType = mapper.fieldDataType(); + this.aggregator = new Aggregator(lat, lon, geoDistance, unit, entries); } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { super.doSetNextReader(reader, docBase); - valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, reader, indexValueFieldName); + ((Aggregator) this.aggregator).valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, reader, indexValueFieldName); } - @Override protected void doCollect(int doc) throws IOException { - if (!fieldData.hasValue(doc)) { - return; + public static class Aggregator implements GeoPointFieldData.ValueInDocProc { + + protected final double lat; + + protected final double lon; + + private final GeoDistance geoDistance; + + private final DistanceUnit unit; + + private final GeoDistanceFacet.Entry[] entries; + + NumericFieldData valueFieldData; + + public Aggregator(double lat, double lon, GeoDistance geoDistance, DistanceUnit unit, GeoDistanceFacet.Entry[] entries) { + this.lat = lat; + this.lon = lon; + this.geoDistance = geoDistance; + this.unit = unit; + this.entries = entries; } - if (fieldData.multiValued()) { - GeoPoint[] points = fieldData.values(doc); - double[] values = valueFieldData.multiValued() ? valueFieldData.doubleValues(doc) : null; - for (int i = 0; i < points.length; i++) { - double distance = geoDistance.calculate(lat, lon, points[i].lat(), points[i].lon(), unit); - for (GeoDistanceFacet.Entry entry : entries) { - if (distance >= entry.getFrom() && distance < entry.getTo()) { - entry.count++; - if (values != null) { - if (i < values.length) { - entry.total += values[i]; - } - } else if (valueFieldData.hasValue(doc)) { - entry.total += valueFieldData.doubleValue(doc); - } - } - } - } - } else { - GeoPoint point = fieldData.value(doc); - double distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit); + @Override public void onValue(int docId, double lat, double lon) { + double distance = geoDistance.calculate(this.lat, this.lon, lat, lon, unit); for (GeoDistanceFacet.Entry entry : entries) { + if (entry.foundInDoc) { + continue; + } if (distance >= entry.getFrom() && distance < entry.getTo()) { + entry.foundInDoc = true; entry.count++; if (valueFieldData.multiValued()) { - double[] values = valueFieldData.doubleValues(doc); + double[] values = valueFieldData.doubleValues(docId); for (double value : values) { entry.total += value; } - } else if (valueFieldData.hasValue(doc)) { - entry.total += valueFieldData.doubleValue(doc); + } else if (valueFieldData.hasValue(docId)) { + entry.total += valueFieldData.doubleValue(docId); } } } } } - - @Override public Facet facet() { - return new InternalGeoDistanceFacet(facetName, entries); - } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/KeyValueRangeFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/KeyValueRangeFacetCollector.java index e9192a8e462..c0847e6e47f 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/KeyValueRangeFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/KeyValueRangeFacetCollector.java @@ -51,6 +51,8 @@ public class KeyValueRangeFacetCollector extends AbstractFacetCollector { private final RangeFacet.Entry[] entries; + private final RangeProc rangeProc; + public KeyValueRangeFacetCollector(String facetName, String keyFieldName, String valueFieldName, RangeFacet.Entry[] entries, SearchContext context) { super(facetName); this.entries = entries; @@ -75,66 +77,61 @@ public class KeyValueRangeFacetCollector extends AbstractFacetCollector { } valueIndexFieldName = mapper.names().indexName(); valueFieldDataType = mapper.fieldDataType(); + + this.rangeProc = new RangeProc(entries); } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { keyFieldData = (NumericFieldData) fieldDataCache.cache(keyFieldDataType, reader, keyIndexFieldName); - valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, reader, valueIndexFieldName); + rangeProc.valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, reader, valueIndexFieldName); } @Override protected void doCollect(int doc) throws IOException { - if (keyFieldData.multiValued()) { - if (valueFieldData.multiValued()) { - // both multi valued, intersect based on the minimum size - double[] keys = keyFieldData.doubleValues(doc); - double[] values = valueFieldData.doubleValues(doc); - int size = Math.min(keys.length, values.length); - for (int i = 0; i < size; i++) { - double key = keys[i]; - for (RangeFacet.Entry entry : entries) { - if (key >= entry.getFrom() && key < entry.getTo()) { - entry.count++; - entry.total += values[i]; - } - } - } - } else { - // key multi valued, value is a single value - double value = valueFieldData.doubleValue(doc); - for (double key : keyFieldData.doubleValues(doc)) { - for (RangeFacet.Entry entry : entries) { - if (key >= entry.getFrom() && key < entry.getTo()) { - entry.count++; - entry.total += value; - } - } - } - } - } else { - double key = keyFieldData.doubleValue(doc); - if (valueFieldData.multiValued()) { - for (RangeFacet.Entry entry : entries) { - if (key >= entry.getFrom() && key < entry.getTo()) { - entry.count++; - for (double value : valueFieldData.doubleValues(doc)) { - entry.total += value; - } - } - } - } else { - // both key and value are not multi valued - double value = valueFieldData.doubleValue(doc); - for (RangeFacet.Entry entry : entries) { - if (key >= entry.getFrom() && key < entry.getTo()) { - entry.count++; - entry.total += value; - } - } - } + for (RangeFacet.Entry entry : entries) { + entry.foundInDoc = false; } + keyFieldData.forEachValueInDoc(doc, rangeProc); } @Override public Facet facet() { return new InternalRangeFacet(facetName, entries); } + + public static class RangeProc implements NumericFieldData.DoubleValueInDocProc { + + private final RangeFacet.Entry[] entries; + + private int missing; + + NumericFieldData valueFieldData; + + public RangeProc(RangeFacet.Entry[] entries) { + this.entries = entries; + } + + @Override public void onValue(int docId, double value) { + for (RangeFacet.Entry entry : entries) { + if (entry.foundInDoc) { + continue; + } + if (value >= entry.getFrom() && value < entry.getTo()) { + entry.foundInDoc = true; + entry.count++; + if (valueFieldData.multiValued()) { + double[] valuesValues = valueFieldData.doubleValues(docId); + for (double valueValue : valuesValues) { + entry.total += valueValue; + } + } else { + double valueValue = valueFieldData.doubleValue(docId); + entry.total += valueValue; + } + } + } + } + + @Override public void onMissing(int docId) { + missing++; + } + } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacet.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacet.java index 4aaf18b632d..c667927871a 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacet.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacet.java @@ -57,6 +57,11 @@ public interface RangeFacet extends Facet, Iterable { double total; + /** + * Internal field used in facet collection + */ + boolean foundInDoc; + Entry() { } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacetCollector.java index ff4638e4028..b447e3e3dc8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/range/RangeFacetCollector.java @@ -74,6 +74,9 @@ public class RangeFacetCollector extends AbstractFacetCollector { } @Override protected void doCollect(int doc) throws IOException { + for (RangeFacet.Entry entry : entries) { + entry.foundInDoc = false; + } fieldData.forEachValueInDoc(doc, rangeProc); } @@ -93,7 +96,11 @@ public class RangeFacetCollector extends AbstractFacetCollector { @Override public void onValue(int docId, double value) { for (RangeFacet.Entry entry : entries) { + if (entry.foundInDoc) { + continue; + } if (value >= entry.getFrom() && value < entry.getTo()) { + entry.foundInDoc = true; entry.count++; entry.total += value; } diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java index 76185606b6d..08db3f202d7 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java @@ -1147,8 +1147,8 @@ public class SimpleFacetsTests extends AbstractNodesTests { assertThat(facet.entries().get(0).total(), closeTo(3, 0.000001)); assertThat(facet.entries().get(1).from(), closeTo(10, 0.000001)); assertThat(facet.entries().get(1).to(), closeTo(26, 0.000001)); - assertThat(facet.entries().get(1).count(), equalTo(5l)); - assertThat(facet.entries().get(1).total(), closeTo(1 * 2 + 2 + 3 * 2, 0.000001)); + assertThat(facet.entries().get(1).count(), equalTo(3l)); + assertThat(facet.entries().get(1).total(), closeTo(1 + 2 + 3, 0.000001)); assertThat(facet.entries().get(2).from(), closeTo(20, 0.000001)); assertThat(facet.entries().get(2).count(), equalTo(3l)); assertThat(facet.entries().get(2).total(), closeTo(1 + 2 + 3, 0.000001)); diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/geo/GeoDistanceFacetTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/geo/GeoDistanceFacetTests.java index e4c6b8da75f..6d05783a688 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/geo/GeoDistanceFacetTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/geo/GeoDistanceFacetTests.java @@ -29,6 +29,8 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.Arrays; + import static org.elasticsearch.common.xcontent.XContentFactory.*; import static org.elasticsearch.index.query.xcontent.QueryBuilders.*; import static org.elasticsearch.search.facet.FacetBuilders.*; @@ -217,4 +219,62 @@ public class GeoDistanceFacetTests extends AbstractNodesTests { assertThat(facet.entries().get(3).count(), equalTo(5l)); assertThat(facet.entries().get(3).total(), closeTo(24, 0.00001)); } + + @Test public void multiLocationGeoDistanceTest() throws Exception { + try { + client.admin().indices().prepareDelete("test").execute().actionGet(); + } catch (Exception e) { + // ignore + } + String mapping = XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location").field("type", "geo_point").field("lat_lon", true).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", "1").setSource(jsonBuilder().startObject() + .field("num", 1) + .startArray("location") + // to NY: 0 + .startObject().field("lat", 40.7143528).field("lon", -74.0059731).endObject() + // to NY: 5.286 km + .startObject().field("lat", 40.759011).field("lon", -73.9844722).endObject() + .endArray() + .endObject()).execute().actionGet(); + + client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject() + .field("num", 3) + .startArray("location") + // to NY: 0.4621 km + .startObject().field("lat", 40.718266).field("lon", -74.007819).endObject() + // to NY: 1.055 km + .startObject().field("lat", 40.7051157).field("lon", -74.0088305).endObject() + .endArray() + .endObject()).execute().actionGet(); + + + client.admin().indices().prepareRefresh().execute().actionGet(); + + SearchResponse searchResponse = client.prepareSearch() // from NY + .setQuery(matchAllQuery()) + .addFacet(geoDistanceFacet("geo1").field("location").point(40.7143528, -74.0059731).unit(DistanceUnit.KILOMETERS) + .addRange(0, 2) + .addRange(2, 10) + ) + .execute().actionGet(); + + assertThat(Arrays.toString(searchResponse.shardFailures()), searchResponse.failedShards(), equalTo(0)); + + assertThat(searchResponse.hits().totalHits(), equalTo(2l)); + GeoDistanceFacet facet = searchResponse.facets().facet("geo1"); + assertThat(facet.entries().size(), equalTo(2)); + + assertThat(facet.entries().get(0).from(), closeTo(0, 0.000001)); + assertThat(facet.entries().get(0).to(), closeTo(2, 0.000001)); + assertThat(facet.entries().get(0).count(), equalTo(2l)); + + assertThat(facet.entries().get(1).from(), closeTo(2, 0.000001)); + assertThat(facet.entries().get(1).to(), closeTo(10, 0.000001)); + assertThat(facet.entries().get(1).count(), equalTo(1l)); + } }