Redis GEO 是 Redis 3.2 版本引入的一种用于处理地理空间数据的数据结构。它基于有序集合(Sorted Set)实现,通过 GeoHash 算法将二维的经纬度坐标转换为一维的整数值,并存储在有序集合中。这种设计使得 Redis GEO 能够高效地执行地理空间查询,如查找附近的地点、计算两点之间的距离等。
Redis GEO 在多种需要处理地理位置数据的场景中具有广泛的应用,以下是一些典型场景:
-
附近的人或事物:通过
GEORADIUS或GEORADIUSBYMEMBER命令,可以查找给定位置一定范围内的所有用户或商家。 -
地理围栏:定义一个虚拟的地理边界,当用户或物体进入或离开该区域时触发特定动作,如发送通知。
-
物流轨迹:实时记录车辆位置,快速查找附近的充电桩或配送点,计算路线距离。
-
社交网络:发现附近的朋友或兴趣相似的人。
-
电子商务:为用户提供基于位置的优惠和服务。
-
导航系统:提供实时路线规划和导航功能。
Redis GEO 的底层实现基于有序集合(Sorted Set),通过 GeoHash 算法将经纬度坐标转换为一维的 52 位整数值作为有序集合的分数(score)。GeoHash 算法的核心思想是将地球划分为多个网格,每个网格用一个字符串表示,相邻的地点往往具有相似的编码。
-
数据存储:每个地理位置被表示为有序集合中的一个元素,其分数是通过 GeoHash 算法计算得到的 52 位整数,值是该位置的名称。
-
范围查询:通过有序集合的特性,Redis GEO 能够快速查找给定范围内的所有位置,时间复杂度为 O(logN)。
-
距离计算:Redis 提供了
GEODIST命令,用于计算两个位置之间的距离。
以下是 Redis GEO 的一些常用命令及其使用示例:
-
GEOADD:向 GEO 键中添加一个或多个位置。
GEOADD locations 116.397428 39.90923 "Beijing" 121.473701 31.230416 "Shanghai" -
GEORADIUS:查找给定经纬度坐标一定范围内的所有位置。
GEORADIUS locations 116.397428 39.90923 100 km WITHDIST WITHCOORD -
GEORADIUSBYMEMBER:查找给定位置一定范围内的所有位置。
GEORADIUSBYMEMBER locations Beijing 100 km WITHDIST -
GEODIST:计算两个位置之间的距离。
GEODIST locations Beijing Shanghai km -
GEOPOS:获取位置的经纬度坐标。
GEOPOS locations Beijing -
GEOHASH:获取位置的 GeoHash 编码。
GEOHASH locations Beijing
以下是一个使用 Java 和 Jedis 客户端实现 Redis GEO 的示例:
import redis.clients.jedis.Jedis; import redis.clients.jedis.GeoCoordinate; import redis.clients.jedis.GeoRadiusResponse; import redis.clients.jedis.GeoUnit; import java.util.List; public class RedisGeoExample { public static void main(String[] args) { Jedis jedis = new Jedis("localhost", 6379); // 添加地理位置信息 jedis.geoadd("locations", 116.397428, 39.90923, "Beijing"); jedis.geoadd("locations", 121.473701, 31.230416, "Shanghai"); // 查询北京附近的地点(1000公里范围内) List<GeoRadiusResponse> nearbyPlaces = jedis.georadius("locations", 116.397428, 39.90923, 1000, GeoUnit.KM); for (GeoRadiusResponse response : nearbyPlaces) { GeoCoordinate coordinate = response.getGeoCoordinate(); String place = response.getMemberByString(); double distance = response.getDistance().getDistance(); System.out.println(place + " - 距离: " + distance + " 公里"); } // 计算北京和上海之间的距离 double distance = jedis.geodist("locations", "Beijing", "Shanghai", GeoUnit.KM); System.out.println("北京和上海之间的距离: " + distance + " 公里"); jedis.close(); } }
当单个实例存储超过 500 万位置点时,建议采用分片集群。此外,可以结合其他 Redis 数据类型(如列表、哈希表)实现更复杂的应用。
Redis GEO 提供了一种轻量级且高效的地理空间数据处理方案,适用于多种需要快速地理位置查询和计算的场景
原文链接:https://blog.csdn.net/weixin_44984196/article/details/148513887?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522ec1125581553d1a943737cc6736c66e9%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=ec1125581553d1a943737cc6736c66e9&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-10-148513887-null-null.nonecase&utm_term=geo%E6%98%AF%E4%BB%80%E4%B9%88