【redis】数据类型之geo

Redis的GEO数据类型用于存储地理位置信息(如经纬度),并提供高效的地理位置查询功能(如计算两地距离、搜索附近地点等)。其底层基于Sorted Set(有序集合)实现,通过Geohash编码将经纬度转换为分数(score)进行存储。

有关hyperloglog类型的命令可以通过help @geo命令来查看。有关命令的使用可以通过help 命令来查看,例如help geoadd

命令的使用

GEOADD

GEOADD:将一个或多个地理坐标(经度、纬度、名称)添加到指定 key

语法:

shell 复制代码
GEOADD key [NX|XX] [CH] longitude latitude member [longitude latitude member ...]

选项说明:

  • key:用于存储地理位置信息的键名。
  • longitude:地理位置的经度,经度范围:-180180
  • latitude:地理位置的纬度,纬度范围:-85.0511287885.05112878
  • member:与经纬度关联的成员名称,通常是一个字符串标识符,比如一个地点名。
  • NX:仅添加新成员(不更新已存在的成员)。
  • XX:仅更新已存在的成员(不添加新成员)。
  • CH:返回被修改的成员数量(默认返回新增数量)。

使用:

shell 复制代码
127.0.0.1:6379> geoadd cities 116.28 39.54 beijing 121.29 31.14 shanghai 117.11 39.09 tianjin
(integer) 3

127.0.0.1:6379> type cities
zset

GEOPOS

GEOPOS:查询一个或多个成员的经纬度。

语法:

shell 复制代码
GEOPOS key member [member ...]

使用:

shell 复制代码
127.0.0.1:6379> geopos cities beijing tianjin
1) 1) "116.28000229597091675"
   2) "39.54000124957348561"
2) 1) "117.11000114679336548"
   2) "39.08999952855024418"

GEODIST

GEODIST:计算两个成员间的距离,支持单位:m(米,默认)、km(千米)、mi(英里)、ft(英尺)。

语法:

shell 复制代码
GEODIST key member1 member2 [M|KM|FT|MI]

使用:

shell 复制代码
127.0.0.1:6379> geodist cities beijing tianjin km
"87.2150"

GEOHASH

GEOHASH:返回成员的Geohash字符串(将二维经纬度编码为一维字符串,便于比较位置相似性)。

语法:

shell 复制代码
GEOHASH key member [member ...]

使用:

shell 复制代码
127.0.0.1:6379> geohash cities beijing tianjin
1) "wx48yn090q0"
2) "wwgq2uhgub0"

GEORADIUS

GEORADIUS:根据给定的中心点坐标和半径,查找附近的成员。

语法:

shell 复制代码
GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]

选项说明:

  • key:存储地理位置信息的Redis键名。
  • longitude和latitude:查询的中心点的经度和纬度。
  • radius:搜索半径,可以是米(m)、千米(km)、英尺(ft)或英里(mi)。
  • [WITHCOORD]:返回匹配元素的经纬度。
  • [WITHDIST]:返回匹配元素到中心点的距离。
  • [WITHHASH]:返回匹配元素的Geohash值。
  • [COUNT count]:限制返回结果的数量。
  • [ASC|DESC]:按距离升序或降序排序。
  • [STORE key]:将返回的结果存储到指定的Redis键中。
  • [STOREDIST key]:将返回的结果及其到中心点的距离存储到指定的Redis键中。

使用:

shell 复制代码
127.0.0.1:6379> georadius cities 119.30 35.35 2000 km count 2
1) "tianjin"
2) "shanghai"

GEORADIUSBYMEMBER

GEORADIUSBYMEMBER:根据给定的成员和半径,查找附近的成员。

语法:

shell 复制代码
GEORADIUSBYMEMBER key member radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]

使用:

shell 复制代码
127.0.0.1:6379> georadiusbymember cities beijing 1000 km withdist
1) 1) "beijing"
   2) "0.0000"
2) 1) "tianjin"
   2) "87.2150"

GEORADIUS_RO

GEORADIUS_RO:GEORADIUS_RO命令是GEORADIUS命令的只读版本。从Redis版本6.2.0开始,GEORADIUS命令被视为已废弃,建议在新代码中使用GEOSEARCH和GEOSEARCHSTORE命令替代GEORADIUS的相关功能。

语法:

shell 复制代码
GEORADIUS_RO key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC]

使用:

shell 复制代码
127.0.0.1:6379> georadius_ro cities 119.30 35.35 1000 km count 2 withdist
1) 1) "tianjin"
   2) "458.9460"
2) 1) "shanghai"
   2) "503.4887"

GEORADIUSBYMEMBER_RO

GEORADIUSBYMEMBER_RO:GEORADIUSBYMEMBER_RO命令是GEORADIUSBYMEMBER命令的只读版本。

语法:

shell 复制代码
GEORADIUSBYMEMBER_RO key member radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC]

使用:

shell 复制代码
127.0.0.1:6379> georadiusbymember_ro cities beijing 1000 km withdist
1) 1) "beijing"
   2) "0.0000"
2) 1) "tianjin"
   2) "87.2150"

GEOSEARCH

GEOSEARCH:根据指定的查询参数在Redis的地理空间数据集中搜索符合条件的位置。

语法:

shell 复制代码
GEOSEARCH key FROMMEMBER member|FROMLONLAT longitude latitude BYRADIUS radius M|KM|FT|MI|BYBOX width height M|KM|FT|MI [ASC|DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH]

选项说明:

  • key:存储地理位置信息的Redis键名。
  • [FROMMEMBER member]:使用有序集中给定的现有位置作为查询的中心点。
  • [FROMCOORD longitude latitude]:使用给定的经度和纬度作为查询的中心点。
  • [BYRADIUS radius unit]:根据给定的半径在一个圆形区域中进行搜索。
  • [BYBOX width height unit]:根据给定的高度和宽度在一个矩形区域中进行搜索。
  • [WITHCOORD]:返回匹配位置的经度和纬度。
  • [WITHDIST]:返回匹配位置与指定中心点的距离。
  • [ASC|DESC]:按距离升序或降序排序返回结果。
  • [COUNT count]:限制返回结果的数量。
  • [STORE key]:将搜索结果存储到指定的新键中。
  • [STOREDIST key]:将搜索结果及其与查询点的距离存储到指定的新键中。

使用:

shell 复制代码
127.0.0.1:6379> geosearch cities fromlonlat 119.30 35.35 byradius 1000 km count 2
1) "tianjin"
2) "shanghai"

127.0.0.1:6379> geosearch cities frommember beijing byradius 2000 km count 2
1) "beijing"
2) "tianjin"

GEOSEARCHSTORE

GEOSEARCHSTORE:与GEOSEARCH命令类似,但它不直接返回搜索结果给客户端,而是将搜索结果存储到一个新的键中。这对于需要在服务器端保存搜索结果以便后续处理或分析的场景非常有用。

语法:

shell 复制代码
GEOSEARCHSTORE destination source FROMMEMBER member|FROMLONLAT longitude latitude BYRADIUS radius M|KM|FT|MI|BYBOX width height M|KM|FT|MI [ASC|DESC] [COUNT count [ANY]] [STOREDIST]

使用:

shell 复制代码
127.0.0.1:6379> geosearchstore searchResult cities frommember beijing byradius 2000 km count 2
(integer) 2

127.0.0.1:6379> zrange searchResult 0 -1 withscores
1) "beijing"
2) "4069140601296155"
3) "tianjin"
4) "4069185489583420"

应用场景

附近的人/地点:根据用户位置搜索周边的餐厅、商店等。

距离计算:物流应用中计算配送距离。

地理围栏:监控设备或用户是否进入特定区域。

底层实现与性能

Geohash编码:将经纬度转换为一个double类型的分数(score),存储在Sorted Set中。

查询原理:利用Sorted Set的范围查询特性,快速筛选出Geohash相近的位置。

注意事项

数据精度:Geohash精度受半径影响,小范围搜索更准确。

性能优化:大量数据时建议分片(按区域拆分多个key)。

命令版本:Redis 6.2+推荐使用GEOSEARCH替代GEORADIUSGEORADIUSBYMEMBER

无法分页:例如附近的人列表无法根据距离从近到远实现分页查询,此时需要使用mongo或者es来实现。

在Java中的使用

java 复制代码
package com.morris.redis.demo.geo;

import org.redisson.Redisson;
import org.redisson.api.GeoUnit;
import org.redisson.api.RGeo;
import org.redisson.api.RedissonClient;
import org.redisson.api.geo.GeoSearchArgs;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;

import java.util.List;

/**
 * redisson中geo的使用
 */
public class RedissonGeoDemo {

    public static void main(String[] args) {
        // 配置Redisson客户端
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");

        // 创建Redisson客户端实例
        RedissonClient redisson = Redisson.create(config);

        RGeo<Object> geo = redisson.getGeo("geo:cities", StringCodec.INSTANCE);
        geo.add(116.28, 39.54, "beijing");
        geo.add(121.29, 31.14, "shanghai");
        geo.add(117.11, 39.09, "tianjin");

        Double dist = geo.dist("beijing", "shanghai", GeoUnit.KILOMETERS);
        System.out.println(dist); // 1038.543

        List<Object> search = geo.search(GeoSearchArgs.from(119.30, 35.35).radius(1000, GeoUnit.KILOMETERS));
        System.out.println(search); // [beijing, tianjin, shanghai]

        redisson.shutdown();
    }
}
相关推荐
陈卓4101 小时前
Redis-限流方案
前端·redis·bootstrap
一只淡水鱼668 小时前
【redis】使用redis作为缓存时所注意事项
redis·缓存
笑远15 小时前
MySQL 主主复制与 Redis 环境安装部署
redis·mysql·adb
小斌的Debug日记16 小时前
框架基本知识总结 Day16
redis·spring
morris13118 小时前
【redis】布隆过滤器的Java实现
java·redis·布隆过滤器
椰椰椰耶18 小时前
【redis】全局命令set、get、keys
数据库·redis·缓存
月落星还在18 小时前
Redis 内存淘汰策略深度解析
数据库·redis·缓存
五行星辰18 小时前
Java链接redis
java·开发语言·redis
左灯右行的爱情18 小时前
Redis- 切片集群
数据库·redis·缓存