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

背景

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

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
动物园©102.714992,25.061773

添加地理位置

geoadd

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

geoadd 语法格式如下:

GEOADD key longitude latitude member [longitude latitude member ...]

重点参数说明如下:

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

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

以下实例中key为km

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 语法格式如下:

GEOPOS key member [member ...]

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

127.0.0.1:6379> geopos km a
1) 1) "102.69033282995223999"
   2) "25.04997624927904809"

距离统计

geodist

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

geodist 语法格式如下:

GEODIST key member1 member2 [m|km|ft|mi]

member1 member2 为两个地理位置。

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

m :米,默认单位。

km :千米。

mi :英里。

ft :英尺。

# 计算翠湖公园(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 语法格式如下:

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: 查找结果根据从远到近排序。

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

# 根据查询的坐标,查询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

删除地理位置信息

zrem key member [member ...]

比如c成员的坐标信息

127.0.0.1:6379> zrem km c
(integer) 1

场景实践

引入jedis

<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>5.1.0</version>
        </dependency>

附近的门店

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

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

实现思路

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

代码实现

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");
        }
    }

结果:

门店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. 根据自身的坐标,去查询附近的附近的人

代码实现

 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");
        }
    }

结果

zhangsan 距离我:0.6776km
lisi 距离我:1.645km
xiaoming 距离我:3.5812km

计算距离

计算两个坐标之间的距离

代码实现

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");
    }

结果

zhangsan与lisi距离:5.208km

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/334845.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu系统Git的安装配置及使用笔记(更新中)

Ubuntu下Git的下载及配置 (1)、下载git 打开终端命令窗口,输入&#xff1a;sudo apt-get install git 提示&#xff1a;sudo命令是用来以其他身份来执行命令&#xff0c;预设的身份为root,使用sudo时必须先输入密码 (2)、可以使用命令git --version查看git的版本号 (3)、设置…

排序链表(LeetCode 148)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路参考文献 1.问题描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff…

git中合并分支时出现了代码冲突怎么办

目录 第一章、Git代码冲突介绍1.1&#xff09;什么是Git代码冲突①git merge命令介绍②代码冲突原因 1.2&#xff09;提示代码冲突的两种情况①本地不同分支的文件有差异时&#xff1a;②本地仓库和git远程仓库的文件有差异时&#xff1a; 1.3&#xff09;解决合并时的代码冲突…

【冥想X理工科思维】场景7:背锅挨批后…

冥想音频合集&#xff1a;职场解压冥想音频 压力场景&#xff1a; 明明不是我的错&#xff0c;却不得不替领导背锅&#xff0c;受到大老板和其它团队领导的疯狂指责&#xff0c;如何借助冥想&#xff0c;处理批评后的负面情绪&#xff1f; 点击看大图&#xff1a; 详细说明&…

HBase学习五:运维排障

1、负载均衡 1.1 Rgion迁移 在当前的HBase版本中,Region迁移虽然是一个轻量级操作,但实现逻辑依然比较复杂,≈复杂性主要表现在两个方面:其一,Region迁移过程涉及多种状态的改变;其二,迁移过程中涉及Master、ZooKeeper(ZK)以及RegionServer等多个组件的相互协调。 …

JS执行顺序

众所周知&#xff0c;JavaScript 是单线程语言,只能同时执行做一件事(js只有一个线程&#xff0c;称之为main thread-主线程) 1.Javascript 运行机制 main thread 主线程和 call-stack 调用栈(执行栈)&#xff0c;所有的任务都会被放到调用栈等待主线程执行。 2.Javascript 任…

Addressables(2) ResourceLocation和AssetReference

IResourceLocation var op Addressables.LoadResourceLocationsAsync(key); var result op.WaitForCompletion(); 把加载的Key塞进去&#xff0c;不难看出&#xff0c;IResourceLocation可以用来获得资源的详细信息 很适合用于更新分析&#xff0c;或者一些检查工具 AssetR…

HTML动态房屋装饰特效

下面是代码&#xff1a; <!DOCTYPE html> <html lang"en" ><head><meta charset"UTF-8"><title>HTML5房屋装饰工具DEMO演示</title><link rel"stylesheet" href"css/style.css"></he…

Maven(五)如何只打包项目某个模块及其依赖模块?

目录 一、背景二、解决方案三、补充3.1 提出疑问3.2 解答 一、背景 在 SpringCloud 微服务框架下&#xff0c;会存在多个模块。当我们需要对其中某一个服务打包的时候&#xff0c;需要将该服务依赖的模块一起打包更新&#xff0c;如果项目比较小的话我们可以直接将项目中的所有…

JAVA 中controller,service,serviceImpl,mapper

Controller&#xff1a;控制器 业务模块流程的控制&#xff0c;不同的业务流程有不同的控制器 负责请求转发&#xff0c;接收页面过来的参数&#xff0c;传给service处理&#xff0c;接到返回值&#xff0c;并再次传给页面 控制处理前端请求和响应&#xff0c;与前端进行交互&…

Verilog基础:强度建模(二)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 三、拥有单个强度和确定值的net型信号的线与组合&#xff08;线网多驱动&#xff09; 首先来说明一下什么叫信号拥有单个强度和确定值&#xff0c;其实如果一个ne…

刷题第一天

1.阶乘求和 令 S 1! 2! 3! ... 202320232023! &#xff0c;求 S 的末尾 9 位数字。 提示&#xff1a;答案首位不为 0 。 很明显,这题如果死算肯定会超出最大数据类型的范围,n∈[1,202320232023],n越大,其中包含10,2,5,的数字(5,12,25,32......)也变多,这些数字相乘末尾为…

YOLOv3:算法与论文详细解读

【yolov1&#xff1a;背景介绍与算法精讲】 【yolo9000&#xff1a;Better, Faster, Stronger的目标检测网络】 目录 一、YOLOv3概述二、创新与改进三、改进细节3.1 多尺度特征3.2 不同尺度先验框3.3 完整的网络结构3.3 Darknet-53主干网络3.4 残差网络3.4.1 恒等映射3.4.2 网络…

app支付宝登录

url的app_id是商户的appid url的redirect_uri是支付宝授权成功后跳回地址&#xff08;授权成功之后会在支付宝中打开这个地址&#xff09; 仅需修改app_id的值和redirect_uri的值 encodeURIComponent()是为了防止url中有特殊字符导致传参失败&#xff0c;必须的 doVerify(){le…

【c语言】扫雷(上)

先开一个test.c文件用来游戏的逻辑测试&#xff0c;在分别开一个game.c文件和game.h头文件用来实现游戏的逻辑 主要步骤&#xff1a; 游戏规则&#xff1a; 输入1&#xff08;0&#xff09;开始&#xff08;结束&#xff09;游戏&#xff0c;输入一个坐标&#xff0c;如果该坐…

UE5 蓝图编辑美化学习

虚幻引擎中干净整洁蓝图的15个提示_哔哩哔哩_bilibili 1.双击线段成节点。 好用&#xff0c;爱用 2.用序列节点 好用&#xff0c;爱用 3.用枚举。 好用&#xff0c;能避免一些的拼写错误 4.对齐节点 两点一水平线 5.节点上下贴节点 &#xff08;以前不懂&#xff0c;现在经常…

小白水平理解面试经典题目LeetCode 125 Valid Palindrome(验证回文串)

125 验证回文串 说到公司面试&#xff0c;那就是得考出高度&#xff0c;考出水平&#xff0c;什么兼顾这两者呢&#xff0c;那就得看这道 原题描述&#xff1a; 给定一个字符串&#xff0c;判断它是否是回文串。回文串是指正读和反读都一样的字符串。 输入: “A man, a pla…

C#使用DateTime.Now静态属性动态获得系统当前日期和时间

目录 一、实例 1.源码 2.生成效果 二、相关知识点 1.Thread类 &#xff08;1&#xff09;Thread.Sleep()方法 &#xff08;2&#xff09;Thread(ThreadStart) &#xff08;3&#xff09;IsBackground &#xff08;4&#xff09;Invoke( &#xff09; 2.CreateGrap…

【算法实验】实验3

实验3-1 快速排序 #include<bits/stdc.h> using namespace std; void Quicksort(int arry[],int L,int R) {if(L>R) return ;int leftL,rightR;int pivotarry[left];while(left<right){while(left<right&&arry[right]>pivot)right--;if(left<rig…

SD-WAN企业组网:实现高效、安全的跨国企业连接

在当今数字化时代&#xff0c;企业日益全球化&#xff0c;跨国办公成为常态。为了应对这一挑战&#xff0c;越来越多的企业选择采用先进的网络技术&#xff0c;其中SD-WAN&#xff08;软件定义广域网&#xff09;便是一种备受青睐的解决方案。 什么是SD-WAN企业组网&#xff1…