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的單條記錄。