DATAREDIS-438 - Add support for geo commands.

Original Pulll Request: #187
CLA: 169220160326121428 (Ninad Divadkar)
This commit is contained in:
Ninad Divadkar
2016-03-27 14:58:18 -07:00
committed by Christoph Strobl
parent 83359a9c4f
commit b0e20d3da8
32 changed files with 5494 additions and 2747 deletions

View File

@@ -15,16 +15,8 @@
*/
package org.springframework.data.redis.connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -33,9 +25,7 @@ import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.convert.ListConverter;
import org.springframework.data.redis.connection.convert.MapConverter;
import org.springframework.data.redis.connection.convert.SetConverter;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.serializer.RedisSerializer;
@@ -280,7 +270,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
delegate.flushDb();
}
public byte[] get(byte[] key) {
public byte[] get(byte[] key) {
byte[] result = delegate.get(key);
if (isFutureConversion()) {
addResultConverter(identityConverter);
@@ -2280,6 +2270,196 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
@Override
public Long geoAdd(byte[] key, double longitude, double latitude, byte[] member){
Long result = delegate.geoAdd(key, longitude, latitude, member);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Long geoAdd(String key, double longitude, double latitude, String member){
Long result = delegate.geoAdd(serialize(key), longitude, latitude, serialize(member));
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Long geoAdd(byte[] key, Map<byte[], GeoCoordinate> memberCoordinateMap) {
Long result = delegate.geoAdd(key, memberCoordinateMap);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Long geoAdd(String key, Map<String, GeoCoordinate> memberCoordinateMap) {
Map<byte[], GeoCoordinate> byteMap = new HashMap<byte[], GeoCoordinate>();
for (String k : memberCoordinateMap.keySet()){
byteMap.put(serialize(k), memberCoordinateMap.get(k));
}
Long result = delegate.geoAdd(serialize(key), byteMap);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2) {
Double result = delegate.geoDist(key, member1, member2);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Double geoDist(String key, String member1, String member2) {
return geoDist(key, member1, member2, GeoUnit.Meters);
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit) {
Double result = delegate.geoDist(key, member1, member2, unit);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Double geoDist(String key, String member1, String member2, GeoUnit geoUnit) {
Double result = delegate.geoDist(serialize(key), serialize(member1), serialize(member2), geoUnit);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<byte[]> geoHash(byte[] key, byte[]... members) {
List<byte[]> result = delegate.geoHash(key, members);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<String> geoHash(String key, String... members) {
List<byte[]> result = delegate.geoHash(serialize(key), serializeMulti(members));
if (isFutureConversion()){
addResultConverter(byteListToStringList);
}
return byteListToStringList.convert(result);
}
@Override
public List<GeoCoordinate> geoPos(byte[] key, byte[]... members) {
List<GeoCoordinate> result = delegate.geoPos(key, members);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoCoordinate> geoPos(String key, String... members) {
List<GeoCoordinate> result = delegate.geoPos(serialize(key), serializeMulti(members));
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadius(String key, double longitude, double latitude, double radius, GeoUnit unit) {
List<GeoRadiusResponse> result = delegate.georadius(serialize(key), longitude, latitude, radius, unit);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadius(String key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
List<GeoRadiusResponse> result = delegate.georadius(serialize(key), longitude, latitude, radius, unit, param);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius, GeoUnit unit) {
List<GeoRadiusResponse> result = delegate.georadiusByMember(serialize(key), serialize(member), radius, unit);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius, GeoUnit unit, GeoRadiusParam param) {
List<GeoRadiusResponse> result = delegate.georadiusByMember(serialize(key), serialize(member), radius, unit, param);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit) {
List<GeoRadiusResponse> result = delegate.georadius(key, longitude, latitude, radius, unit);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
List<GeoRadiusResponse> result = delegate.georadius(key, longitude, latitude, radius, unit, param);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit) {
List<GeoRadiusResponse> result = delegate.georadiusByMember(key, member, radius, unit);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) {
List<GeoRadiusResponse> result = delegate.georadiusByMember(key, member, radius, unit, param);
if (isFutureConversion()){
addResultConverter(identityConverter);
}
return result;
}
@Override
public Long geoRemove(byte[] key, byte[]... values) {
return zRem(key, values);
}
@Override
public Long geoRemove(String key, String... members) {
return zRem(key, members);
}
public List<Object> closePipeline() {
try {
return convertResults(delegate.closePipeline(), pipelineConverters);

View File

@@ -24,7 +24,7 @@ package org.springframework.data.redis.connection;
*/
public interface RedisCommands extends RedisKeyCommands, RedisStringCommands, RedisListCommands, RedisSetCommands,
RedisZSetCommands, RedisHashCommands, RedisTxCommands, RedisPubSubCommands, RedisConnectionCommands,
RedisServerCommands, RedisScriptingCommands, HyperLogLogCommands {
RedisServerCommands, RedisScriptingCommands, RedisGeoCommands, HyperLogLogCommands {
/**
* 'Native' or 'raw' execution of the given command along-side the given arguments. The command is executed as is,

View File

@@ -0,0 +1,188 @@
/*
* Copyright 2011-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.connection;
import org.springframework.data.redis.core.GeoCoordinate;
import org.springframework.data.redis.core.GeoRadiusParam;
import org.springframework.data.redis.core.GeoRadiusResponse;
import org.springframework.data.redis.core.GeoUnit;
import java.util.List;
import java.util.Map;
/**
* Geo-specific Redis commands.
*
* @author Ninad Divadkar
*/
public interface RedisGeoCommands {
/**
* Add latitude and longitude for a given key with a name.
* Returns the number of elements added to the sorted set, not including elements already existing for which the
* score was updated.
* <p>
* @link http://redis.io/commands/geoadd
*
* @param key
* @param member
* @param longitude
* @param latitude
* @return
*/
Long geoAdd(byte[] key, double longitude, double latitude, byte[] member);
/**
* Add latitude and longitude for a given key with a name.
* Returns the number of elements added to the sorted set, not including elements already existing for which the
* score was updated.
* <p>
* @link http://redis.io/commands/geoadd
*
* @param key
* @param memberCoordinateMap
* @return
*/
Long geoAdd(byte[] key, Map<byte[], GeoCoordinate> memberCoordinateMap);
/**
* Return the distance between two members in the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/geodist
*
* @param key
* @param member1
* @param member2
* @return
*/
Double geoDist(byte[] key, byte[] member1, byte[] member2);
/**
* Return the distance between two members in the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/geodist
*
* @param key
* @param member1
* @param member2
* @param unit
* @return
*/
Double geoDist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit);
/**
* Return valid Geohash strings representing the position of one or more elements in a sorted set value
* representing a geospatial index (where elements were added using GEOADD).
* <p>
* @link http://redis.io/commands/geohash
*
* @param key
* @param members
* @return
*/
List<byte[]> geoHash(byte[] key, byte[]... members);
/**
* Return the positions (longitude,latitude) of all the specified members of the geospatial index represented by
* the sorted set at key.
* <p>
* @link http://redis.io/commands/geopos
*
* @param key
* @param members
* @return
*/
List<GeoCoordinate> geoPos(byte[] key, byte[]... members);
/**
* Return the members of a sorted set populated with geospatial information using GEOADD, which are within
* the borders of the area specified with the center location and the maximum distance from the radius.
* <p>
* @link http://redis.io/commands/georadius
*
* @param key
* @param longitude
* @param latitude
* @param radius
* @param unit
* @return
*/
List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude,
double radius, GeoUnit unit);
/**
* Return the members of a sorted set populated with geospatial information using GEOADD, which are within
* the borders of the area specified with the center location and the maximum distance from the radius.
* <p>
* @link http://redis.io/commands/georadius
*
* @param key
* @param longitude
* @param latitude
* @param radius
* @param unit
* @param param
* @return
*/
List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude,
double radius, GeoUnit unit, GeoRadiusParam param);
/**
* This command is exactly like GEORADIUS with the sole difference that instead of taking, as the center of
* the area to query, a longitude and latitude value, it takes the name of a member already existing inside
* the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/georadiusbymember
*
* @param key
* @param member
* @param radius
* @param unit
*
* @return
*/
List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius,
GeoUnit unit);
/**
* This command is exactly like GEORADIUS with the sole difference that instead of taking, as the center of
* the area to query, a longitude and latitude value, it takes the name of a member already existing inside
* the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/georadiusbymember
*
* @param key
* @param member
* @param radius
* @param unit
* @param param
*
* @return
*/
List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius,
GeoUnit unit, GeoRadiusParam param);
/**
* Redis does not have a georem command, so this command just maps to zrem
* <p>
* @link http://redis.io/commands/geoadd
*
* @param key
* @param values
* @return
*/
Long geoRemove(byte[] key, byte[]... values);
}

View File

@@ -20,10 +20,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.serializer.RedisSerializer;
@@ -625,4 +622,152 @@ public interface StringRedisConnection extends RedisConnection {
*/
Set<String> zRangeByLex(String key, Range range, Limit limit);
/**
* Add latitude and longitude for a {@member} with a given {@key}.
* Returns the number of elements added to the sorted set, not including elements already existing for which the
* score was updated.
* <p>
* @link http://redis.io/commands/geoadd
*
* @param key
* @param member
* @param longitude
* @param latitude
* @return
*/
Long geoAdd(String key, double longitude, double latitude, String member);
/**
* Add memberCoordinateMap with a given {@key}.
* Returns the number of elements added to the sorted set, not including elements already existing for which the
* score was updated.
* <p>
* @link http://redis.io/commands/geoadd
*
* @param key
* @param memberCoordinateMap
* @return
*/
Long geoAdd(String key, Map<String, GeoCoordinate> memberCoordinateMap);
/**
* Return the distance between {@member1} and {@member2} in the geospatial index represented by the sorted set.
* The unit in which the distance is returned is meters.
* <p>
* @link http://redis.io/commands/geodist
*
* @param key
* @param member1
* @param member2
* @return
*/
Double geoDist(String key, String member1, String member2);
/**
* Return the distance in {@unit} between {@member1} and {@member2} in the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/geodist
*
* @param key
* @param member1
* @param member2
* @return
*/
Double geoDist(String key, String member1, String member2, GeoUnit unit);
/**
* Return valid Geohash strings representing the position of one or more {@values}
* representing a geospatial index (where elements were added using GEOADD).
* <p>
* @link http://redis.io/commands/geohash
*
* @param key
* @param values
* @return
*/
List<String> geoHash(String key, String... values);
/**
* Return the positions (longitude,latitude) in GeoCoordinate of all the specified {@members} of the geospatial index represented by
* the sorted set at key.
* <p>
* @link http://redis.io/commands/geopos
*
* @param key
* @param members
* @return
*/
List<GeoCoordinate> geoPos(String key, String... members);
/**
* Return the members of a sorted set populated with geospatial information using GEOADD, which are within
* the borders of the area specified with the center location given by {@longitude} and {@latitude} and
* the maximum distance from the {@radius}.
* <p>
* @link http://redis.io/commands/georadius
*
* @param key
* @param longitude
* @param latitude
* @param radius
* @param unit
* @return
*/
List<GeoRadiusResponse> georadius(String key, double longitude, double latitude,
double radius, GeoUnit unit);
/**
* Return the members of a sorted set populated with geospatial information using GEOADD, which are within
* the borders of the area specified with the center location given by {@longitude} and {@latitude} and
* the maximum distance from the {@radius}. {@param} can be passed to get coordinates, distance and sort the values
* <p>
* @link http://redis.io/commands/georadius
*
* @param key
* @param longitude
* @param latitude
* @param radius
* @param unit
* @param param
* @return
*/
List<GeoRadiusResponse> georadius(String key, double longitude, double latitude,
double radius, GeoUnit unit, GeoRadiusParam param);
/**
* This command is exactly like GEORADIUS with the sole difference that instead of taking, as the center of
* the area to query, a longitude and latitude value, it takes the name of a member already existing inside
* the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/georadiusbymember
*
* @param key
* @param member
* @param radius
* @param unit
*
* @return
*/
List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius,
GeoUnit unit);
/**
* This command is exactly like GEORADIUS with the sole difference that instead of taking, as the center of
* the area to query, a longitude and latitude value, it takes the name of a member already existing inside
* the geospatial index represented by the sorted set.
* <p>
* @link http://redis.io/commands/georadiusbymember
*
* @param key
* @param member
* @param radius
* @param unit
* @param param
*
* @return
*/
List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius,
GeoUnit unit, GeoRadiusParam param);
Long geoRemove(String key, String... members);
}

View File

@@ -15,19 +15,8 @@
*/
package org.springframework.data.redis.connection.jedis;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.DirectFieldAccessor;
@@ -59,10 +48,8 @@ import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.Subscription;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.connection.util.ByteArraySet;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanCursor;
import org.springframework.data.redis.core.ScanIteration;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.GeoRadiusResponse;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.util.ByteUtils;
@@ -70,12 +57,9 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import redis.clients.jedis.BinaryJedisPubSub;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ZParams;
import redis.clients.jedis.*;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoUnit;
/**
* {@link RedisClusterConnection} implementation on top of {@link JedisCluster}.<br/>
@@ -2511,10 +2495,126 @@ public class JedisClusterConnection implements RedisClusterConnection {
}
}
@Override
public Long geoAdd(byte[] key, double longitude, double latitude, byte[] member){
try {
return cluster.geoadd(key, longitude, latitude, member);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Long geoAdd(byte[] key, Map<byte[], org.springframework.data.redis.core.GeoCoordinate> memberCoordinateMap) {
Map<byte[], redis.clients.jedis.GeoCoordinate> redisGeoCoordinateMap = new HashMap<byte[], GeoCoordinate>();
for(byte[] mapKey : memberCoordinateMap.keySet()){
redisGeoCoordinateMap.put(mapKey, JedisConverters.toGeoCoordinate(memberCoordinateMap.get(mapKey)));
}
try {
return cluster.geoadd(key, redisGeoCoordinateMap);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2) {
try {
return cluster.geodist(key, member1, member2);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2, org.springframework.data.redis.core.GeoUnit unit) {
GeoUnit geoUnit = JedisConverters.toGeoUnit(unit);
try {
return cluster.geodist(key, member1, member2, geoUnit);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public List<byte[]> geoHash(byte[] key, byte[]... members) {
try {
return cluster.geohash(key, members);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public List<org.springframework.data.redis.core.GeoCoordinate> geoPos(byte[] key, byte[]... members) {
try {
return JedisConverters.geoCoordinateListToGeoCoordinateList().convert(cluster.geopos(key, members));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude,
double radius, org.springframework.data.redis.core.GeoUnit unit) {
GeoUnit geoUnit = JedisConverters.toGeoUnit(unit);
try {
return JedisConverters.geoRadiusResponseGeoRadiusResponseList().
convert(cluster.georadius(key, longitude, latitude, radius, geoUnit));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude,
double radius, org.springframework.data.redis.core.GeoUnit unit, GeoRadiusParam param) {
GeoUnit geoUnit = JedisConverters.toGeoUnit(unit);
redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(param);
try {
return JedisConverters.geoRadiusResponseGeoRadiusResponseList().
convert(cluster.georadius(key, longitude, latitude, radius, geoUnit, geoRadiusParam));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius,
org.springframework.data.redis.core.GeoUnit unit) {
GeoUnit geoUnit = JedisConverters.toGeoUnit(unit);
try {
return JedisConverters.geoRadiusResponseGeoRadiusResponseList().
convert(cluster.georadiusByMember(key, member, radius, geoUnit));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius,
org.springframework.data.redis.core.GeoUnit unit, GeoRadiusParam param) {
GeoUnit geoUnit = JedisConverters.toGeoUnit(unit);
redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(param);
try {
return JedisConverters.geoRadiusResponseGeoRadiusResponseList().
convert(cluster.georadiusByMember(key, member, radius, geoUnit, geoRadiusParam));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Long geoRemove(byte[] key, byte[]... values) {
return zRem(key, values);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConnectionCommands#select(int)
*/
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConnectionCommands#select(int)
*/
@Override
public void select(final int dbIndex) {

View File

@@ -42,6 +42,10 @@ import org.springframework.data.redis.connection.convert.ListConverter;
import org.springframework.data.redis.connection.convert.MapConverter;
import org.springframework.data.redis.connection.convert.SetConverter;
import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter;
import org.springframework.data.redis.core.GeoCoordinate;
import org.springframework.data.redis.core.GeoRadiusParam;
import org.springframework.data.redis.core.GeoRadiusResponse;
import org.springframework.data.redis.core.GeoUnit;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
@@ -79,6 +83,10 @@ abstract public class JedisConverters extends Converters {
private static final Converter<Object, RedisClusterNode> OBJECT_TO_CLUSTER_NODE_CONVERTER;
private static final Converter<Expiration, byte[]> EXPIRATION_TO_COMMAND_OPTION_CONVERTER;
private static final Converter<SetOption, byte[]> SET_OPTION_TO_COMMAND_OPTION_CONVERTER;
private static final Converter<redis.clients.jedis.GeoCoordinate, GeoCoordinate> GEO_COORDINATE_CONVERTER;
private static final ListConverter<redis.clients.jedis.GeoCoordinate, GeoCoordinate> GEO_COORDINATE_LIST_TO_GEO_COORDINATE_LIST;
private static final Converter<redis.clients.jedis.GeoRadiusResponse, GeoRadiusResponse> GEO_RADIUS_RESPONSE_CONVERTER;
private static final ListConverter<redis.clients.jedis.GeoRadiusResponse, GeoRadiusResponse> GEO_RADIUS_RESPONSE_LIST_TO_GEO_RADIUS_RESPONSE_LIST;
public static final byte[] PLUS_BYTES;
public static final byte[] MINUS_BYTES;
@@ -165,6 +173,27 @@ abstract public class JedisConverters extends Converters {
}
};
GEO_COORDINATE_CONVERTER = new Converter<redis.clients.jedis.GeoCoordinate, GeoCoordinate>() {
@Override
public GeoCoordinate convert(redis.clients.jedis.GeoCoordinate geoCoordinate) {
return geoCoordinate != null ? new GeoCoordinate(geoCoordinate.getLongitude(), geoCoordinate.getLatitude()) : null;
}
};
GEO_COORDINATE_LIST_TO_GEO_COORDINATE_LIST = new ListConverter<redis.clients.jedis.GeoCoordinate, GeoCoordinate>(GEO_COORDINATE_CONVERTER);
GEO_RADIUS_RESPONSE_CONVERTER = new Converter<redis.clients.jedis.GeoRadiusResponse, GeoRadiusResponse>() {
@Override
public GeoRadiusResponse convert(redis.clients.jedis.GeoRadiusResponse geoRadiusResponse) {
if (geoRadiusResponse == null)
return null;
GeoRadiusResponse response = new GeoRadiusResponse(geoRadiusResponse.getMember());
response.setDistance(geoRadiusResponse.getDistance());
response.setCoordinate(GEO_COORDINATE_CONVERTER.convert(geoRadiusResponse.getCoordinate()));
return response;
}
};
GEO_RADIUS_RESPONSE_LIST_TO_GEO_RADIUS_RESPONSE_LIST = new ListConverter<redis.clients.jedis.GeoRadiusResponse, GeoRadiusResponse>(GEO_RADIUS_RESPONSE_CONVERTER);
}
public static Converter<String, byte[]> stringToBytes() {
@@ -201,6 +230,10 @@ abstract public class JedisConverters extends Converters {
return EXCEPTION_CONVERTER;
}
public static ListConverter<redis.clients.jedis.GeoCoordinate, GeoCoordinate> geoCoordinateListToGeoCoordinateList() { return GEO_COORDINATE_LIST_TO_GEO_COORDINATE_LIST; }
public static ListConverter<redis.clients.jedis.GeoRadiusResponse, GeoRadiusResponse> geoRadiusResponseGeoRadiusResponseList() { return GEO_RADIUS_RESPONSE_LIST_TO_GEO_RADIUS_RESPONSE_LIST; }
public static String[] toStrings(byte[][] source) {
String[] result = new String[source.length];
for (int i = 0; i < source.length; i++) {
@@ -456,4 +489,41 @@ abstract public class JedisConverters extends Converters {
return sp;
}
public static redis.clients.jedis.GeoUnit toGeoUnit(GeoUnit geoUnit){
switch (geoUnit){
case Meters: return redis.clients.jedis.GeoUnit.M;
case KiloMeters: return redis.clients.jedis.GeoUnit.KM;
case Miles: return redis.clients.jedis.GeoUnit.MI;
case Feet: return redis.clients.jedis.GeoUnit.FT;
default: throw new IllegalArgumentException("geoUnit not supported");
}
}
public static redis.clients.jedis.GeoCoordinate toGeoCoordinate(GeoCoordinate geoCoordinate){
return new redis.clients.jedis.GeoCoordinate(geoCoordinate.getLongitude(), geoCoordinate.getLatitude());
}
public static redis.clients.jedis.params.geo.GeoRadiusParam toGeoRadiusParam(GeoRadiusParam geoRadiusParam){
redis.clients.jedis.params.geo.GeoRadiusParam param = redis.clients.jedis.params.geo.GeoRadiusParam.geoRadiusParam();
for (String k : geoRadiusParam.getParams().keySet()){
if (k.equals(GeoRadiusParam.getASC()))
param.sortAscending();
if (k.equals(GeoRadiusParam.getDESC()))
param.sortDescending();
if (k.equals(GeoRadiusParam.getCOUNT()))
param.count((Integer)geoRadiusParam.getParams().get(k));
if (k.equals(GeoRadiusParam.getWITHCOORD()))
param.withCoord();
if (k.equals(GeoRadiusParam.getWITHDIST()))
param.withDist();
}
return param;
}
public static redis.clients.jedis.GeoRadiusResponse toGeoRadiusResponse(GeoRadiusResponse geoRadiusResponse){
redis.clients.jedis.GeoRadiusResponse response = new redis.clients.jedis.GeoRadiusResponse(geoRadiusResponse.getMember());
response.setCoordinate(toGeoCoordinate(geoRadiusResponse.getCoordinate()));
response.setDistance(geoRadiusResponse.getDistance());
return response;
}
}

View File

@@ -45,8 +45,7 @@ import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.Subscription;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
@@ -1187,14 +1186,74 @@ public class JredisConnection extends AbstractRedisConnection {
throw new UnsupportedOperationException();
}
public void subscribe(MessageListener listener, byte[]... channels) {
throw new UnsupportedOperationException();
}
//
// Geo commands
//
@Override
public Long geoAdd(byte[] key, double longitude, double latitude, byte[] member) {
throw new UnsupportedOperationException();
}
@Override
public Long geoAdd(byte[] key, Map<byte[], GeoCoordinate> memberCoordinateMap){
throw new UnsupportedOperationException();
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2) {
throw new UnsupportedOperationException();
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2, org.springframework.data.redis.core.GeoUnit unit) {
throw new UnsupportedOperationException();
}
@Override
public List<byte[]> geoHash(byte[] key, byte[]... members) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoCoordinate> geoPos(byte[] key, byte[]... members) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) {
throw new UnsupportedOperationException();
}
@Override
public Long geoRemove(byte[] key, byte[]... values) {
throw new UnsupportedOperationException();
}
//
// Scripting commands
//
public void subscribe(MessageListener listener, byte[]... channels) {
throw new UnsupportedOperationException();
}
public void scriptFlush() {
throw new UnsupportedOperationException();
}

View File

@@ -35,6 +35,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.lambdaworks.redis.*;
import org.springframework.beans.BeanUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
@@ -56,12 +57,8 @@ import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.Subscription;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.connection.convert.TransactionResultConverter;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.KeyBoundCursor;
import org.springframework.data.redis.core.RedisCommand;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ScanCursor;
import org.springframework.data.redis.core.ScanIteration;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
@@ -69,25 +66,6 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import com.lambdaworks.redis.AbstractRedisClient;
import com.lambdaworks.redis.KeyScanCursor;
import com.lambdaworks.redis.LettuceFutures;
import com.lambdaworks.redis.MapScanCursor;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisAsyncConnectionImpl;
import com.lambdaworks.redis.RedisChannelHandler;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisClusterConnection;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisException;
import com.lambdaworks.redis.RedisSentinelAsyncConnection;
import com.lambdaworks.redis.RedisURI;
import com.lambdaworks.redis.ScanArgs;
import com.lambdaworks.redis.ScoredValue;
import com.lambdaworks.redis.ScoredValueScanCursor;
import com.lambdaworks.redis.SortArgs;
import com.lambdaworks.redis.ValueScanCursor;
import com.lambdaworks.redis.ZStoreArgs;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.output.BooleanOutput;
import com.lambdaworks.redis.output.ByteArrayOutput;
@@ -3079,10 +3057,184 @@ public class LettuceConnection extends AbstractRedisConnection {
}
}
//
// Geo functionality
//
@Override
public Long geoAdd(byte[] key, double longitude, double latitude, byte[] member) {
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().geoadd(key, longitude, latitude, member)));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().geoadd(key, longitude, latitude, member)));
return null;
}
return getConnection().geoadd(key, longitude, latitude, member);
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public Long geoAdd(byte[] key, Map<byte[], GeoCoordinate> memberCoordinateMap){
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().geoadd(key, memberCoordinateMap)));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().geoadd(key, memberCoordinateMap)));
return null;
}
return getConnection().geoadd(key, memberCoordinateMap);
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2) {
throw new UnsupportedOperationException("Lettuce does not support this method without unit parameter passed");
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit) {
GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(unit);
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().geodist(key, member1, member2, geoUnit)));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().geodist(key, member1, member2, geoUnit)));
return null;
}
return getConnection().geodist(key, member1, member2, geoUnit);
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public List<byte[]> geoHash(byte[] key, byte[]... members) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoCoordinate> geoPos(byte[] key, byte[]... members) {
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().geopos(key, members), LettuceConverters.geoCoordinateListToGeoCoordinateList()));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().geopos(key, members), LettuceConverters.geoCoordinateListToGeoCoordinateList()));
return null;
}
return LettuceConverters.geoCoordinateListToGeoCoordinateList().convert(getConnection().geopos(key, members));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit) {
GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(unit);
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().georadius(key, longitude, latitude, radius, geoUnit),
LettuceConverters.bytesSetToGeoRadiusResponseListConverter()));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().georadius(key, longitude, latitude, radius, geoUnit),
LettuceConverters.bytesSetToGeoRadiusResponseListConverter()));
return null;
}
return LettuceConverters.bytesSetToGeoRadiusResponseListConverter().
convert(getConnection().georadius(key, longitude, latitude, radius, geoUnit));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(unit);
GeoArgs geoArgs = LettuceConverters.toGeoArgs(param);
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().georadius(key, longitude, latitude, radius, geoUnit, geoArgs),
LettuceConverters.getGeowithinListToGeoRadiusResponseList()));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().georadius(key, longitude, latitude, radius, geoUnit, geoArgs),
LettuceConverters.getGeowithinListToGeoRadiusResponseList()));
return null;
}
return LettuceConverters.getGeowithinListToGeoRadiusResponseList().
convert(getConnection().georadius(key, longitude, latitude, radius, geoUnit, geoArgs));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit) {
GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(unit);
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().georadiusbymember(key, member, radius, geoUnit),
LettuceConverters.bytesSetToGeoRadiusResponseListConverter()));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().georadiusbymember(key, member, radius, geoUnit),
LettuceConverters.bytesSetToGeoRadiusResponseListConverter()));
return null;
}
return LettuceConverters.bytesSetToGeoRadiusResponseListConverter().
convert(getConnection().georadiusbymember(key, member, radius, geoUnit));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) {
GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(unit);
GeoArgs geoArgs = LettuceConverters.toGeoArgs(param);
try {
if (isPipelined()) {
pipeline(new LettuceResult(getAsyncConnection().georadiusbymember(key, member, radius, geoUnit, geoArgs),
LettuceConverters.getGeowithinListToGeoRadiusResponseList()));
return null;
}
if (isQueueing()) {
transaction(new LettuceTxResult(getConnection().georadiusbymember(key, member, radius, geoUnit, geoArgs),
LettuceConverters.getGeowithinListToGeoRadiusResponseList()));
return null;
}
return LettuceConverters.getGeowithinListToGeoRadiusResponseList().
convert(getConnection().georadiusbymember(key, member, radius, geoUnit, geoArgs));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
@Override
public Long geoRemove(byte[] key, byte[]... values) {
return zRem(key, values);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time()
*/
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time()
*/
@Override
public Long time() {
try {

View File

@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.lambdaworks.redis.*;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.DefaultTuple;
@@ -47,19 +48,19 @@ import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.SortParameters.Order;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.connection.convert.ListConverter;
import org.springframework.data.redis.connection.convert.LongToBooleanConverter;
import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter;
import org.springframework.data.redis.core.GeoCoordinate;
import org.springframework.data.redis.core.GeoRadiusParam;
import org.springframework.data.redis.core.GeoRadiusResponse;
import org.springframework.data.redis.core.GeoUnit;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.lambdaworks.redis.KeyValue;
import com.lambdaworks.redis.RedisURI;
import com.lambdaworks.redis.ScoredValue;
import com.lambdaworks.redis.ScriptOutputType;
import com.lambdaworks.redis.SortArgs;
import com.lambdaworks.redis.cluster.models.partitions.Partitions;
import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode.NodeFlag;
import com.lambdaworks.redis.protocol.LettuceCharsets;
@@ -91,6 +92,10 @@ abstract public class LettuceConverters extends Converters {
private static final Converter<String[], List<RedisClientInfo>> STRING_TO_LIST_OF_CLIENT_INFO = new StringToRedisClientInfoConverter();
private static final Converter<Partitions, List<RedisClusterNode>> PARTITIONS_TO_CLUSTER_NODES;
private static Converter<com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode, RedisClusterNode> CLUSTER_NODE_TO_CLUSTER_NODE_CONVERTER;
private static final Converter<com.lambdaworks.redis.GeoCoordinates, GeoCoordinate> GEO_COORDINATE_CONVERTER;
private static final ListConverter<com.lambdaworks.redis.GeoCoordinates, GeoCoordinate> GEO_COORDINATE_LIST_TO_GEO_COORDINATE_LIST;
private static final Converter<Set<byte[]>, List<GeoRadiusResponse>> BYTES_SET_TO_GEO_RADIUS_RESPONSE_LIST;
private static final Converter<List<GeoWithin<byte[]>>, List<GeoRadiusResponse>> GEOWITHIN_LIST_TO_GEO_RADIUS_RESPONSE_LIST;
public static final byte[] PLUS_BYTES;
public static final byte[] MINUS_BYTES;
@@ -284,6 +289,55 @@ abstract public class LettuceConverters extends Converters {
MINUS_BYTES = toBytes("-");
POSITIVE_INFINITY_BYTES = toBytes("+inf");
NEGATIVE_INFINITY_BYTES = toBytes("-inf");
GEO_COORDINATE_CONVERTER = new Converter<com.lambdaworks.redis.GeoCoordinates, GeoCoordinate>() {
@Override
public GeoCoordinate convert(com.lambdaworks.redis.GeoCoordinates geoCoordinate) {
return geoCoordinate != null ? new GeoCoordinate(geoCoordinate.x.doubleValue(), geoCoordinate.y.doubleValue()) : null;
}
};
GEO_COORDINATE_LIST_TO_GEO_COORDINATE_LIST = new ListConverter<com.lambdaworks.redis.GeoCoordinates, GeoCoordinate>(GEO_COORDINATE_CONVERTER);
BYTES_SET_TO_GEO_RADIUS_RESPONSE_LIST = new Converter<Set<byte[]>, List<GeoRadiusResponse>>() {
@Override
public List<GeoRadiusResponse> convert(Set<byte[]> source) {
if (CollectionUtils.isEmpty(source)) {
return Collections.emptyList();
}
List<GeoRadiusResponse> geoRadiusResponses = new ArrayList<GeoRadiusResponse>();
Iterator<byte[]> it = source.iterator();
while (it.hasNext()) {
geoRadiusResponses.add(new GeoRadiusResponse(it.next()));
}
return geoRadiusResponses;
}
};
GEOWITHIN_LIST_TO_GEO_RADIUS_RESPONSE_LIST = new Converter<List<GeoWithin<byte[]>>, List<GeoRadiusResponse>>() {
@Override
public List<GeoRadiusResponse> convert(List<GeoWithin<byte[]>> source) {
if (CollectionUtils.isEmpty(source)) {
return Collections.emptyList();
}
List<GeoRadiusResponse> geoRadiusResponses = new ArrayList<GeoRadiusResponse>();
Iterator<GeoWithin<byte[]>> it = source.iterator();
while (it.hasNext()) {
GeoWithin<byte[]> geoWithin = it.next();
GeoRadiusResponse geoRadiusResponse = new GeoRadiusResponse(geoWithin.member);
geoRadiusResponse.setCoordinate(new GeoCoordinate(geoWithin.coordinates.x.doubleValue(),
geoWithin.coordinates.y.doubleValue()));
geoRadiusResponse.setDistance(geoWithin.distance);
}
return geoRadiusResponses;
}
};
}
public static List<Tuple> toTuple(List<byte[]> list) {
@@ -294,6 +348,14 @@ abstract public class LettuceConverters extends Converters {
return BYTES_LIST_TO_TUPLE_LIST_CONVERTER;
}
public static Converter<Set<byte[]>, List<GeoRadiusResponse>> bytesSetToGeoRadiusResponseListConverter() {
return BYTES_SET_TO_GEO_RADIUS_RESPONSE_LIST;
}
public static Converter<List<GeoWithin<byte[]>>, List<GeoRadiusResponse>> getGeowithinListToGeoRadiusResponseList() {
return GEOWITHIN_LIST_TO_GEO_RADIUS_RESPONSE_LIST;
}
public static Converter<String, List<RedisClientInfo>> stringToRedisClientListConverter() {
return new Converter<String, List<RedisClientInfo>>() {
@@ -344,6 +406,8 @@ abstract public class LettuceConverters extends Converters {
return EXCEPTION_CONVERTER;
}
public static ListConverter<com.lambdaworks.redis.GeoCoordinates, GeoCoordinate> geoCoordinateListToGeoCoordinateList() { return GEO_COORDINATE_LIST_TO_GEO_COORDINATE_LIST; }
/**
* @return
* @sice 1.3
@@ -657,4 +721,32 @@ abstract public class LettuceConverters extends Converters {
return args;
}
public static com.lambdaworks.redis.GeoArgs.Unit toGeoArgsUnit(GeoUnit geoUnit){
switch (geoUnit){
case Meters: return GeoArgs.Unit.m;
case KiloMeters: return GeoArgs.Unit.km;
case Miles: return GeoArgs.Unit.mi;
case Feet: return GeoArgs.Unit.ft;
default: throw new IllegalArgumentException("geoUnit not supported");
}
}
public static com.lambdaworks.redis.GeoArgs toGeoArgs(GeoRadiusParam geoRadiusParam){
com.lambdaworks.redis.GeoArgs geoArgs = new GeoArgs();
for (String k : geoRadiusParam.getParams().keySet()){
if (k.equals(GeoRadiusParam.getASC()))
geoArgs.asc();
else if (k.equals(GeoRadiusParam.getDESC()))
geoArgs.desc();
else if (k.equals(GeoRadiusParam.getCOUNT()))
geoArgs.withCount((Integer)geoRadiusParam.getParams().get(k));
else if (k.equals(GeoRadiusParam.getWITHCOORD()))
geoArgs.withCoordinates();
else if (k.equals(GeoRadiusParam.getWITHDIST()))
geoArgs.withDistance();
else
throw new IllegalArgumentException("unknown key value");
}
return geoArgs;
}
}

View File

@@ -44,8 +44,7 @@ import org.springframework.data.redis.connection.RedisSubscribedConnectionExcept
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.Subscription;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
@@ -2241,6 +2240,61 @@ public class SrpConnection extends AbstractRedisConnection {
}
}
@Override
public Long geoAdd(byte[] key, double longitude, double latitude, byte[] member) {
throw new UnsupportedOperationException();
}
@Override
public Long geoAdd(byte[] key, Map<byte[], GeoCoordinate> memberCoordinateMap) {
throw new UnsupportedOperationException();
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2) {
throw new UnsupportedOperationException();
}
@Override
public Double geoDist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit) {
throw new UnsupportedOperationException();
}
@Override
public List<byte[]> geoHash(byte[] key, byte[]... members) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoCoordinate> geoPos(byte[] key, byte[]... members) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit) {
throw new UnsupportedOperationException();
}
@Override
public List<GeoRadiusResponse> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) {
throw new UnsupportedOperationException();
}
@Override
public Long geoRemove(byte[] key, byte[]... values) {
throw new UnsupportedOperationException();
}
/**
* Specifies if pipelined results should be converted to the expected data type. If false, results of
* {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Lettuce driver

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import java.util.List;
import java.util.Map;
/**
* Hash operations bound to a certain key.
*
* @author Ninad Divadkar
*/
public interface BoundGeoOperations<K,M> extends BoundKeyOperations<K> {
Long geoAdd(K key, double longitude, double latitude, M member);
Long geoAdd(K key, Map<M, GeoCoordinate> memberCoordinateMap);
Double geoDist(K key, M member1, M member2);
Double geoDist(K key, M member1, M member2, GeoUnit unit);
List<byte[]> geoHash(K key, M... members);
List<GeoCoordinate> geoPos(K key, M... members);
List<GeoRadiusResponse> georadius(K key, double longitude, double latitude,
double radius, GeoUnit unit);
List<GeoRadiusResponse> georadius(K key, double longitude, double latitude,
double radius, GeoUnit unit, GeoRadiusParam param);
List<GeoRadiusResponse> georadiusByMember(K key, M member, double radius,
GeoUnit unit);
List<GeoRadiusResponse> georadiusByMember(K key, M member, double radius,
GeoUnit unit, GeoRadiusParam param);
Long geoRemove(K key, M... members);
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2011-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import org.springframework.data.redis.connection.DataType;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author Ninad Divadkar
*/
class DefaultBoundGeoOperations<K, M> extends DefaultBoundKeyOperations<K> implements BoundGeoOperations<K, M> {
private final GeoOperations<K, M> ops;
/**
* Constructs a new <code>DefaultBoundGeoOperations</code> instance.
*
* @param key
* @param operations
*/
public DefaultBoundGeoOperations(K key, RedisOperations<K, M> operations) {
super(key, operations);
this.ops = operations.opsForGeo();
}
@Override
public Long geoAdd(K key, double longitude, double latitude, M member) {
return ops.geoAdd(key, longitude, latitude, member);
}
@Override
public Long geoAdd(K key, Map<M, GeoCoordinate> memberCoordinateMap) {
return ops.geoAdd(key, memberCoordinateMap);
}
@Override
public Double geoDist(K key, M member1, M member2) {
return ops.geoDist(key, member1, member2);
}
@Override
public Double geoDist(K key, M member1, M member2, GeoUnit unit) {
return ops.geoDist(key, member1, member2, unit);
}
@Override
public List<byte[]> geoHash(K key, M... members) {
return ops.geoHash(key, members);
}
@Override
public List<GeoCoordinate> geoPos(K key, M... members) {
return ops.geoPos(key, members);
}
@Override
public List<GeoRadiusResponse> georadius(K key, double longitude, double latitude, double radius, GeoUnit unit) {
return ops.georadius(key, longitude, latitude, radius, unit);
}
@Override
public List<GeoRadiusResponse> georadius(K key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
return ops.georadius(key, longitude, latitude, radius, unit, param);
}
@Override
public List<GeoRadiusResponse> georadiusByMember(K key, M member, double radius, GeoUnit unit) {
return ops.georadiusByMember(key, member, radius, unit);
}
@Override
public List<GeoRadiusResponse> georadiusByMember(K key, M member, double radius, GeoUnit unit, GeoRadiusParam param) {
return ops.georadiusByMember(key, member, radius, unit, param);
}
@Override
public Long geoRemove(K key, M... members) {
return ops.geoRemove(key, members);
}
@Override
public DataType getType() {
return DataType.STRING;
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import org.springframework.data.redis.connection.RedisConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Default implementation of {@link GeoOperations}.
*
* @author Ninad Divadkar
*/
public class DefaultGeoOperations<K, M> extends AbstractOperations<K, M> implements GeoOperations<K, M> {
DefaultGeoOperations(RedisTemplate<K, M> template) {
super(template);
}
@Override
public Long geoAdd(K key, final double longitude, final double latitude, M member) {
final byte[] rawKey = rawKey(key);
final byte[] rawMember = rawValue(member);
return execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) {
return connection.geoAdd(rawKey, longitude, latitude, rawMember);
}
}, true);
}
@Override
public Long geoAdd(K key, Map<M, GeoCoordinate> memberCoordinateMap) {
final byte[] rawKey = rawKey(key);
final Map<byte[], GeoCoordinate> rawMemberCoordinateMap = new HashMap<byte[], GeoCoordinate>();
for(M member : memberCoordinateMap.keySet()){
final byte[] rawMember = rawValue(member);
rawMemberCoordinateMap.put(rawMember, memberCoordinateMap.get(member));
}
return execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) {
return connection.geoAdd(rawKey, rawMemberCoordinateMap);
}
}, true);
}
@Override
public Double geoDist(K key, final M member1, final M member2) {
final byte[] rawKey = rawKey(key);
final byte[] rawMember1 = rawValue(member1);
final byte[] rawMember2 = rawValue(member2);
return execute(new RedisCallback<Double>() {
public Double doInRedis(RedisConnection connection) {
return connection.geoDist(rawKey, rawMember1, rawMember2);
}
}, true);
}
@Override
public Double geoDist(K key, M member1, M member2, final GeoUnit unit) {
final byte[] rawKey = rawKey(key);
final byte[] rawMember1 = rawValue(member1);
final byte[] rawMember2 = rawValue(member2);
return execute(new RedisCallback<Double>() {
public Double doInRedis(RedisConnection connection) {
return connection.geoDist(rawKey, rawMember1, rawMember2, unit);
}
}, true);
}
@Override
public List<byte[]> geoHash(K key, final M... members) {
final byte[] rawKey = rawKey(key);
final byte[][] rawMembers = rawValues(members);
return execute(new RedisCallback<List<byte[]>>() {
public List<byte[]> doInRedis(RedisConnection connection) {
return connection.geoHash(rawKey, rawMembers);
}
}, true);
}
@Override
public List<GeoCoordinate> geoPos(K key, M... members) {
final byte[] rawKey = rawKey(key);
final byte[][] rawMembers = rawValues(members);
return execute(new RedisCallback<List<GeoCoordinate>>() {
public List<GeoCoordinate> doInRedis(RedisConnection connection) {
return connection.geoPos(rawKey, rawMembers);
}
}, true);
}
@Override
public List<GeoRadiusResponse> georadius(K key, final double longitude, final double latitude, final double radius, final GeoUnit unit) {
final byte[] rawKey = rawKey(key);
return execute(new RedisCallback<List<GeoRadiusResponse>>() {
public List<GeoRadiusResponse> doInRedis(RedisConnection connection) {
return connection.georadius(rawKey, longitude, latitude, radius, unit);
}
}, true);
}
@Override
public List<GeoRadiusResponse> georadius(K key, final double longitude, final double latitude, final double radius, final GeoUnit unit, final GeoRadiusParam param) {
final byte[] rawKey = rawKey(key);
return execute(new RedisCallback<List<GeoRadiusResponse>>() {
public List<GeoRadiusResponse> doInRedis(RedisConnection connection) {
return connection.georadius(rawKey, longitude, latitude, radius, unit, param);
}
}, true);
}
@Override
public List<GeoRadiusResponse> georadiusByMember(K key, M member, final double radius, final GeoUnit unit) {
final byte[] rawKey = rawKey(key);
final byte[] rawMember = rawValue(member);
return execute(new RedisCallback<List<GeoRadiusResponse>>() {
public List<GeoRadiusResponse> doInRedis(RedisConnection connection) {
return connection.georadiusByMember(rawKey, rawMember, radius, unit);
}
}, true);
}
@Override
public List<GeoRadiusResponse> georadiusByMember(K key, M member, final double radius, final GeoUnit unit, final GeoRadiusParam param) {
final byte[] rawKey = rawKey(key);
final byte[] rawMember = rawValue(member);
return execute(new RedisCallback<List<GeoRadiusResponse>>() {
public List<GeoRadiusResponse> doInRedis(RedisConnection connection) {
return connection.georadiusByMember(rawKey, rawMember, radius, unit, param);
}
}, true);
}
@Override
public Long geoRemove(K key, M... members) {
final byte[] rawKey = rawKey(key);
final byte[][] rawMembers = rawValues(members);
return execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) {
return connection.zRem(rawKey, rawMembers);
}
}, true);
}
}

View File

@@ -0,0 +1,22 @@
package org.springframework.data.redis.core;
/**
* Created by ndivadkar on 3/29/16.
*/
public class GeoCoordinate {
private double longitude;
private double latitude;
public GeoCoordinate(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import java.util.List;
import java.util.Map;
/**
* Redis operations for geo commands.
*
* @author Ninad Divadkar
*/
public interface GeoOperations<K, M> {
Long geoAdd(K key, double longitude, double latitude, M member);
Long geoAdd(K key, Map<M, GeoCoordinate> memberCoordinateMap);
Double geoDist(K key, M member1, M member2);
Double geoDist(K key, M member1, M member2, GeoUnit unit);
List<byte[]> geoHash(K key, M... members);
List<GeoCoordinate> geoPos(K key, M... members);
List<GeoRadiusResponse> georadius(K key, double longitude, double latitude,
double radius, GeoUnit unit);
List<GeoRadiusResponse> georadius(K key, double longitude, double latitude,
double radius, GeoUnit unit, GeoRadiusParam param);
List<GeoRadiusResponse> georadiusByMember(K key, M member, double radius,
GeoUnit unit);
List<GeoRadiusResponse> georadiusByMember(K key, M member, double radius,
GeoUnit unit, GeoRadiusParam param);
Long geoRemove(K key, M... members);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2011-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import java.beans.PropertyEditorSupport;
/**
* PropertyEditor allowing for easy injection of {@link org.springframework.data.redis.core.GeoOperations} from {@link org.springframework.data.redis.core.RedisOperations}.
*
* @author Ninad Divadkar
*/
class GeoOperationsEditor extends PropertyEditorSupport {
public void setValue(Object value) {
if (value instanceof RedisOperations) {
super.setValue(((RedisOperations) value).opsForGeo());
} else {
throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class);
}
}
}

View File

@@ -0,0 +1,88 @@
package org.springframework.data.redis.core;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ndivadkar on 3/29/16.
*/
public class GeoRadiusParam {
private static final String WITHCOORD = "withcoord";
private static final String WITHDIST = "withdist";
private static final String ASC = "asc";
private static final String DESC = "desc";
private static final String COUNT = "count";
private Map<String, Object> params;
private GeoRadiusParam() {
}
public static GeoRadiusParam geoRadiusParam() {
return new GeoRadiusParam();
}
public GeoRadiusParam withCoord() {
addParam(WITHCOORD);
return this;
}
public GeoRadiusParam withDist() {
addParam(WITHDIST);
return this;
}
public GeoRadiusParam sortAscending() {
addParam(ASC);
return this;
}
public GeoRadiusParam sortDescending() {
addParam(DESC);
return this;
}
public GeoRadiusParam count(int count) {
if (count > 0) {
addParam(COUNT, count);
}
return this;
}
protected void addParam(String name, Object value) {
if (params == null) {
params = new HashMap<String, Object>();
}
params.put(name, value);
}
protected void addParam(String name) {
if (params == null) {
params = new HashMap<String, Object>();
}
params.put(name, null);
}
public Map<String, Object> getParams() {
return params;
}
public static String getWITHCOORD() {
return WITHCOORD;
}
public static String getWITHDIST() {
return WITHDIST;
}
public static String getASC() {
return ASC;
}
public static String getDESC() {
return DESC;
}
public static String getCOUNT() {
return COUNT;
}
}

View File

@@ -0,0 +1,34 @@
package org.springframework.data.redis.core;
/**
* Created by ndivadkar on 4/1/16.
*/
public class GeoRadiusResponse {
private byte[] member;
private double distance;
private GeoCoordinate coordinate;
public GeoRadiusResponse(byte[] member) {
this.member = member;
}
public void setDistance(double distance) {
this.distance = distance;
}
public void setCoordinate(GeoCoordinate coordinate) {
this.coordinate = coordinate;
}
public byte[] getMember() {
return member;
}
public double getDistance() {
return distance;
}
public GeoCoordinate getCoordinate() {
return coordinate;
}
}

View File

@@ -0,0 +1,11 @@
package org.springframework.data.redis.core;
/**
* Created by ndivadkar on 3/29/16.
*/
public enum GeoUnit {
Meters,
KiloMeters,
Miles,
Feet;
}

View File

@@ -78,6 +78,7 @@ public enum RedisCommand {
GETBIT("r", 2, 2), //
GETRANGE("r", 3, 3), //
GETSET("rw", 2, 2), //
GEOADD("w", 3, 2),
// -- H
HDEL("rw", 2), //
HEXISTS("r", 2, 2), //

View File

@@ -283,6 +283,21 @@ public interface RedisOperations<K, V> {
*/
<HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key);
/**
* Returns the operations performed on geo values.
*
* @return geo operations
*/
GeoOperations<K, V> opsForGeo();
/**
* Returns the operations performed on values bound to the given key.
*
* @param key Redis key
* @return geo operations bound to the given key.
*/
BoundGeoOperations<K, V> boundGeoOps(K key);
/**
* Returns the cluster specific operations interface.
*

View File

@@ -98,6 +98,7 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
private ListOperations<K, V> listOps;
private SetOperations<K, V> setOps;
private ZSetOperations<K, V> zSetOps;
private GeoOperations<K, V> geoOps;
private HyperLogLogOperations<K, V> hllOps;
/**
@@ -1006,10 +1007,23 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
return zSetOps;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.RedisOperations#opsForHyperLogLog()
*/
@Override
public GeoOperations<K, V> opsForGeo() {
if (geoOps == null) {
geoOps = new DefaultGeoOperations<K, V>(this);
}
return geoOps;
}
@Override
public BoundGeoOperations<K, V> boundGeoOps(K key) {
return new DefaultBoundGeoOperations<K, V>(key, this);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.RedisOperations#opsForHyperLogLog()
*/
@Override
public HyperLogLogOperations<K, V> opsForHyperLogLog() {