水煮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);
    }
相关推荐
Dcs1 分钟前
常见 GC 垃圾收集器对比分析
java
程序员岳焱4 分钟前
Java高级反射实战:15个场景化编程技巧与底层原理解析
java·后端·编程语言
程序员小假4 分钟前
说一说 Netty 中的心跳机制
java·后端
chen.@-@10 分钟前
后端下载限速(redis记录实时并发,bucket4j动态限速)
数据库·redis·缓存
真实的菜11 分钟前
消息队列处理模式:流式与批处理的艺术
java
盖世英雄酱5813626 分钟前
Java 内存管理技巧(新手必看集合篇)
java
码农小灰29 分钟前
Java 8 Stream API 入门到实践详解
java·java案例
步、步、为营34 分钟前
.NET 事件模式举例介绍
java·开发语言·.net
呼拉拉呼拉34 分钟前
Redis高可用架构
数据库·redis·架构·高可用架构
cui_hao_nan37 分钟前
设计模式——模板方法
java·设计模式