水煮Redisson(二二)-GEO功能介绍

前言

Redis提供了GEO地理索引的实现,其存储结构本质上来说是一个ZSET,这一点可以从Redisson中的GEO接口看出来【public interface RGeoAsync extends RScoredSortedSetAsync

Redis 命令描述

  • GEOHASH 返回一个或多个位置元素的 Geohash 表示,Redis 使用 Geohash 技术的变体来表示元素的位置
  • GEOPOS 从 key 里返回所有给定位置元素的位置(经度和纬度)
  • GEODIST 返回两个给定位置之间的距离
  • GEORADIUS 以给定的经纬度为中心, 找出某一半径内的元素
  • GEOADD 将指定的地理空间位置(纬度、经度、名称)添加到指定的 key 中
  • GEORADIUSBYMEMBER 找出位于指定范围内的元素,中心点是由给定的位置元素决定

注意:没有 GEODEL 命令,因为可以使用 ZREM 来删除元素,地理索引结构只是一个有序集合【zset】。
注意:如果数据量过亿甚至更大,可能造成redis节点卡顿,这时就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 zset 集合的大小。(注意:zset集合大小,进行合适地切分)

新增地理元素

csharp 复制代码
        RGeo<String> geo = client.getGeo("GEO_TEST");
        geo.add(new GeoEntry(121.472641,31.231707,"上海"));
		// 新增返回1,更新返回0
        long 添加数量 = geo.add(new GeoEntry(116.405289,39.904987,"北京"));
		System.out.println("添加数量:"+添加数量);

经纬度越界

  • 有效经度从-180到180度。
  • 有效纬度从 -85.05112878 到 85.05112878 度。
    当用户尝试索引超出指定范围的坐标时,该命令将报告错误。
csharp 复制代码
        // 异常:RedisException: ERR invalid longitude,latitude pair xxx,xxx
        geo.add(new GeoEntry(183.549130,22.198750,"经度越界"));
        geo.add(new GeoEntry(113.549130,92.198750,"纬度越界"));

计算两个元素之间的距离

ini 复制代码
        Double distance = geo.dist("北京", "上海", GeoUnit.KILOMETERS);
        System.out.println("北京和上海的距离:" + distance + " 千米");

输出信息
北京和上海的距离:1067.597 千米

元素的经纬度信息

ini 复制代码
        Map<String, GeoPosition> pos = geo.pos("北京", "上海");
        System.out.println("两个元素的经纬度信息\n" + pos);

输出信息
两个元素的经纬度信息
{上海=GeoPosition [longitude=121.47264093160629, latitude=31.231707441819232], 北京=GeoPosition [longitude=116.40528827905655, latitude=39.90498588819134]}

附近的元素

ini 复制代码
        // 返回10个在上海附近200米的元素名称和距离
        Map<String, Double> radiusWithDistance = geo.radiusWithDistance(
                "上海", 500, GeoUnit.KILOMETERS, GeoOrder.ASC, 10);
        System.out.println("上海附近500千米的元素名称和距离[千米]\n" + radiusWithDistance);
        // 经度 120,纬度30,半径500千米,这个范围内的元素
        List<String> cities = geo.radius(120, 30, 500, GeoUnit.KILOMETERS);
        System.out.println("经度120,纬度30,半径500千米,这个范围内的元素\n" + cities);
        // 返回10个在经度15,纬度37附近200米内的元素名称和距离,方便在列表中显示
        Map<String, Double> radiusWithDistance2 = geo.radiusWithDistance(
                120, 30, 500, GeoUnit.KILOMETERS, GeoOrder.ASC, 10);
        System.out.println("经度120,纬度30附近500千米内的元素名称和距离[千米]\n" + radiusWithDistance2);

输出信息
上海附近500千米的元素名称和距离[千米]
{上海=0.0, 杭州=164.0861, 南京=271.5419, 合肥=403.2241}
经度120,纬度30,半径500千米,这个范围内的元素
[南昌, 合肥, 杭州, 上海, 南京, 福州]
经度120,纬度30附近500千米内的元素名称和距离[千米]
{杭州=35.2204, 上海=196.5638, 南京=255.6618, 合肥=331.7151, 南昌=424.5977, 福州=441.8072}

redisson实现

RGeo的实现类是【RedissonGeo】,其中基本都是直接调用redis的指令来完成计算,没有特别的自定义逻辑,所以不进行详细介绍。例如:

scss 复制代码
    public RFuture<Map<V, Double>> radiusWithDistanceAsync(double longitude, double latitude, double radius,
            GeoUnit geoUnit, GeoOrder geoOrder, int count) {
        return commandExecutor.readAsync(getName(), codec, GEORADIUS_RO_DISTANCE, getName(), convert(longitude),
                convert(latitude), radius, geoUnit, "WITHDIST", "COUNT", count, geoOrder);
    }
相关推荐
雾月555 分钟前
LeetCode 1292 元素和小于等于阈值的正方形的最大边长
java·数据结构·算法·leetcode·职场和发展
hnlucky10 分钟前
redis 数据类型新手练习系列——Hash类型
数据库·redis·学习·哈希算法
24k小善1 小时前
Flink TaskManager详解
java·大数据·flink·云计算
想不明白的过度思考者1 小时前
Java从入门到“放弃”(精通)之旅——JavaSE终篇(异常)
java·开发语言
.生产的驴2 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
猿周LV2 小时前
JMeter 安装及使用 [软件测试工具]
java·测试工具·jmeter·单元测试·压力测试
晨集2 小时前
Uni-App 多端电子合同开源项目介绍
java·spring boot·uni-app·电子合同
AnsenZhu2 小时前
2025年Redis分片存储性能优化指南
数据库·redis·性能优化·分片
时间之城2 小时前
笔记:记一次使用EasyExcel重写convertToExcelData方法无法读取@ExcelDictFormat注解的问题(已解决)
java·spring boot·笔记·spring·excel
椰羊~王小美2 小时前
LeetCode -- Flora -- edit 2025-04-25
java·开发语言