范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Redis实战篇通过Geo类型实现附近的人邂逅女神

  产品经理说他有一个 idea,为广大少男少女提供一个连接彼此的机会。
  让处于这最美的年龄的少男少女能在每一个十二时辰里能邂逅到那个  Ta 。
  所以就想开发一款  App ,用户登陆后能发现附近的那个 Ta ,连接彼此。
  我该如何实现发现 附近的人 ?我也希望通过这个 App 邂逅女神……
  记忆中,一个下班的夜晚,她从人群中轻盈的移动着,那高挑苗条的身材像漂浮在空间中的一个飘逸的音符。她的眼睛充满清澈的阳光和活力,她的双眸中印着银河系的星光。  开篇寄语"
  多锻炼自己的表达能力,特别是在工作中。很多人说「干活的不如那些做 PPT 的」,实际上老板都不傻,为何他们会更认可那些做 PPT 的?
  因为他们从老板的角度考虑问题,对他而言,需要的是一个「解决方案」。多从一个创造者的视角去考虑问题,而不是局限在用程序员的视角考虑问题;
  多想一下这个东西到底给人提供什么价值,而不是「我要怎么实现它」。当然,怎么实现是必须的,但通常不是最重要的。
  "   什么是面向 LBS 应用
  经纬度是经度与纬度的合称组成一个 坐标系统 。又称为地理坐标系统,它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统,能够标示地球上的任何一个位置 (小数点后7位,精度可以到1厘米)。
  经度的范围在 (-180, 180],纬度的范围 在(-90, 90],纬度正负以赤道为界,北正南负,经度正负以本初子午线 (英国格林尼治天文台) 为界,东正西负。
  附近的人  也就是常说的 LBS  (Location Based Services,基于位置服务),它围绕用户当前地理位置数据而展开的服务,为用户提供精准的邂逅服务。
  附近的人 核心思想如下: 以 "我" 为中心,搜索附近的 Ta;  以 "我" 当前的地理位置为准,计算出别人和 "我" 之间的距离;  按 "我" 与别人距离的远近排序,筛选出离我最近的用户。  MySQL 实现"
  计算「附近的人」,通过一个坐标计算这个坐标附近的其他数据,按照距离排序,如何下手呢?
  "
  以用户为中心,给定一个 1000 米作为半径画圆,那么圆形区域内的用户就是我们想要邂逅的「附近的人」。
  将经纬度存储到  MySQL : CREATE TABLE `nearby_user` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `name` varchar(255) DEFAULT NULL COMMENT "名称",   `longitude` double DEFAULT NULL COMMENT "经度",   `latitude` double DEFAULT NULL COMMENT "纬度",   `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT "创建时间",   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;  "
  可是总不能遍历所有的「女神」经纬度与自己的经纬度数据计算在根据距离排序,这个计算量也太大了。
  "
  我们可以通过区域来过滤出有限「女神」坐标数据,再对矩形区域内的数据进行全量距离计算再排序,这样计算量明显降低。  "
  如何划分矩形区域呢?
  "
  在圆形外套上一个正方形,根据用户经、纬度的最大最小值(经、纬度 + 距离),作为筛选条件过滤数据,就很容易将正方形内的「女神」信息搜索出来。
  "
  多出来的一些区域咋办?
  "
  多出来的这部分区域内的用户,到圆点的距离一定比圆的半径要大,那么我们就计算用户中心点与正方形内所有用户的距离, 筛选出所有距离小于等于半径的用户 ,圆形区域内的所用户即符合要求的附近的人 。
  为了满足高性能的矩形区域算法,数据表需要在经纬度坐标加上复合索引  (longitude, latitude) ,这样可以最大优化查询性能。 实战
  根据经纬度和距离获取外接矩形最大、最小经纬度以及根据经纬度计算距离使用了一个第三方类库:        com.spatial4j      spatial4j      0.5 
  获取到外接矩形后,以矩形的 最大最小经、纬度值 搜索正方形区域内的用户,再剔除超过指定距离的用户,就是最终的附近的人 。 /**  * 获取附近 x 米的人  *  * @param distance 搜索距离范围 单位km  * @param userLng  当前用户的经度  * @param userLat  当前用户的纬度  */ public String nearBySearch(double distance, double userLng, double userLat) {   //1.获取外接正方形   Rectangle rectangle = getRectangle(distance, userLng, userLat);   //2.获取位置在正方形内的所有用户   List users = userMapper.selectUser(rectangle.getMinX(), rectangle.getMaxX(), rectangle.getMinY(), rectangle.getMaxY());   //3.剔除半径超过指定距离的多余用户   users = users.stream()     .filter(a -> getDistance(a.getLongitude(), a.getLatitude(), userLng, userLat) <= distance)     .collect(Collectors.toList());   return JSON.toJSONString(users); }  // 获取外接矩形 private Rectangle getRectangle(double distance, double userLng, double userLat) {   return spatialContext.getDistCalc()     .calcBoxByDistFromPt(spatialContext.makePoint(userLng, userLat),                           distance * DistanceUtils.KM_TO_DEG, spatialContext, null); }       /***      * 球面中,两点间的距离      * @param longitude 经度1      * @param latitude  纬度1      * @param userLng   经度2      * @param userLat   纬度2      * @return 返回距离,单位km      */     private double getDistance(Double longitude, Double latitude, double userLng, double userLat) {         return spatialContext.calcDistance(spatialContext.makePoint(userLng, userLat),                 spatialContext.makePoint(longitude, latitude)) * DistanceUtils.DEG_TO_KM;     }
  由于用户间距离的排序是在业务代码中实现的,可以看到SQL语句也非常的简单。  SELECT * FROM nearby_user WHERE 1=1 AND (longitude BETWEEN #{minlng} AND #{maxlng}) AND (latitude BETWEEN #{minlat} AND #{maxlat})
  但是数据库查询性能毕竟有限,如果「附近的人」查询请求非常多,在高并发场合,这可能并不是一个很好的方案。  尝试 Redis Hash 未果
  我们一起分析下 LBS 数据的特点:  每个「女神」都有一个 ID 编号,每个ID 对应着经纬度信息。  「宅男」登陆  app 获取「心动女生」的时候,app 根据「宅男」的经纬度查找附近的「女神」。 获取到位置符合的「女神」ID 列表后,再从数据库获取 ID 对应的「女神」信息返回用户。  "
  数据特点就是一个女神(用户)对应着一组经纬度,让我想到了 Redis 的 Hash 结构。也就是一个 key(女神 ID) 对应着 一个 value(经纬度)。
  "
  Hash 看起来好像可以实现,但是 LBS 应用除了记录经纬度以外,还需要对 Hash 集合中的数据进行范围查询,根据经纬度换算成距离排序。
  而 Hash 集合的数据是无序的,显然不可取 。 Sorted Set 初见端倪"
  Sorted Set 类型是是否合适呢?因为它可以排序。
  "
  Sorted Set  类型也是一个 key 对应一个 value ,key元素内容,而 value `就是该元素的权重分数。
  Sorted Set 可以根据元素的权重分数对元素排序,这样看起来就满足我们的需求了。
  比如,Sorted Set 的元素是「女神ID」,元素对应的权重 score 是经纬度信息。
  "
  问题来了,Sorted Set 元素的权重值是一个浮点数,经纬度是经度、纬度两个值,咋办呢?能不能将经纬度转换成一个浮点数呢?
  "
  思路对了,为了实现对经纬度比较,Redis 采用业界广泛使用的 GeoHash 编码,分别对经度和纬度编码,最后再把经纬度各自的编码组合成一个最终编码。
  这样就实现了将经纬度转换成一个值,而  Redis 的 GEO 类型的底层数据结构用的就是  Sorted Set 来实现。
  我们来看下  GeoHash  如何将经纬度编码的。 GEOHash 编码"
  关于 GeoHash 可参考 :https://en.wikipedia.org/wiki/Geohash
  "
  GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。
  当我们想要计算「附近的人时」,首先将目标位置映射到这条线上,然后在这个一维的线上获取附近的点就行了。
  GeoHash 编码会把一个经度值编码成一个 N 位的二进制值,我们来对经度范围[-180,180]做 N 次的二分区操作,其中 N 可以自定义。
  在进行第一次二分区时,经度范围[-180,180]会被分成两个子区间:[-180,0) 和[0,180](我称之为左、右分区)。
  此时,我们可以查看一下要编码的经度值落在了左分区还是右分区。如 果是落在左分区,我们就用 0 表示;如果落在右分区,就用 1 表示 。
  这样一来, 每做完一次二分区,我们就可以得到 1 位编码值(不是0 就是 1)。
  再对经度值所属的分区再做一次二分区,同时再次查看经度值落在了二分区后的左分区还是右分区,按照刚才的规则再做 1 位编码。当做完 N 次的二分区后,经度值就可以用一个 N bit 的数来表示了。
  所有的地图元素坐标都将放置于唯一的方格中。方格越小,坐标越精确。然后对这些方格进行整数编码,越是靠近的方格编码越是接近。
  编码之后,每个地图元素的坐标都将变成一个整数,通过这个整数可以还原出元素的坐标,整数越长,还原出来的坐标值的损失程度就越小。对于「附近的人」这个功能而言,损失的一点精确度可以忽略不计。
  比如对经度值等于  169.99  进行 4 位编码(N = 4,做 4 次分区),把经度区间[-180,180]分成了左分区[-180,0) 和右分区[0,180]。 169.99 属于右分区,使用  1  表示第一次分区编码; 再将 169.99 经过第一次划分所属的 [0, 180] 区间继续分成 [0, 90) 和 [90, 180],169.99 依然在右区间,编码 ‘1’。  将[90, 180] 分为[90, 135) 和 [135, 180],这次落在左分区,编码 ‘0’。
  如此,最后我们就得到一个 4 位的编码。
  而纬度的编码思路跟经度也是一样的,不再赘述。  合并经纬度编码
  假如计算的经纬度编码分别是  11011 和 00101`,目标编码第 0 位则从经度第 0 位的值 1 作为目标值,目标编码的第 1 位则从纬度第 0 位值 0 作为目标值,以此类推:
  就这样,经纬度(35.679,114.020)就可以使用  1010011011  表示,而这个值就可以作为 SortedSet  的权重值实现排序。 Redis GEO 实现"
  GEO 类型是将经纬度的经过 GeoHash 编码的合并值作为 Sorted Set 元素的 score 权重,Redis 的 GEO 有哪些指令呢?
  "
  我们需要把登陆 app 的女生 ID 和对应的经纬度存到 Sorted Set 里面。
  更多 GEO 类型指令可参考:https://redis.io/commands#geo
  GEOADD
  Redis 提供了  GEOADD key longitude latitude member  命令,将一组经纬度信息和对应的「女神 ID」记录到 GEO 类型的集合中,如下:一次记录多个用户(苍井空、波多野结衣)的经纬度信息。 GEOADD girl:localtion 13.361389 38.115556 "苍井空" 15.087269 37.502669 "波多野结衣"
  GEORADIUS  "
  我登陆了 app,获取自己的经纬度信息,如何查找以这个经纬度为中心的一定范围内的其他用用户呢?
  "
  Redis GEO 类型提供了 GEORADIUS 指令:会根据输入的经纬度位置,查找以这个经纬度为中心的一定范围内的其他元素。
  假设自己的经纬度是(15.087269 37.502669),需要获取附近 10 km 的「女神」并返回给 LBS 应用:  GEORADIUS girl:locations 15.087269 37.502669 km ASC COUNT 10
  ASC 可以实现让「女神」信息按照这个距离自己的经纬度由近到远排序。
  COUNT 选项表示指定返回的「女神」数量,防止附近太多「女神」,节省带宽资源。
  如果觉得自己需要更多女神,那么可以无限制,但是需要注意身体,多吃鸡蛋补一补 。 "
  用户下线后,如删除下线的「女神」经纬度呢?
  "
  这个问题问得好, GEO  类型是基于 Sorted Set  实现的,所以可以借用 ZREM  命令实现对地理位置信息的删除。
  比如删除「苍井空」的位置信息:  ZREM girl:localtion "苍井空" 小结
  GEO 本身并没有设计新的底层数据结构,而是直接使用了 Sorted Set 集合类型。
  GEO 类型使用 GeoHash 编码方法实现了经纬度到 Sorted Set 中元素权重分数的转换,这其中的两个关键机制就是对二维地图做区间划分,以及对区间进行编码。
  一组经纬度落在某个区间后,就用区间的编码值来表示,并把编码值作为 Sorted Set 元素的权重分数。
  在一个地图应用中,车的数据、餐馆的数据、人的数据可能会有百万千万条,如果使用 Redis 的 Geo 数据结构,它们将全部放在一个 zset 集合中。
  在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。
  所以,这里建议 Geo 的数据使用单独的 Redis 集群实例部署。
  如果数据量过亿甚至更大,就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。
  这样就可以显著降低单个 zset 集合的大小。
  原文:https://zhuanlan.zhihu.com/p/413263209

金庸群侠传玩家一直看不上的剑法,大成之后威力远胜辟邪剑法说来也怪,在具有浓浓江湖味道的金庸群侠传中,剑法和刀法往往都是最没有价值的武功。在原版中我们能够学会的,威力最大的剑法就是辟邪剑谱了,而且还要自宫才能练成,影响心情啊!其他威力较大DNF魂异界地图即将来临,快来回顾一下那些有趣的机制吧作者纸鸢助手id376118948前言2021DNF嘉年华中爆料了许多有意思的内容,其中异界地图的重新登场格外引人瞩目,今天笔者就盘点一下以前异界地下城中那些有趣的机制,带小伙伴们新天龙八部年终回馈奖,今年氪金宠物有点帅,消费玩家也有礼包年终了,年终了,策划估计也要为年终奖开始考虑,而今年的年终回馈玩家奖励也是火热出炉,来来来,看一下值不值。因为今年新开的卡级服,所以说奖励也分为了正式服和卡级服,毕竟好多东西卡级她最终幻想7REMOD增强蒂法腹肌玩家直呼有品位最终幻想7重制版Intergrade在不久前登陆了PC平台,随之而来的不仅有针对游戏本身的讨论,还有各种衍生MOD内容出现在玩家的视野中。比起许多人期待的服装MOD,N网作者Mud哈利波特手游嗅嗅都被玩家玩坏了!网友一看就知道是獾院养的印象中,咱们的嗅嗅有着长长的鼻子,矮矮的身子,两只大眼睛只对闪闪发光的东西情有独钟,不要太可爱!其实也是凭借着萌萌的外表,圈了无数粉,不得不说设计师可太会了。另外,我们在霍格沃茨魔热血传奇你知道传奇史上因特戒导致退服的玩家背后的原因吗?无兄弟,无传说。各位,我经常向大家介绍传奇游戏,以及相关的游戏攻略,喜欢玩传奇的玩家可以在评论区里讲述自己的传奇故事,让更多人看到您的传奇。传奇玩家退游事件,许多人根本就不愿意去打外媒评2021年最让人失望游戏大作频频翻车2021年即将结束,许多游戏媒体都对今年的游戏业界做出了不同方面的评价,而这次带来排行榜的是Dsogaming,他们评选出了2021年发售的7款最让人失望游戏。这些游戏都是由较大规原神八观盛明自选邀约如何取舍?8个4星角色,其实是4选1哈喽,小伙伴们大家好,这里是花郎聊游戏。原神的第二个海灯节已经进入了开幕倒计时阶段,相信小伙伴们看完前瞻直播后,早就已经迫不及待的想让荒泷一斗的UP池快进到结束了吧?这最后的一周时被打服了?ShowMaker认输2021的DK确实没有之前的压制力了大家好,这里是锦城,给大家带来英雄联盟电竞圈的最新资讯。2021对于S10卫冕冠军DK来说是记忆犹新的一年,虽然豪取LCK联赛春夏双冠,但是两度出征世界赛都被LPL队伍击败倒在了决一年花掉500亿,网易腾讯字节同时入局!今年最挤赛道?导语两大套路,反着来!3亿女玩家,一年消费超过500亿元。这是中国音数协游戏工委在2020年所给出的数据。吸金能力全面释放,吸引网易腾讯字节等顶级大厂相继发力。想要从这条赛道上脱颖剧情凄美血统纯正!DPRG佳作鲁弗兰的地下迷宫与魔女的旅团鲁弗兰的地下迷宫与魔女的旅团(以下统称魔女的旅团)是由日本一工作室于2016年在PSV掌机平台发售的DRPG游戏。玩家在故事中将扮演名为妖路历程的魔法书,需要完成薄暮魔女朵洛妮亚的
老师恶意喊单怎么挽回损失?股票群炒外汇被骗怎么办?每逢行情,几家欢喜几家愁,炒外汇的投资者,你有没有想过为什么唯独你次次亏损,真的是你时运不济吗?劝你赶紧回过头来思考一下为什么亏损,有没有想过你的平台是否合法合规?在我国境内是否受期货投资是正规合法的吗?炒期货怀疑遇到黑平台了怎么办?市场上关于国际期货投资的诈骗行为层出不穷,唯独不变的核心永远都是用各种诱惑手段图谋投资者的资金!期货被骗真实案例分享老谢不同于其他的人,有很多的兴趣爱好,但是唯独对股票情有独钟,说认识三天在游戏里面结婚?游戏被骗充值的钱可以退吗?随着游戏的发展,各类游戏琳琅满目,但是很多游戏都是小的游戏公司制作的,为了推广这些游戏,很多公司违规操作,导致现在有了游戏托这个职业,专门来骗局玩家的钱,最后还把玩家给耍了,真是可玩游戏被骗的钱能退吗?遭遇游戏托诈骗我去投诉有用吗?文章精选自小语追损网络是一把双刃剑,有利又有弊,互联网在给我们提供便利的同时,又给我们带来了很多弊端,毕竟是虚拟的平台,很多东西都不真实,比如说,游戏,交友APP,最近很多游戏玩家游戏诱导充值被骗的钱怎么要回来?遇到游戏托骗我充值怎么办?国内游戏界的竞争也是越演越烈,每年都有不少游戏进入市场,当然也有更多的黑游戏无法通过审核进入市场,而一些不法分子通过运营这些黑游戏,以招募游戏托的方式让人去其他热门游戏拉人头,通过传奇私服被骗的钱能追回吗?游戏被骗投诉有用吗?玩游戏有托早已不是新起的行业,这一行业在互联网诞生的那一天就注定他会出现在这个信息时代,随着信息的发展,国家也在努力地推进新的治理方案,而我们自己也要大量了解知识,谨防被骗。游戏骗网络游戏诱导我充值的钱能退吗?遇到游戏托骗我充值我该怎么维权带刺的玫瑰美不美?答案肯定是美,带刺最为独特,当你越靠近它的时候,难免会受到伤害。而在游戏中,这些看似美好的邂逅,其实都是游戏托在作怪,导致玩家纷纷在游戏中充值,在她们的糖衣炮弹之游戏里面诱导充值氪金的钱能追回吗?游戏被骗经历这是一个被网络包围社交软件泛滥的年代,网恋现象屡见不鲜,电信网络诈骗更是层出不穷屡禁不止。不法分子随时潜藏在虚拟的网络空间,甜言蜜语的温柔乡可能是诈骗的圈套和利器,稍有不慎,就会被玩游戏被骗充值怎么快速退款?游戏被骗能追回吗?现在市面上很多游戏推广业务员通过利用婚恋交友APP网络交友,男扮女装等手段欺骗消费者,诱导游戏玩家在游戏中充值氪金,导致很多玩家最后人才两空。游戏被骗的套路一般都是什么样的小杰性格游戏被骗充值怎么办?网上玩游戏遇到游戏托骗我钱报警会受理吗?相信大家在电视新闻里面看到过很多这种消息吧,年轻女子以谈朋友名义勾引男性到酒吧咖啡厅进行大额消费的饭托酒托。而现在在游戏领域,也存在着游戏托出现骗感情,骗钱。这些游戏托往往以游戏公在网上找的情感挽回机构不靠谱!交钱没效果还不退钱怎么办?文章精选自小语追损感情这种事,哪有百分百能挽回的?那岂不是花钱买对象?再厉害的情感挽回机构都不可能做到百分百挽回,这一点一定要注意,标榜百分百挽回根本不可信!情感被骗者自述被骗经过