diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index af2539287..3829e5bca 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -7,6 +7,7 @@ New and noteworthy in the latest releases. == New in Spring Data Redis 1.8 * Support for Redis http://redis.io/commands#geo[GEO] commands. +* Support for Geospatial Indexes using Spring Data Repository abstractions (see <>). [[new-in-1.7.0]] == New in Spring Data Redis 1.7 diff --git a/src/main/asciidoc/reference/redis-repositories.adoc b/src/main/asciidoc/reference/redis-repositories.adoc index f339d36fd..6db528106 100644 --- a/src/main/asciidoc/reference/redis-repositories.adoc +++ b/src/main/asciidoc/reference/redis-repositories.adoc @@ -310,6 +310,7 @@ public class ApplicationConfig { == Secondary Indexes http://redis.io/topics/indexes[Secondary indexes] are used to enable lookup operations based on native Redis structures. Values are written to the according indexes on every save and are removed when objects are deleted or <>. +[[redis.repositories.indexes.simple]] === Simple Property Index Given the sample `Person` entity we can create an index for _firstname_ by annotating the property with `@Indexed`. @@ -421,9 +422,10 @@ public class ApplicationConfig { ---- ==== +[[redis.repositories.indexes.geospatial]] === Geospatial Index -Assume the `Address` type contains a property `location` of type `Point` that holds the geo coordinates of the particular address. By annotating the property with `@GeoIndexed` those values will be added using Redis `GEO` commands. +Assume the `Address` type contains a property `location` of type `Point` that holds the geo coordinates of the particular address. By annotating the property with `@GeoIndexed` those values will be added using Redis `GEO` commands. ==== [source,java] @@ -456,13 +458,13 @@ repository.save(rand); <3 repository.findByAddressLocationNear(new Point(15D, 37D), new Distance(200)); <4> ---- -<1> finder declaration on nested property using Point and Distance. -<2> finder declaration on nested property using Circle to search within. +<1> Query method declaration on nested property using Point and Distance. +<2> Query method declaration on nested property using Circle to search within. <3> `GEOADD persons:address:location 13.361389 38.115556 e2c7dcee-b8cd-4424-883e-736ce564363e` <4> `GEORADIUS persons:address:location 15.0 37.0 200.0 km` ==== -In the above example the lon/lat values are stored using `GEOADD` using the objects `id` as the members name. The finder methods allow usage of `Circle` or `Point, Distance` combinations for querying those values. +In the above example the lon/lat values are stored using `GEOADD` using the objects `id` as the member's name. The finder methods allow usage of `Circle` or `Point, Distance` combinations for querying those values. NOTE: It is **not** possible to combine `near`/`within` with other criteria. diff --git a/src/main/java/org/springframework/data/redis/core/IndexWriter.java b/src/main/java/org/springframework/data/redis/core/IndexWriter.java index 8b6d3cde2..18e584888 100644 --- a/src/main/java/org/springframework/data/redis/core/IndexWriter.java +++ b/src/main/java/org/springframework/data/redis/core/IndexWriter.java @@ -206,7 +206,7 @@ class IndexWriter { return; } - else if (indexedData instanceof SimpleIndexedPropertyValue) { + if (indexedData instanceof SimpleIndexedPropertyValue) { Object value = ((SimpleIndexedPropertyValue) indexedData).getValue(); @@ -234,9 +234,7 @@ class IndexWriter { // keep track of indexes used for the object connection.sAdd(ByteUtils.concatAll(toBytes(indexedData.getKeyspace() + ":"), key, toBytes(":idx")), indexKey); - } - - else { + } else { throw new IllegalArgumentException( String.format("Cannot write index data for unknown index type %s", indexedData.getClass())); } diff --git a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java index 194617b9a..ee136b3cc 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java @@ -516,9 +516,9 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter ? ByteUtils.concatAll(toBytes(redisUpdateObject.keyspace), toBytes((":" + path)), toBytes(":"), value) : null; if (connection.exists(existingValueIndexKey)) { - redisUpdateObject.addIndexToUpdate(new RedisUpdateObject.Index(existingValueIndexKey, DataType.SET)); } + return redisUpdateObject; } @@ -545,13 +545,11 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter } String pathToUse = GeoIndexedPropertyValue.geoIndexName(path); - if (connection.zRank(ByteUtils.concatAll(toBytes(redisUpdateObject.keyspace), toBytes(":"), toBytes(pathToUse)), - toBytes(redisUpdateObject.targetId)) != null) { + byte[] existingGeoIndexKey = ByteUtils.concatAll(toBytes(redisUpdateObject.keyspace), toBytes(":"), + toBytes(pathToUse)); - redisUpdateObject - .addIndexToUpdate(new org.springframework.data.redis.core.RedisKeyValueAdapter.RedisUpdateObject.Index( - ByteUtils.concatAll(toBytes(redisUpdateObject.keyspace), toBytes(":"), toBytes(pathToUse)), - DataType.ZSET)); + if (connection.zRank(existingGeoIndexKey, toBytes(redisUpdateObject.targetId)) != null) { + redisUpdateObject.addIndexToUpdate(new RedisUpdateObject.Index(existingGeoIndexKey, DataType.ZSET)); } return redisUpdateObject; diff --git a/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java b/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java index 95e81e196..684aa5a98 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java +++ b/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java @@ -90,18 +90,11 @@ class RedisQueryEngine extends QueryEngine> doInRedis(RedisConnection connection) throws DataAccessException { - String key = keyspace + ":"; - byte[][] keys = new byte[criteria.getSismember().size()][]; - int i = 0; - for (Object o : criteria.getSismember()) { - keys[i] = getAdapter().getConverter().getConversionService().convert(key + o, byte[].class); - i++; - } - List allKeys = new ArrayList(); if (!criteria.getSismember().isEmpty()) { allKeys.addAll(connection.sInter(keys(keyspace + ":", criteria.getSismember()))); } + if (!criteria.getOrSismember().isEmpty()) { allKeys.addAll(connection.sUnion(keys(keyspace + ":", criteria.getOrSismember()))); } @@ -229,5 +222,4 @@ class RedisQueryEngine extends QueryEngine sismember = new LinkedHashSet(); private Set orSismember = new LinkedHashSet(); - private NearPath near; public void sismember(String path, Object value) { @@ -163,5 +162,4 @@ public class RedisOperationChain { return (Distance) it.next(); } } - } diff --git a/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java b/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java index ba3b9b9fa..aa4b15f40 100644 --- a/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java +++ b/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java @@ -41,7 +41,6 @@ public class RedisQueryCreator extends AbstractQueryCreator