From d1a7e583ad989d01e7ba3e08dc01da9d2e2da281 Mon Sep 17 00:00:00 2001 From: David Clement Date: Wed, 31 May 2017 10:51:52 +0200 Subject: [PATCH] Allows to index points, circles and boxes in PREFIX_TREE mapping in ES. Signed-off-by: David Clement --- docs/elasticsearch.txt | 2 +- docs/searchpredicates.txt | 2 +- .../diskstorage/es/ElasticSearchIndex.java | 124 ++++++++++-------- .../indexing/IndexProviderTest.java | 32 ++--- 4 files changed, 88 insertions(+), 72 deletions(-) diff --git a/docs/elasticsearch.txt b/docs/elasticsearch.txt index 6160bfd201..1ad7fa2f42 100644 --- a/docs/elasticsearch.txt +++ b/docs/elasticsearch.txt @@ -7,7 +7,7 @@ Elasticsearch is a distributed, RESTful search and analytics engine capable of s JanusGraph supports https://www.elastic.co/[Elasticsearch] as an index backend. Here are some of the Elasticsearch features supported by JanusGraph: * *Full-Text*: Supports all `Text` predicates to search for text properties that matches a given word, prefix or regular expression. -* *Geo*: Supports all `Geo` predicates to search for geo properties that are intersecting, within, disjoint to or contained in a given query geometry. Supports points, lines and polygons for indexing. Supports circles, boxes and polygons for querying point properties and all shapes for querying non-point properties. Note that JTS is required when using line and polygon shapes (see <> for more information). +* *Geo*: Supports all `Geo` predicates to search for geo properties that are intersecting, within, disjoint to or contained in a given query geometry. Supports points, circles, boxes, lines and polygons for indexing. Supports circles, boxes and polygons for querying point properties and all shapes for querying non-point properties. Note that JTS is required when using line and polygon shapes (see <> for more information). * *Numeric Range*: Supports all numeric comparisons in `Compare`. * *Flexible Configuration*: Supports embedded or remote operation, custom transport and discovery, and open-ended settings customization. * *TTL*: Supports automatically expiring indexed elements. diff --git a/docs/searchpredicates.txt b/docs/searchpredicates.txt index 5031601d78..ab886f9dea 100644 --- a/docs/searchpredicates.txt +++ b/docs/searchpredicates.txt @@ -92,7 +92,7 @@ Additional data types will be supported in the future. [[geoshape]] === Geoshape Data Type -The Geoshape data type supports representing a point, circle, box, line, polygon, multi-point, multi-line and multi-polygon. Index backends currently support indexing points, lines and polygons. Indexing multi-point, multi-line and multi-polygon properties has not been tested. +The Geoshape data type supports representing a point, circle, box, line, polygon, multi-point, multi-line and multi-polygon. Index backends currently support indexing points, circles, boxes, lines and polygons. Indexing multi-point, multi-line and multi-polygon properties has not been tested. Geospatial index lookups are only supported via mixed indexes. .Note: diff --git a/janusgraph-es/src/main/java/org/janusgraph/diskstorage/es/ElasticSearchIndex.java b/janusgraph-es/src/main/java/org/janusgraph/diskstorage/es/ElasticSearchIndex.java index 5ba241c844..1ed2b31d43 100644 --- a/janusgraph-es/src/main/java/org/janusgraph/diskstorage/es/ElasticSearchIndex.java +++ b/janusgraph-es/src/main/java/org/janusgraph/diskstorage/es/ElasticSearchIndex.java @@ -19,6 +19,7 @@ import com.google.common.collect.Iterators; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Multimap; +import com.spatial4j.core.shape.Rectangle; import org.apache.commons.lang.StringUtils; import org.elasticsearch.Version; import org.elasticsearch.common.geo.ShapeRelation; @@ -317,7 +318,7 @@ public void register(String store, String key, KeyInformation information, BaseT if (textAnalyzer != null) { mapping.field(ANALYZER, textAnalyzer); } - break; + break; case TEXTSTRING: if (textAnalyzer != null) { mapping.field(ANALYZER, textAnalyzer); @@ -422,11 +423,11 @@ public Map getNewDocument(final List additions, KeyI Object value = null; switch (keyInformation.getCardinality()) { case SINGLE: - value = convertToEsType(Iterators.getLast(add.getValue().iterator()).value); + value = convertToEsType(Iterators.getLast(add.getValue().iterator()).value, Mapping.getMapping(keyInformation)); break; case SET: case LIST: - value = add.getValue().stream().map(v -> convertToEsType(v.value)) + value = add.getValue().stream().map(v -> convertToEsType(v.value, Mapping.getMapping(keyInformation))) .filter(v -> { Preconditions.checkArgument(!(v instanceof byte[]), "Collections not supported for " + add.getKey()); return true; @@ -446,7 +447,7 @@ public Map getNewDocument(final List additions, KeyI return doc; } - private static Object convertToEsType(Object value) { + private static Object convertToEsType(Object value, Mapping mapping) { if (value instanceof Number) { if (AttributeUtil.isWholeNumber((Number) value)) { return ((Number) value).longValue(); @@ -456,7 +457,7 @@ private static Object convertToEsType(Object value) { } else if (AttributeUtil.isString(value)) { return value; } else if (value instanceof Geoshape) { - return convertgeo((Geoshape) value); + return convertgeo((Geoshape) value, mapping); } else if (value instanceof Date) { return value; } else if (value instanceof Instant) { @@ -468,18 +469,31 @@ private static Object convertToEsType(Object value) { } else throw new IllegalArgumentException("Unsupported type: " + value.getClass() + " (value: " + value + ")"); } - private static Object convertgeo(Geoshape geoshape) { - if (geoshape.getType() == Geoshape.Type.POINT) { + @SuppressWarnings("unchecked") + private static Object convertgeo(Geoshape geoshape, Mapping mapping) { + if (geoshape.getType() == Geoshape.Type.POINT && Mapping.PREFIX_TREE != mapping) { Geoshape.Point p = geoshape.getPoint(); return new double[]{p.getLongitude(), p.getLatitude()}; - } else if (geoshape.getType() != Geoshape.Type.BOX && geoshape.getType() != Geoshape.Type.CIRCLE) { + } else if (geoshape.getType() == Geoshape.Type.BOX) { + Rectangle box = geoshape.getShape().getBoundingBox(); + Map map = new HashMap<>(); + map.put("type", "envelope"); + map.put("coordinates", new double[][] {{box.getMinX(),box.getMaxY()},{box.getMaxX(),box.getMinY()}}); + return map; + } else if (geoshape.getType() == Geoshape.Type.CIRCLE) { try { - return geoshape.toMap(); + Map map = geoshape.toMap(); + map.put("radius", map.get("radius") + ((Map) map.remove("properties")).get("radius_units")); + return map; } catch (IOException e) { throw new IllegalArgumentException("Invalid geoshape: " + geoshape, e); } } else { - throw new IllegalArgumentException("Unsupported or invalid shape type for indexing: " + geoshape.getType()); + try { + return geoshape.toMap(); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid geoshape: " + geoshape, e); + } } } @@ -557,17 +571,17 @@ private String getDeletionScript(KeyInformation.IndexRetriever informations, Str switch (keyInformation.getCardinality()) { case SINGLE: - script.append("ctx._source.remove(\"" + deletion.field + "\");"); + script.append("ctx._source.remove(\"").append(deletion.field).append("\");"); if (hasDualStringMapping(informations.get(storename, deletion.field))) { - script.append("ctx._source.remove(\"" + getDualMappingName(deletion.field) + "\");"); + script.append("ctx._source.remove(\"").append(getDualMappingName(deletion.field)).append("\");"); } break; case SET: case LIST: - String jsValue = convertToJsType(deletion.value, scriptLang); - script.append("def index = ctx._source[\"" + deletion.field + "\"].indexOf(" + jsValue + "); ctx._source[\"" + deletion.field + "\"].remove(index);"); + String jsValue = convertToJsType(deletion.value, scriptLang, Mapping.getMapping(keyInformation)); + script.append("def index = ctx._source[\"").append(deletion.field).append("\"].indexOf(").append(jsValue).append("); ctx._source[\"").append(deletion.field).append("\"].remove(index);"); if (hasDualStringMapping(informations.get(storename, deletion.field))) { - script.append("def index = ctx._source[\"" + getDualMappingName(deletion.field) + "\"].indexOf(" + jsValue + "); ctx._source[\"" + getDualMappingName(deletion.field) + "\"].remove(index);"); + script.append("def index = ctx._source[\"").append(getDualMappingName(deletion.field)).append("\"].indexOf(").append(jsValue).append("); ctx._source[\"").append(getDualMappingName(deletion.field)).append("\"].remove(index);"); } break; @@ -583,11 +597,13 @@ private String getAdditionScript(KeyInformation.IndexRetriever informations, Str switch (keyInformation.getCardinality()) { case SET: case LIST: - script.append("ctx._source[\"" + e.field + "\"].add(" + convertToJsType(e.value, scriptLang) + ");"); + script.append("ctx._source[\"").append(e.field).append("\"].add(").append(convertToJsType(e.value, scriptLang, Mapping.getMapping(keyInformation))).append(");"); if (hasDualStringMapping(keyInformation)) { - script.append("ctx._source[\"" + getDualMappingName(e.field) + "\"].add(" + convertToJsType(e.value, scriptLang) + ");"); + script.append("ctx._source[\"").append(getDualMappingName(e.field)).append("\"].add(").append(convertToJsType(e.value, scriptLang, Mapping.getMapping(keyInformation))).append(");"); } break; + default: + break; } @@ -600,9 +616,9 @@ private Map getAdditionDoc(KeyInformation.IndexRetriever informat for (IndexEntry e : mutation.getAdditions()) { KeyInformation keyInformation = informations.get(storename).get(e.field); if (keyInformation.getCardinality() == Cardinality.SINGLE) { - doc.put(e.field, convertToEsType(e.value)); + doc.put(e.field, convertToEsType(e.value, Mapping.getMapping(keyInformation))); if (hasDualStringMapping(keyInformation)) { - doc.put(getDualMappingName(e.field), convertToEsType(e.value)); + doc.put(getDualMappingName(e.field), convertToEsType(e.value, Mapping.getMapping(keyInformation))); } } } @@ -610,11 +626,11 @@ private Map getAdditionDoc(KeyInformation.IndexRetriever informat return doc; } - private static String convertToJsType(Object value, String scriptLang) throws PermanentBackendException { + private static String convertToJsType(Object value, String scriptLang, Mapping mapping) throws PermanentBackendException { try { XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); - Object esValue = convertToEsType(value); + Object esValue = convertToEsType(value, mapping); if (esValue instanceof byte[]) { builder.rawField("value", new ByteArrayInputStream((byte[]) esValue)); } else { @@ -755,34 +771,34 @@ public QueryBuilder getFilter(Condition condition, KeyInformation.StoreRetrie Geoshape shape = (Geoshape) value; final ShapeBuilder sb; switch (shape.getType()) { - case CIRCLE: - Geoshape.Point center = shape.getPoint(); - sb = ShapeBuilder.newCircleBuilder().center(center.getLongitude(), center.getLatitude()).radius(shape.getRadius(), DistanceUnit.KILOMETERS); - break; - case BOX: - Geoshape.Point southwest = shape.getPoint(0); - Geoshape.Point northeast = shape.getPoint(1); - sb = ShapeBuilder.newEnvelope().bottomRight(northeast.getLongitude(),southwest.getLatitude()).topLeft(southwest.getLongitude(),northeast.getLatitude()); - break; - case LINE: - sb = ShapeBuilder.newLineString(); - IntStream.range(0, shape.size()).forEach(i -> { - Geoshape.Point point = shape.getPoint(i); - ((LineStringBuilder) sb).point(point.getLongitude(), point.getLatitude()); - }); - break; - case POLYGON: - sb = ShapeBuilder.newPolygon(); - IntStream.range(0, shape.size()).forEach(i -> { - Geoshape.Point point = shape.getPoint(i); - ((PolygonBuilder) sb).point(point.getLongitude(), point.getLatitude()); - }); - break; - case POINT: - sb = ShapeBuilder.newPoint(shape.getPoint().getLongitude(),shape.getPoint().getLatitude()); - break; - default: - throw new IllegalArgumentException("Unsupported or invalid search shape type: " + shape.getType()); + case CIRCLE: + Geoshape.Point center = shape.getPoint(); + sb = ShapeBuilder.newCircleBuilder().center(center.getLongitude(), center.getLatitude()).radius(shape.getRadius(), DistanceUnit.KILOMETERS); + break; + case BOX: + Geoshape.Point southwest = shape.getPoint(0); + Geoshape.Point northeast = shape.getPoint(1); + sb = ShapeBuilder.newEnvelope().bottomRight(northeast.getLongitude(),southwest.getLatitude()).topLeft(southwest.getLongitude(),northeast.getLatitude()); + break; + case LINE: + sb = ShapeBuilder.newLineString(); + IntStream.range(0, shape.size()).forEach(i -> { + Geoshape.Point point = shape.getPoint(i); + ((LineStringBuilder) sb).point(point.getLongitude(), point.getLatitude()); + }); + break; + case POLYGON: + sb = ShapeBuilder.newPolygon(); + IntStream.range(0, shape.size()).forEach(i -> { + Geoshape.Point point = shape.getPoint(i); + ((PolygonBuilder) sb).point(point.getLongitude(), point.getLatitude()); + }); + break; + case POINT: + sb = ShapeBuilder.newPoint(shape.getPoint().getLongitude(),shape.getPoint().getLatitude()); + break; + default: + throw new IllegalArgumentException("Unsupported or invalid search shape type: " + shape.getType()); } return QueryBuilders.geoShapeQuery(key, sb, SPATIAL_PREDICATES.get((Geo) janusgraphPredicate)); @@ -940,11 +956,11 @@ public boolean supports(KeyInformation information, JanusGraphPredicate janusgra if (janusgraphPredicate instanceof Cmp) return true; } else if (dataType == Geoshape.class) { switch(mapping) { - case DEFAULT: - return janusgraphPredicate instanceof Geo && janusgraphPredicate != Geo.CONTAINS; - case PREFIX_TREE: - return janusgraphPredicate instanceof Geo; - } + case DEFAULT: + return janusgraphPredicate instanceof Geo && janusgraphPredicate != Geo.CONTAINS; + case PREFIX_TREE: + return janusgraphPredicate instanceof Geo; + } } else if (AttributeUtil.isString(dataType)) { switch(mapping) { case DEFAULT: diff --git a/janusgraph-test/src/main/java/org/janusgraph/diskstorage/indexing/IndexProviderTest.java b/janusgraph-test/src/main/java/org/janusgraph/diskstorage/indexing/IndexProviderTest.java index e2594890ac..7f0ef43cc5 100644 --- a/janusgraph-test/src/main/java/org/janusgraph/diskstorage/indexing/IndexProviderTest.java +++ b/janusgraph-test/src/main/java/org/janusgraph/diskstorage/indexing/IndexProviderTest.java @@ -49,7 +49,7 @@ public abstract class IndexProviderTest { private static final Random random = new Random(); - private static final Parameter[] NO_PARAS = new Parameter[0]; + private static final Parameter[] NO_PARAS = new Parameter[0]; protected IndexProvider index; protected IndexFeatures indexFeatures; @@ -61,7 +61,7 @@ public abstract class IndexProviderTest { public static final String TEXT = "text", TIME = "time", WEIGHT = "weight", LOCATION = "location", BOUNDARY = "boundary", NAME = "name", PHONE_LIST = "phone_list", PHONE_SET = "phone_set", DATE = "date", STRING="string", ANALYZED="analyzed", FULL_TEXT="full_text", KEYWORD="keyword"; - public static StandardKeyInformation of(Class clazz, Cardinality cardinality, Parameter... paras) { + public static StandardKeyInformation of(Class clazz, Cardinality cardinality, Parameter... paras) { return new StandardKeyInformation(clazz, cardinality, paras); } @@ -191,7 +191,7 @@ private void storeTest(String... stores) throws Exception { Multimap doc1 = getDocument("Hello world", 1001, 5.2, Geoshape.point(48.0, 0.0), Geoshape.polygon(Arrays.asList(new double[][] {{-0.1,47.9},{0.1,47.9},{0.1,48.1},{-0.1,48.1},{-0.1,47.9}})),Arrays.asList("1", "2", "3"), Sets.newHashSet("1", "2"), Instant.ofEpochSecond(1)); Multimap doc2 = getDocument("Tomorrow is the world", 1010, 8.5, Geoshape.point(49.0, 1.0), Geoshape.line(Arrays.asList(new double[][] {{0.9,48.9},{0.9,49.1},{1.1,49.1},{1.1,48.9}})), Arrays.asList("4", "5", "6"), Sets.newHashSet("4", "5"), Instant.ofEpochSecond(2)); - Multimap doc3 = getDocument("Hello Bob, are you there?", -500, 10.1, Geoshape.point(47.0, 10.0), Geoshape.polygon(Arrays.asList(new double[][] {{9.9,46.9},{10.1,46.9},{10.1,47.1},{9.9,47.1},{9.9,46.9}})), Arrays.asList("7", "8", "9"), Sets.newHashSet("7", "8"), Instant.ofEpochSecond(3)); + Multimap doc3 = getDocument("Hello Bob, are you there?", -500, 10.1, Geoshape.point(47.0, 10.0), Geoshape.box(46.9, 9.9, 47.1, 10.1), Arrays.asList("7", "8", "9"), Sets.newHashSet("7", "8"), Instant.ofEpochSecond(3)); for (String store : stores) { initialize(store); @@ -275,7 +275,7 @@ private void storeTest(String... stores) throws Exception { assertEquals(0, tx.query(new IndexQuery(store, PredicateCondition.of(NAME, Text.REGEX, "Tomorrow"))).size()); } - if (index.supports(new StandardKeyInformation(String.class, Cardinality.SINGLE, new Parameter("mapping", Mapping.STRING)), Text.REGEX)) { + if (index.supports(new StandardKeyInformation(String.class, Cardinality.SINGLE, Mapping.STRING.asParameter()), Text.REGEX)) { assertEquals(1, tx.query(new IndexQuery(store, PredicateCondition.of(NAME, Text.REGEX, "Tomo[r]+ow is.*world"))).size()); assertEquals(0, tx.query(new IndexQuery(store, PredicateCondition.of(NAME, Text.REGEX, "Tomorrow"))).size()); } @@ -340,7 +340,7 @@ private void storeTest(String... stores) throws Exception { assertEquals(2, result.size()); assertEquals(ImmutableSet.of("doc1","doc2"), ImmutableSet.copyOf(result)); - if (index.supports(new StandardKeyInformation(Geoshape.class, Cardinality.SINGLE, new Parameter("mapping", Mapping.PREFIX_TREE)), Geo.DISJOINT)) { + if (index.supports(new StandardKeyInformation(Geoshape.class, Cardinality.SINGLE, Mapping.PREFIX_TREE.asParameter()), Geo.DISJOINT)) { result = tx.query(new IndexQuery(store, PredicateCondition.of(BOUNDARY, Geo.DISJOINT, Geoshape.box(46.5, -0.5, 50.5, 10.5)))); assertEquals(0,result.size()); @@ -397,7 +397,7 @@ private void storeTest(String... stores) throws Exception { assertEquals(1, Iterables.size(tx.query(new RawQuery(store,"name:\"Hello world\"",NO_PARAS)))); } - if (index.supports(new StandardKeyInformation(String.class, Cardinality.LIST, new Parameter("mapping", Mapping.STRING)), Cmp.EQUAL)) { + if (index.supports(new StandardKeyInformation(String.class, Cardinality.LIST, Mapping.STRING.asParameter()), Cmp.EQUAL)) { assertEquals("doc1", tx.query(new IndexQuery(store, PredicateCondition.of(PHONE_LIST, Cmp.EQUAL, "1"))).get(0)); assertEquals("doc1", tx.query(new IndexQuery(store, PredicateCondition.of(PHONE_LIST, Cmp.EQUAL, "2"))).get(0)); assertEquals("doc2", tx.query(new IndexQuery(store, PredicateCondition.of(PHONE_LIST, Cmp.EQUAL, "4"))).get(0)); @@ -424,12 +424,12 @@ private void storeTest(String... stores) throws Exception { //Update some data - add(store, "doc4", getDocument("I'ts all a big Bob", -100, 11.2, Geoshape.point(48.0, 8.0), Geoshape.line(Arrays.asList(new double[][] {{7.5, 47.5}, {8.5, 48.5}})), Arrays.asList("10", "11", "12"), Sets.newHashSet("10", "11"), Instant.ofEpochSecond(4)), true); + add(store, "doc4", getDocument("I'ts all a big Bob", -100, 11.2, Geoshape.point(-48.0, 8.0), Geoshape.point(-48.0, 8.0), Arrays.asList("10", "11", "12"), Sets.newHashSet("10", "11"), Instant.ofEpochSecond(4)), true); remove(store, "doc2", doc2, true); - remove(store, "doc3", ImmutableMultimap.of(WEIGHT, (Object) 10.1), false); - add(store, "doc3", ImmutableMultimap.of(TIME, (Object) 2000, TEXT, "Bob owns the world"), false); + remove(store, "doc3", ImmutableMultimap.of(WEIGHT, 10.1), false); + add(store, "doc3", ImmutableMultimap.of(TIME, 2000, TEXT, "Bob owns the world"), false); remove(store, "doc1", ImmutableMultimap.of(TIME, (Object) 1001), false); - add(store, "doc1", ImmutableMultimap.of(TIME, (Object) 1005, WEIGHT, 11.1), false); + add(store, "doc1", ImmutableMultimap.of(TIME, 1005, WEIGHT, 11.1, LOCATION, Geoshape.point(-48.0, 0.0), BOUNDARY, Geoshape.circle(-48.0, 0.0, 1.0)), false); } @@ -445,22 +445,22 @@ private void storeTest(String... stores) throws Exception { assertEquals(1, result.size()); assertEquals("doc1", result.get(0)); - result = tx.query(new IndexQuery(store, PredicateCondition.of(LOCATION, Geo.WITHIN, Geoshape.circle(48.5, 0.5, 200.00)))); + result = tx.query(new IndexQuery(store, PredicateCondition.of(LOCATION, Geo.WITHIN, Geoshape.circle(-48.5, 0.5, 200.00)))); assertEquals(ImmutableSet.of("doc1"), ImmutableSet.copyOf(result)); - result = tx.query(new IndexQuery(store, PredicateCondition.of(BOUNDARY, Geo.WITHIN, Geoshape.circle(48.5, 0.5, 200.00)))); + result = tx.query(new IndexQuery(store, PredicateCondition.of(BOUNDARY, Geo.WITHIN, Geoshape.circle(-48.5, 0.5, 200.00)))); assertEquals(ImmutableSet.of("doc1"), ImmutableSet.copyOf(result)); - result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TEXT, Text.CONTAINS, "tomorrow"), PredicateCondition.of(LOCATION, Geo.WITHIN, Geoshape.circle(48.5, 0.5, 200.00))))); + result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TEXT, Text.CONTAINS, "tomorrow"), PredicateCondition.of(LOCATION, Geo.WITHIN, Geoshape.circle(-48.5, 0.5, 200.00))))); assertEquals(ImmutableSet.of(), ImmutableSet.copyOf(result)); - result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TEXT, Text.CONTAINS, "tomorrow"), PredicateCondition.of(BOUNDARY, Geo.WITHIN, Geoshape.circle(48.5, 0.5, 200.00))))); + result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TEXT, Text.CONTAINS, "tomorrow"), PredicateCondition.of(BOUNDARY, Geo.WITHIN, Geoshape.circle(-48.5, 0.5, 200.00))))); assertEquals(ImmutableSet.of(), ImmutableSet.copyOf(result)); - result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TIME, Cmp.GREATER_THAN_EQUAL, -1000), PredicateCondition.of(TIME, Cmp.LESS_THAN, 1010), PredicateCondition.of(LOCATION, Geo.WITHIN, Geoshape.circle(48.5, 0.5, 1000.00))))); + result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TIME, Cmp.GREATER_THAN_EQUAL, -1000), PredicateCondition.of(TIME, Cmp.LESS_THAN, 1010), PredicateCondition.of(LOCATION, Geo.WITHIN, Geoshape.circle(-48.5, 0.5, 1000.00))))); assertEquals(ImmutableSet.of("doc1", "doc4"), ImmutableSet.copyOf(result)); - result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TIME, Cmp.GREATER_THAN_EQUAL, -1000), PredicateCondition.of(TIME, Cmp.LESS_THAN, 1010), PredicateCondition.of(BOUNDARY, Geo.WITHIN, Geoshape.circle(48.5, 0.5, 1000.00))))); + result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(TIME, Cmp.GREATER_THAN_EQUAL, -1000), PredicateCondition.of(TIME, Cmp.LESS_THAN, 1010), PredicateCondition.of(BOUNDARY, Geo.WITHIN, Geoshape.circle(-48.5, 0.5, 1000.00))))); assertEquals(ImmutableSet.of("doc1", "doc4"), ImmutableSet.copyOf(result)); result = tx.query(new IndexQuery(store, And.of(PredicateCondition.of(WEIGHT, Cmp.GREATER_THAN, 10.0))));