前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何实现查找附近的人-GEO

如何实现查找附近的人-GEO

原创
作者头像
柯柏技术笔记
发布2024-01-19 17:00:46
3890
发布2024-01-19 17:00:46
举报
文章被收录于专栏:柯柏后端架构

背景

打开美团,可以通过自身定位查看附近的商品。打开社交软件,可以查看附近的人交友。打开滴滴,可以查看的附近的共享单车,那这些是如何实现?

Redis GEO

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。

Redis GEO 操作方法有:

  • geoadd:添加地理位置的坐标。
  • geopos:获取地理位置的坐标。
  • geodist:计算两个位置之间的距离。
  • georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
  • georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
  • geohash:返回一个或多个位置对象的 geohash 值。
  • zrem:删除地理位置

基础使用

数据准备

先用百度地图提供的经纬度查询工具 拾取坐标系统,准备一些坐标信息:

选择三个点的坐标作为测数据,如下

地点

坐标

翠湖公园(a)

102.710039,25.054179

大观公园(b)

102.679209,25.027989

动物园(c)

102.714992,25.061773

添加地理位置

geoadd

geoadd 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。

geoadd 语法格式如下:

代码语言:shell
复制
GEOADD key longitude latitude member [longitude latitude member ...]

重点参数说明如下:

  • longitude 表示经度
  • latitude 表示纬度
  • member 是为此经纬度起的名字

此命令支持一次添加一个或多个位置信息。

以下实例中key为km

代码语言:shell
复制
geoadd km  102.710039 25.054179 "a"
geoadd km  102.679209 25.027989  "b"
geoadd km  102.714992 25.061773  "c"

查询位置信息

geopos

geopos 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。

geopos 语法格式如下:

代码语言:shell
复制
GEOPOS key member [member ...]

此命令支持查看一个或多个位置信息

代码语言:shell
复制
127.0.0.1:6379> geopos km a
1) 1) "102.69033282995223999"
   2) "25.04997624927904809"

距离统计

geodist

geodist 用于返回两个给定位置之间的距离。

geodist 语法格式如下:

代码语言:shell
复制
GEODIST key member1 member2 [m|km|ft|mi]

member1 member2 为两个地理位置。

最后一个距离单位参数说明:

m :米,默认单位。

km :千米。

mi :英里。

ft :英尺。

代码语言:shell
复制
# 计算翠湖公园(a)到大观公园(b)的距离,单位km
127.0.0.1:6379> geodist km a b km
"4.2587"

计算翠湖公园(a)到大观公园(b)的距离是4.25公里,跟地图比对,结果基本吻合

查询某位置内的其他成员信息

georadius

以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

georadiusbymember

georadiusbymember 和 georadius 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。georadius 与 georadiusbymember 语法格式如下:

代码语言:shell
复制
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

参数说明:

  • m 米,默认单位。
  • km :千米。
  • mi :英里。
  • t :英尺。
  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
  • WITHCOORD: 将位置元素的经度和纬度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
  • COUNT 限定返回的记录数。
  • ASC: 查找结果根据距离从近到远排序。
  • DESC: 查找结果根据从远到近排序。

根据给定的经纬度坐标查询附近的成员

代码语言:shell
复制
# 根据查询的坐标,查询5km以内的成员信息
127.0.0.1:6379> georadius km 102.705224 25.0499233 5 km
1) "b"
2) "a"
3) "c"

# 根据坐标查询5km以内的成员信息,并返回位置元素与中心之间的距离
127.0.0.1:6379> georadius km 102.705224 25.0499233 5 km withdist
1) 1) "b"
   2) "3.5812"
2) 1) "a"
   2) "0.6776"
3) 1) "c"
   2) "1.6450"
   
#根据坐标查询5km以内的成员信息,并返回位置元素与中心之间的距离,从近到远,返回2个成员
georadius km 102.705224 25.0499233 5 km withdist count 2 asc
1) 1) "a"
   2) "0.6776"
2) 1) "c"
   2) "1.6450"
# 根据成员的坐标查询5km以内的成员信息,并返回位置元素与中心之间的距离,从近到远,返回2个成员
  127.0.0.1:6379> georadiusbymember km a  5 km withdist count 2 asc
1) 1) "a"
   2) "0.0000"
2) 1) "c"
   2) "0.9813" 

删除地理位置

zrem

删除地理位置信息

代码语言:shell
复制
zrem key member [member ...]

比如c成员的坐标信息

代码语言:shell
复制
127.0.0.1:6379> zrem km c
(integer) 1

场景实践

引入jedis

代码语言:java
复制
<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>5.1.0</version>
        </dependency>

附近的门店

查找附近的门店,本地生活这种场景特别多。

我想喝一杯瑞幸咖啡,打开瑞幸的微信小程序,根据自身当前定位,查看下我附近都有哪些门店,哪个离我最近,那我就在哪个门店下单。

实现思路

  1. 门店的地址固定的,除非搬迁或者闭店,才会发生改变,根据门店地址换算为经纬度存储在redis
  2. 根据gps定位,获取自身当前的经纬度
  3. 根据定位的经纬度查询附近的门店

代码实现

代码语言:java
复制
public static void main(String[] args) {
        Jedis jedis = new Jedis("10.1.250.157",6379);
        jedis.auth("google00");
        //添加门店a
        jedis.geoadd("store",102.710039,25.054179,"a");
        //添加门店b
        jedis.geoadd("store",102.679209,25.027989,"b");
        //添加门店c
        jedis.geoadd("store",102.714992 ,25.061773,"c");

        //我当前定位的坐标,查询附近的门店,从近到远的门店,并显示距离
        GeoRadiusParam geoRadiusParam = new GeoRadiusParam();
        geoRadiusParam.withDist().sortAscending();
        List<GeoRadiusResponse>  storeList =  jedis.georadius("store",102.705224 ,25.0499233,5,GeoUnit.KM,geoRadiusParam);
        for (GeoRadiusResponse r : storeList) {
            System.out.println("门店"+r.getMemberByString()+" 距离我:"+r.getDistance()+"km");
        }
    }

结果:

代码语言:java
复制
门店a 距离我:0.6776km
门店c 距离我:1.645km
门店b 距离我:3.5812km

注意点:所有门店数据放入到store这个key里,查询如果频繁,这个key容易成为热key,可以使用redis集群,同样的数据多设置几个key,比如:store_1,store_2,store_3 ,查询的时候可以根据用户id取余,命中不同的key查询

附近的人

社交软件,经常看到附近的人,怎么做呢

实现思路

  1. 打开软件,当点击附近的人,定位自身的坐标
  2. 根据自身的坐标,去查询附近的附近的人

代码实现

代码语言:java
复制
 public static void main(String[] args) {
        Jedis jedis = new Jedis("10.1.250.157",6379);
        jedis.auth("google00");
        //添加张三
        jedis.geoadd("person_member",102.710039,25.054179,"zhangsan");
        //添加小明
        jedis.geoadd("person_member",102.679209,25.027989,"xiaoming");
        //添加李四
        jedis.geoadd("person_member",102.714992 ,25.061773,"lisi");

        //我当前定位的坐标,查询附近5km范围内的人,从近到远排序,并显示距离
        GeoRadiusParam geoRadiusParam = new GeoRadiusParam();
        geoRadiusParam.withDist().sortAscending();
        List<GeoRadiusResponse>  storeList =  jedis.georadius("person_member",102.705224 ,25.0499233,5,GeoUnit.KM,geoRadiusParam);
        for (GeoRadiusResponse r : storeList) {
            System.out.println(r.getMemberByString()+" 距离我:"+r.getDistance()+"km");
        }
    }

结果

代码语言:java
复制
zhangsan 距离我:0.6776km
lisi 距离我:1.645km
xiaoming 距离我:3.5812km

计算距离

计算两个坐标之间的距离

代码实现

代码语言:java
复制
public static void main(String[] args) {
        Jedis jedis = new Jedis("10.1.250.157",6379);
        jedis.auth("google00");
        //添加张三
        jedis.geoadd("person_member",102.710039,25.054179,"zhangsan");
        //添加小明
        jedis.geoadd("person_member",102.679209,25.027989,"xiaoming");
        //添加李四
        jedis.geoadd("person_member",102.714992 ,25.061773,"lisi");

        //我当前定位的坐标,查询附近5km的人,从近到远排序,并显示距离
        GeoRadiusParam geoRadiusParam = new GeoRadiusParam();
        geoRadiusParam.withDist().sortAscending();
        Double dist = jedis.geodist("person_member","xiaoming","lisi",GeoUnit.KM);
        System.out.println("xiaoming与lisi距离:"+dist+"km");
    }

结果

代码语言:java
复制
zhangsan与lisi距离:5.208km

写作不易,刚好你看到,刚好对你有帮助,动动小手,点点赞,欢迎转发,有疑问的欢迎留言或者私信讨论,有问必回。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • Redis GEO
  • 基础使用
    • 数据准备
      • 添加地理位置
        • 查询位置信息
          • 距离统计
            • 查询某位置内的其他成员信息
              • 删除地理位置
              • 场景实践
                • 附近的门店
                  • 实现思路
                  • 代码实现
                • 附近的人
                  • 实现思路
                  • 代码实现
                • 计算距离
                  • 代码实现
              相关产品与服务
              云数据库 Redis®
              腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档