Redis Geo 使用场景 API列表名词 API列表 Springboot使用 注意事项
Redis Geo 是Redis在3.2版本中新增的功能,用于存储和操作地理位置信息
使用场景
滴滴打车:这是一个对地理位置精度要求较高的场景。通过使用Redis的GEO功能,滴滴打车可以存储房源和店铺的地理位置信息,并根据用户所在位置的经纬度,加上范围,查询到附近的房源和店铺列表,放到高德地图中展现出来。 直播业务:比如主播开播的时候写入主播Id的经纬度,关播的时候删除主播Id元素,这样就维护了一个具有位置信息的在线主播集合提供给线上检索。 自如、蛋壳、链家、美团等平台也有根据距离找房源或者商铺的功能,这个功能也是使用的Redis的GEO功能。
API列表名词
字段 含义 longitude 经度 latitude 纬度 member 位置名称 radius 距离中心位置的距离 m/km/ft/mi 距离中心位置的单位,米/千米/英里/英尺 WITHCOORD 返回距离中心位置元素及经纬度 WITHDIST 返回距离中心位置元素及距离 WITHHASH 返回距离中心位置元素及geohash 值 COUNT 返回距离中心位置元素的元素个数 ASC/DESC 距离远近排序 STORE key 返回的集合元素存储到某个key中 STOREDIST key 返回的元素距离集合存储到某个key中 BYRADIUS 按圆形扫描 BYBOX 按矩形扫描
API列表
名称 含义 指令 GEOADD 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中 GEOADD key longitude latitude member [longitude latitude member …] GEOPOS 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度) GEOPOS key member [member …] GEOHASH 用于获取一个或多个位置元素的 geohash 值 GEOHASH key member [member …] GEODIST 用于返回两个给定位置之间的距离 GEODIST key member1 member2 [m/km/ft/mi] GEORADIUS 以给定的经纬度为中心, 返回键包含的位置元素中, 与中心的距离不超过给定最大距离(radius)的所有位置元素 GEORADIUS key longitude latitude radius [m/km/ft/mi] [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC GEORADIUSBYMEMBER 与GEORADIUS 相似,只是该指令是以位置(member)为中心 GEORADIUSBYMEMBER key member radius [m/km/ft/mi] [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC/DESC] [STORE key] [STOREDIST key] GEOSEARCH 存在高版本Redis中,GEORADIUS升级,除了可以设置扫描范围,还可以设置扫描形状(圆形,矩形),geosearch的功能更加强大和灵活,可以满足更多的使用场景和需求 GEOSEARCH key <member / longitude latitude> <[BYRADIUS radius [m/km/ft/mi] ]/ [BYBOX width height [m/km/ft/mi]]> [ASC/DESC] [COUNT count] [WITHCOORD] [WITHDIST][WITHHASH]
Springboot使用
maven
< dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-undertow</ artifactId> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-web</ artifactId> < exclusions> < exclusion> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-tomcat</ artifactId> </ exclusion> </ exclusions> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-test</ artifactId> < scope> test</ scope> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-data-redis</ artifactId> </ dependency> < dependency> < groupId> junit</ groupId> < artifactId> junit</ artifactId> < scope> test</ scope> </ dependency>
yaml
spring : redis : host : 127.0.0.1 port : 6379 database : 0
Test
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. boot. test. context. SpringBootTest ;
import org. springframework. data. geo. Circle ;
import org. springframework. data. geo. Distance ;
import org. springframework. data. geo. GeoResults ;
import org. springframework. data. geo. Point ;
import org. springframework. data. redis. connection. RedisGeoCommands ;
import org. springframework. data. redis. core. StringRedisTemplate ;
import org. springframework. data. redis. domain. geo. Metrics ;
import org. springframework. test. context. junit4. SpringRunner ; import java. util. List ; @RunWith ( SpringRunner . class )
@SpringBootTest
public class MyDemoApplicationTests { @Autowired StringRedisTemplate redisTemplate; @Test public void redisTestAdd ( ) { Long a = redisTemplate. opsForGeo ( ) . add ( "geo" , new Point ( 13.261391222476959 , 38.215556214674542 ) , "a" ) ; Long b = redisTemplate. opsForGeo ( ) . add ( "geo" , new Point ( 15.087267458438873 , 37.50266842333162 ) , "b" ) ; System . out. println ( a) ; System . out. println ( b) ; } @Test public void redisTestGeoGet ( ) { List < Point > points = redisTemplate. opsForGeo ( ) . position ( "geo" , "a" , "b" ) ; System . out. println ( points) ; } @Test public void testDist ( ) { Distance distance = redisTemplate. opsForGeo ( ) . distance ( "geo" , "a" , "b" , RedisGeoCommands. DistanceUnit . KILOMETERS ) ; System . out. println ( distance) ; } @Test public void redisTestNearByXY ( ) { Circle circle = new Circle ( new Point ( 114.05 , 22.55 ) , new Distance ( 200 , Metrics . KILOMETERS ) ) ; RedisGeoCommands. GeoRadiusCommandArgs args = RedisGeoCommands. GeoRadiusCommandArgs . newGeoRadiusArgs ( ) . includeDistance ( ) . includeCoordinates ( ) . sortAscending ( ) . limit ( 5 ) ; GeoResults < RedisGeoCommands. GeoLocation < String > > results = redisTemplate. opsForGeo ( ) . radius ( "geo" , circle, args) ; System . out. println ( results) ; } @Test public void testNearByPlace ( ) { Distance distance = new Distance ( 200 , Metrics . KILOMETERS ) ; RedisGeoCommands. GeoRadiusCommandArgs args = RedisGeoCommands. GeoRadiusCommandArgs . newGeoRadiusArgs ( ) . includeDistance ( ) . includeCoordinates ( ) . sortAscending ( ) . limit ( 5 ) ; GeoResults < RedisGeoCommands. GeoLocation < String > > results = redisTemplate. opsForGeo ( ) . radius ( "geo" , "a" , distance, args) ; System . out. println ( results) ; } @Test public void testGeoHash ( ) { List < String > results = redisTemplate. opsForGeo ( ) . hash ( "geo" , "a" , "b" ) ; System . out. println ( results) ; } }
注意事项
在Redis的集群环境中,不建议将大量的数据存储在一个zset集合中,因为这会导致集群迁移时出现卡顿现象,影响线上服务的正常运行。如果数据量过大,需要对数据进行拆分,按国家、省份、城市等拆分。 建议将频繁访问的数据存储在Redis中,而将低频数据存储在其他数据库中。 避免将不相关的数据业务都放到一个Redis中,这可以避免业务相互影响,避免单实例膨胀,并能在故障时降低影响面,快速恢复。 由于Redis是单线程服务,消息过大会阻塞并拖慢其他操作。因此,需要保持消息内容在1KB以下,严禁超过50KB的单条记录。