返回顶部
首页 > 资讯 > 数据库 >附近的人?你zao吗?
  • 788
分享到

附近的人?你zao吗?

附近的人?你zao吗? 2014-06-26 19:06:01 788人浏览 无得
摘要

前几天收到一个新的需求,需要实现类似“附近的人”的功能:根据自己当前的定位,获取距离范围内的所有任务地点。刚看到这个需求时有点懵逼,第一想到的就是要利用地球的半径公式去计算距离,也就是把地球想成一个球体,去计算球上两点之间的距离。可想而知

附近的人?你zao吗?

前几天收到一个新的需求,需要实现类似“附近的人”的功能:根据自己当前的定位,获取距离范围内的所有任务地点。刚看到这个需求时有点懵逼,第一想到的就是要利用地球的半径公式去计算距离,也就是把地球想成一个球体,去计算球上两点之间的距离。可想而知,这样的方法效率会比较低,每条数据都要来与本人的坐标做计算,太过繁琐。经过大佬的指点,想到了用Redis自带的GEO来实现此功能。

实战演习

以下是给大家准备的sql脚本

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for job_base_info
-- ----------------------------
DROP TABLE IF EXISTS `job_base_info`;
CREATE TABLE `job_base_info`  (
  `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT "任务ID",
  `job_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "任务名称",
  `job_location` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT "" COMMENT "任务地点位置经纬度-逗号隔开",
  `job_detail_address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "任务详细地点位置",
  PRIMARY KEY (`job_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "工作任务详情基础信息表" ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of job_base_info
-- ----------------------------
INSERT INTO `job_base_info` VALUES (1, "软件开发", "120.433576,36.139697", "青岛市崂山区海尔路1号");
INSERT INTO `job_base_info` VALUES (2, "儿童摄影", "120.420297,36.156589", "山东省青岛市李沧区书院路188号");
INSERT INTO `job_base_info` VALUES (3, "清洁家用电器", "120.025706,36.281478", "山东省青岛市胶州市福州支路232号东60米");
INSERT INTO `job_base_info` VALUES (4, "辩论学习", "120.505042,36.171247", "松岭路238号中国海洋大学内");

SET FOREIGN_KEY_CHECKS = 1;

废话不多说,让我们来看看具体的实现

(1)我们要在程序启动时,将数据库中的任务数据的坐标信息初始化到redis中(此处暂且忽略任务的增删改查对redis中数据的影响)

@PostConstruct
public void init(){
    //首先要删除该key的所有值
    redisTemplate.delete("company-task");
    List jobBaseInfoList = jobBaseInfoMapper.selectList(Wrappers.emptyWrapper());
    jobBaseInfoList.stream().forEach(item->{
        String jobLocation = item.getJobLocation();
        if(StrUtil.isNotEmpty(jobLocation)){
            String[] split = jobLocation.split(",");comp
            if(split.length==2){
                //Point(经度, 纬度) 
                Point point = new Point(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
                //将经纬度数据及其id存到key为“company-task”中
                redisTemplate.opsForGeo().add("company-task",point,item.getJobId());
            }
        }
    });
}

(2)查询当前坐标下3km范围内的任务地点(外加根据任务名搜索的联合查询)

@Override
public List selectJobList(JobBaseInfoDTO jobBaseInfoDTO) {
    String jobLocation = jobBaseInfoDTO.getJobLocation();
    //距离
    Double distance = jobBaseInfoDTO.getDistance();
    List idList = new ArrayList<>();
    if(StringUtils.isNotNull(jobLocation) && StringUtils.isNotNull(distance)){
        String[] split = jobLocation.split(",");
        if(split.length==2){
            //Point(经度, 纬度) Distance(距离量, 距离单位)
            Circle circle = new Circle(new Point(Double.parseDouble(split[0]),Double.parseDouble(split[1])),
                                       new Distance(distance, Metrics.KILOMETERS));
            //params: key, Circle 获取存储到redis中的distance范围内的所有任务地点数据
            GeoResults radius = redisTemplate.opsForGeo().radius("company-task", circle);
            List contentList = radius.getContent();
            if(contentList.size()>0){
                contentList.stream().forEach(item->{
                    RedisGeoCommands.GeoLocation content = (RedisGeoCommands.GeoLocation) item.getContent();
                    idList.add((Integer) content.getName());
                });
            }
        }
    }
    jobBaseInfoDTO.setIdList(idList);
    return jobBaseInfoMapper.selectJobList(jobBaseInfoDTO);
}

selectJobList(jobBaseInfoDTO)方法的sql如下


到这儿我们就已经实现了“附近的人”的功能了,接下来就让我们具体的了解一下Redis中的GEO都有哪些骚操作吧。gzh回复“pSearch”获取源码呦!

GEO操作

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增,GEO 是基于zset的一种扩展数据格式。Redis GEO 操作方法有:

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

1、geoadd

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

geoadd 语法格式如下:

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

以下实例中 key 为 Sicily,Palermo 和 Catania 为位置名称 :

实例

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis>

1.png

2、geopos

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

geopos 语法格式如下:

GEOPOS key member [member ...]

实例

redis> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.36138933897018433"
  2) "38.11555639549629859"
2) 1) "15.08726745843887329"
  2) "37.50266842333162032"
3) (nil)
redis>

注:也可以使用zrange返回所有的位置元素而不带经纬度信息

redis> ZRANGE Sicily 0 -1
1)  "Palermo"
 2)  "Catania"
redis>

3、geodist

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

geodist 语法格式如下:

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

member1 member2 为两个地理位置。

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

  • m :米,默认单位。
  • km :千米。
  • mi :英里。
  • ft :英尺。

实例: 计算 Palermo 与 Catania 之间的距离

redis> GEODIST Sicily Palermo Catania
"166274.1516"
redis> GEODIST Sicily Palermo Catania km
"166.2742"
redis> GEODIST Sicily Palermo Catania mi
"103.3182"
redis> GEODIST Sicily Foo Bar
(nil)
redis>

4、georadius、georadiusbymember

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

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

georadius 实例

redis> GEORADIUS Sicily 15 37 200 km WITHDIST
1) 1) "Palermo"
  2) "190.4424"
2) 1) "Catania"
  2) "56.4413"
redis> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
  2) 1) "13.36138933897018433"
   2) "38.11555639549629859"
2) 1) "Catania"
  2) 1) "15.08726745843887329"
   2) "37.50266842333162032"
redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
  2) "190.4424"
  3) 1) "13.36138933897018433"
   2) "38.11555639549629859"
2) 1) "Catania"
  2) "56.4413"
  3) 1) "15.08726745843887329"
   2) "37.50266842333162032"
redis>

georadiusbymember 实例:

redis> GEOADD Sicily 13.583333 37.316667 "Agrigento"
(integer) 1
redis> GEORADIUSBYMEMBER Sicily Agrigento 100 km
1) "Agrigento"
2) "Palermo"
redis>

5、geohash

Redis GEO 使用 geohash 来保存地理位置的坐标。geohash 用于获取一个或多个位置元素的 geohash 值。

geohash 语法格式如下:

GEOHASH key member [member ...]

实例:

redis> GEOHASH Sicily Palermo Catania
1) "sqc8b49rny0"
2) "sqdtr74hyu0"
redis>

geo并没有提供删除指令,但根据其底层是zset实现,我们可以使用zrem对数据进行删除

redis> ZREM Sicily Agrigento
"1"
redis>

Redis GEO JAVA api

有了以上GEO的操作,我们可以在java中找到对应的api


//params: key, Point(经度, 纬度), 地方名称
Long addedNum = redisTemplate.opsForGeo().add("Sicily", new Point(13.361389,38.115556), "Palermo");


//params: key, 地方名称...
List points = redisTemplate.opsForGeo().position("Sicily","Palermo","Catania");


//params: key, 地方名称1, 地方名称2, 距离单位
Distance distance = redisTemplate.opsForGeo()
                .distance("Sicily","Palermo","Catania", RedisGeoCommands.DistanceUnit.KILOMETERS);


//Point(经度, 纬度) Distance(距离量, 距离单位)
Circle circle = new Circle(new Point(13.361389,38.115556), new Distance(200, Metrics.KILOMETERS));
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().
    //包含距离,包含经纬度,升序前五个
    includeDistance().includeCoordinates().sortAscending().limit(5);
//params: key, Circle, GeoRadiusCommandArgs
GeoResults> results = redisTemplate.opsForGeo()
                .radius("Sicily",circle,args);


//params: 距离量, 距离单位
Distance distance = new Distance(200,Metrics.KILOMETERS);
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
    .includeDistance().includeCoordinates().sortAscending().limit(5);
//params: key, 地方名称, Circle, GeoRadiusCommandArgs
GeoResults>  results = redisTemplate.opsForGeo()
    .radius("Sicily","Palermo",distance,args);
     


//params: key, 地方名称...
List results = redisTemplate.opsForGeo()
                .hash("Sicily","Palermo","Catania");

看到这里,“附近的人”功能你一定掌握了吧!如果你觉得这篇文章对你有所帮助,请移步关注gzh“阿Q说代码”或者直接联系阿Q:qingqing-4132,阿Q期待你的到来!

您可能感兴趣的文档:

--结束END--

本文标题: 附近的人?你zao吗?

本文链接: https://lsjlt.com/news/8421.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 附近的人?你zao吗?
    前几天收到一个新的需求,需要实现类似“附近的人”的功能:根据自己当前的定位,获取距离范围内的所有任务地点。刚看到这个需求时有点懵逼,第一想到的就是要利用地球的半径公式去计算距离,也就是把地球想成一个球体,去计算球上两点之间的距离。可想而知...
    99+
    2014-06-26
    附近的人?你zao吗?
  • Redis如何实现“附近的人”功能
    这篇文章给大家分享的是有关Redis如何实现“附近的人”功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。针对“附近的人”这一位置服务领域的应用场景,常见的可使用PG、MySQL...
    99+
    2024-04-02
  • 使用redis实现附近的人功能
    目录前言工具一、测试数据二、基本命令三、javaApi前言 Redis自3.2版本开始提供了GEO(geograph)功能,支持地理位置相关操作,以实现诸如附近的人这类依赖于地理位置...
    99+
    2024-04-02
  • Android仿QQ附近的人搜索展示功能
     1.概述 老规矩,先上图 原装货(就不录制gif了,大家可以自己在Q群助手开启共享地理位置,返回群聊天页面就看到看到附近的人): 看起来还是挺像的吧。 ...
    99+
    2022-06-06
    展示 Android
  • Android实现微信自动向附近的人打招呼(AccessibilityService)
    学习功能强大的AccessibilityService!!! 以下是本人根据自动抢红包的实现思路敲的用于微信自动向附近的人打招呼的核心代码 public class Aut...
    99+
    2022-06-06
    自动 Android
  • Elasticsearches通过坐标位置实现对附近人的搜索
    目录一 创建mapping二 导入数据三 查询3.1根据给定两个点组成的矩形,查询矩形内的点3.2根据给定的多个点组成的多边形,查询范围内的点3.3查询给定1000KM距离范围内的点...
    99+
    2024-04-02
  • Redis实现附近商铺的项目实战
    目录一、GEO数据结构1、入门2、练习二、附加商户搜索1、先批量导入商户坐标2、实现附近商户功能一、GEO数据结构 1、入门 GEO是Geolocation的缩写,代表地理坐标。Redis3.2中加入对GEO的支持,允许...
    99+
    2023-01-29
    Redis附近商铺 Redis附近
  • 微信小程序附近的店如何申请
    本篇内容介绍了“微信小程序附近的店如何申请”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!附近的店是微信为了丰富小程序的服务能力,商户可在小程...
    99+
    2023-06-26
  • postgres go lib pq 的“,”附近出现语法错误
    小伙伴们有没有觉得学习Golang很有意思?有意思就对了!今天就给大家带来《postgres go lib pq 的“,”附近出现语法错误》,以下内容将会涉及到,若是在学习中对其中部分知识点有疑问,...
    99+
    2024-04-05
  • 利用Python探测附近WIFI密码的详细代码
    前言 本文将记录学习下如何通过 Python 脚本实现 WIFI 密码的暴力破解,从而实现免费蹭网。 无图形界面 先来看看没有图形界面版的爆破脚本。 WIFI爆破 import py...
    99+
    2024-04-02
  • 利用Python探测附近WIFI密码的代码怎么写
    利用Python探测附近WIFI密码的代码怎么写,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。前言下面将学习下如何通过 Python 脚本实现 WIFI 密码的暴力破解,从而实...
    99+
    2023-06-28
  • 你知道 HTML 外部样式表的惊人威力吗?
    ...
    99+
    2024-04-02
  • 微信小程序中如何实现搜索附近的iBeacon设备
    这篇文章主要为大家展示了微信小程序中如何实现搜索附近的iBeacon设备,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“微信小程序中如何实现搜索附近的iBeacon设备”这篇文章吧。wx.start...
    99+
    2023-06-26
  • Android 扫描附近的蓝牙设备并连接蓝牙音响的示例
    写了一个可以扫描附近蓝牙设备的小Demo,可以查看蓝牙设备的设备名和Mac地址代码量不多,很容易看懂public class ScanDeviceActivity extends AppCompatActivity { private Lo...
    99+
    2023-05-30
    android 扫描 蓝牙
  • 小程序中如何停止搜寻附近的蓝牙外围设备
    本文将为大家详细介绍“小程序中如何停止搜寻附近的蓝牙外围设备”,内容步骤清晰详细,细节处理妥当,而小编每天都会更新不同的知识点,希望这篇“小程序中如何停止搜寻附近的蓝牙外围设备”能够给你意想不到的收获,请大家跟着小编的思路慢慢深入,具体内容...
    99+
    2023-06-26
  • 使用 gorm 在 postgres 中的“$1”处或附近出现 golang 语法错误
    学习Golang要努力,但是不要急!今天的这篇文章《使用 gorm 在 postgres 中的“$1”处或附近出现 golang 语法错误》将会介绍到等等知识点,如果你想深入学习Golang,可以关...
    99+
    2024-04-04
  • 简单的这些不为人知的小技巧你都知道吗?
      随着科技的发展,手机在生活越来越重要,微信渐渐成为我们生活中沟通的重要媒介。现在很多的中老年人也开始使用微信了,但是微信上有很多功能,他们都不会使用,如果我们不在他们的身边,他们又想使用微信的话,那...
    99+
    2024-04-02
  • 新人同学你知道win7和win10哪个流畅吗?
    最好在完全相同的环境中对比 Windows 7 和 Windows 10 的性能。 在使用游戏模式或支持 DirectX 12 的游戏中,更新操作系统的优势立即值得注意。本文将讨论哪个版本的游戏最适合 Windows 7 或 Windows...
    99+
    2023-07-10
  • 手把手教你利用opencv实现人脸识别功能(附源码+文档)
    目录一、环境二、使用Haar级联进行人脸检测三、Haar级联结合摄像头四、使用SSD的人脸检测五、 SSD结合摄像头人脸检测六、结语一、环境 pip install opencv...
    99+
    2024-04-02
  • 你的对象被人从网络传输走了还能回来吗?
    🍎 博客主页:@风一样的美狼子 🍎 欢迎关注:👍点赞🍃收藏🔥留言 🍎系列专栏: 《云平台实战》、《Linux随你玩-实操》 ἴ...
    99+
    2023-08-30
    java 开发语言 后端
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作