基于快速GeoHash,如何实现海量商品与商圈的高效匹配?

小叽导读:闲鱼是一款闲置物品的交易平台APP。通过这个平台,全国各地“无处安放”的物品能够轻松实现流动。这种分享经济业务形态被越来越多的人所接受,也进一步实现了低碳生活的目标。

今天,闲鱼团队就商品与商圈的匹配算法为我们展开详细解读。

摘要
闲鱼app根据交通条件、商场分布情况、住宅区分布情况综合考虑,将城市划分为一个个商圈。杭州部分区域商圈划分如下图所示。 

闲鱼的商品是由用户发布的GPS随机分布在地图上的点数据。当用户处于某个商圈范围内时,app会向用户推荐GPS位于此商圈中的商品。要实现精准推荐服务,就需要计算出哪些商品是归属于你所处的商圈。

在数据库中,商圈是由多个点围成的面数据,这些面数据形状、大小各异,且互不重叠。商品是以GPS标记的点数据,如何能够快速高效地确定海量商品与商圈的归属关系呢?传统而直接的方法是,利用几何学的空间关系计算公式对海量数据实施直接的“点—面”关系计算,来确定每一个商品是否位于每一个商圈内部。

闲鱼目前有10亿商品数据,且每天还在快速增加。全国所有城市的商圈数量总和大约为1万,每个商圈的大小不一,边数从10到80不等。如果直接使用几何学点面关系运算,需要的计算量级约为2亿亿次基本运算。按照这个思路,我们尝试过使用阿里巴巴集团内部的离线计算集群来执行计算,结果集群在运行了超过2天之后也未能给出结果。

经过算法改进,我们采用了一种基于GeoHash精确匹配,结合GeoHash非精确匹配并配合小范围几何学关系运算精匹配的算法,大大降低了计算量,高效地实现了离线环境下海量点-面数据的包含关系计算。同样是对10亿条商品和1万条商圈数据做匹配,可以在1天内得到结果。

▌点数据GeoHash原理与算法

GeoHash是一种对地理坐标进行编码的方法,它将二维坐标映射为一个字符串。每个字符串代表一个特定的矩形,在该矩形范围内的所有坐标都共用这个字符串。字符串越长精度越高,对应的矩形范围越小。

对一个地理坐标编码时,按照初始区间范围纬度[-90,90]和经度[-180,180],计算目标经度和纬度分别落在左区间还是右区间。落在左区间则取0,右区间则取1。然后,对上一步得到的区间继续按照此方法对半查找,得到下一位二进制编码。当编码长度达到业务的进度需求后,根据“偶数位放经度,奇数位放纬度”的规则,将得到的二进制编码穿插组合,得到一个新的二进制串。最后,根据base32的对照表,将二进制串翻译成字符串,即得到地理坐标对应的目标GeoHash字符串。

以坐标“30.280245, 120.027162”为例,计算其GeoHash字符串。首先对纬度做二进制编码:

将[-90,90]平分为2部分,“30.280245”落在右区间(0,90],则第一位取1。

将(0,90]平分为2分,“30.280245”落在左区间(0,45],则第二位取0。

不断重复以上步骤,得到的目标区间会越来越小,区间的两个端点也越来越逼近“30.280245”。

下图的流程详细地描述了前几次迭代的过程: 

按照上面的流程,继续往下迭代,直到编码位数达到我们业务对精度的需求为止。完整的15位二进制编码迭代表格如下: 

得到的纬度二进制编码为10101 01100 01000。

按照同样的流程,对经度做二进制编码,具体迭代详情如下:

得到的经度二进制编码为11010 10101 01101。

按照“偶数位放经度,奇数位放纬度”的规则,将经纬度的二进制编码穿插,得到完成的二进制编码为:11100 11001 10011 10010 00111 00010。由于后续要使用的是base32编码,每5个二进制数对应一个32进制数,所以这里将每5个二进制位转换成十进制位,得到28,25,19,18,7,2。 对照base32编码表,得到对应的编码为:wtmk72。 

可以在geohash.org/网站对上述结果进行验证,验证结果如下:


验证结果的前几位与我们的计算结果一致。如果我们利用二分法获取二进制编码时迭代更多次,就会得到验证网站中这样的位数更多的更精确结果。

GeoHash字符串的长度与精度的对应关系如下: 

**▌面数据GeoHash编码实现
**
上一节介绍的标准GeoHash算法只能用来计算二维点坐标对应的GeoHash编码,我们的场景中还需要计算面数据(即GIS中的POLYGON多边形对象)对应的GeoHash编码,需要扩展算法来实现。

算法思路是,先找到目标Polygon的最小外接矩形MBR,计算此MBR西南角坐标对应的GeoHash编码。然后用GeoHash编码的逆算法,反解出此编码对应的矩形GeoHash块。以此GeoHash块为起点,循环往东、往北找相邻的同等大小的GeoHash块,直到找到的GeoHash块完全超出MBR的范围才停止。如此找到的多个GeoHash块,边缘上的部分可能与目标Polygon完全不相交,这部分块需要通过计算剔除掉,如此一来可以减少后续不必要的计算量。 

上面的例子中最终得到的结果高清大图如下,其中蓝色的GeoHash块是与原始Polygon部分相交的,橘黄色的GeoHash块是完全被包含在原始Polygon内部的。

上述算法总结成流程图如下: 

▌求临近GeoHash块的快速算法

上一节对面数据进行GeoHash编码的流程图中标记为绿色和橘黄色的两步,分别是要寻找相邻的东边或北边的GeoHash字符串。

传统的做法是,根据当前GeoHash块的反解信息,求出相邻块内部的一点,在对这个点做GeoHash编码,即为相邻块的GeoHash编码。如下图,我们要计算"wtmk72"周围的8个相邻块的编码,就要先利用GeoHash逆算法将"wtmk72"反解出4个顶点的坐标N1、N2、N3、N4,然后由这4个坐标计算出右侧邻接块内部的任意一点坐标N5,再对N5做GeoHash编码,得到的“wtmk78”就是我们要求的右边邻接块的编码。按照同样的方法,求可以求出"wtmk72"周围总共8个邻接块的编码。

这种方法需要先解码一次再编码一次,比较耗时,尤其是在指定的GeoHash字符串长度较长需要循环较多次的情况下。

通过观察GeoHash编码表的规律,结合GeoHash编码使用的Z阶曲线的特性,验证了一种通过查表来快速求相邻GeoHash字符串的方法。

还是以“wtmk72”这个GeoHash字符串为例,对应的10进制数是“28,25,19,18,7,2”,转换成二进制就是11100 11001 10011 10010 00111 00010。其中,w对应11100,这5个二进制位分别代表“经 纬 经 纬 经”;t对应11001,这5个二进制位分别代表“纬 经 纬 经 纬”。由此推广开来可知,GeoHash中的奇数位字符(本例中的'w'、'm'、'7')代表的二进制位分别对应“经 纬 经 纬 经”,偶数位字符(本例中的't'、'k'、'2')代表的二进制位分别对应“纬 经 纬 经 纬”。

'w'的二进制11100,转换成方位含义就是“右 上 右 下 左”。't'的二进制11001,转换成方位含义就是“上 右 下 左 上”。

根据这个字符与方位的转换关系,我们可以知道,奇数位上的字符与位置对照表如下: 

偶数位上的字符与位置对照表如下:

这里可以看到一个很有意思的现象,奇数位的对照表和偶数位对照表存在一种转置和翻转的关系。

有了以上两份字符与位置对照表,就可以快速得出每个字符周围的8个字符分别是什么。而要计算一个给定GeoHash字符串周围8个GeoHash值,如果字符串最后一位字符在该方向上未超出边界,则前面几位保持不变,最后一位取此方向上的相邻字符即可;如果最后一位在此方向上超出了对照表边界,则先求倒数第二个字符在此方向上的相邻字符,再求最后一个字符在此方向上相邻字符(对照表环状相邻字符);如果倒数第二位在此方向上的相邻字符也超出了对照表边界,则先求倒数第三位在此方向上的相邻字符。以此类推。

以上面的“wtmk72”举例,要求这个GeoHash字符串的8个相邻字符串,实际就是求尾部字符‘2’的相邻字符。‘2’适用偶数对照表,它的8个相邻字符分别是‘1’、‘3’、‘9’、‘0’、‘8’、‘p’、‘r’、‘x’,其中‘p’、‘r’、‘x’已经超出了对照表的下边界,是将偶数位对照表上下相接组成环状得到的相邻关系。所以,对于这3个超出边界的“下方”相邻字符,需要求倒数第二位的下方相邻字符,即‘7’的下方相邻字符。‘7’是奇数位,适用奇数位对照表,‘7’在对照表中的“下方”相邻字符是‘5’,所以“wtmk72”的8个相邻GeoHash字符串分别是“wtmk71”、“wtmk73”、“wtmk79”、“wtmk70”、“wtmk78”、“wtmk5p”、“wtmk5r”、“wtmk5x”。利用此相邻字符串快速算法,可以大大提高上一节流程图中面数据GeoHash编码算法的效率。

▌高效建立海量点数据与面数据的关系

建立海量点数据与面数据的关系的思路是,先将需要匹配的商品GPS数据(点数据)、商圈AOI数据(面数据)按照前面所述的算法,分别计算同等长度的GeoHash编码。每个点数据都对应唯一一个GeoHash字符串;每个面数据都对应一个或多个GeoHash编码,这些编码要么是“完全包含字符串”,要么是“部分包含字符串”。

a)将每个商品的GeoHash字符串与商圈的“完全包含字符串”进行join操作。join得到的结果中出现的<商品,商圈>数据就是能够确定的“某个商品属于某个商圈”的关系。

b)对于剩下的还未被确定关系的商品,将这些商品的GeoHash字符串与商圈的“部分包含字符串”进行join操作。join得到的结果中出现的<商品,商圈>数据是有可能存在的“商品属于某个商圈”的关系,接下来对这批数据中的商品gps和商圈AOI数据进行几何学关系运算,进而从中筛选出确定的“商品属于某个商圈”的关系。

如图,商品1的点数据GeoHash编码为"wtmk70j",与面数据的“完全包含字符串wtmk70j”join成功,所以可以直接确定商品1属于此面数据。

商品2的点数据GeoHash编码为“wtmk70r”,与面数据的“部分包含字符串wtmk70r”join成功,所以商品2疑似属于面数据,具体是否存在包含关系,还需要后续的点面几何学计算来确定。 商品3的点数据GeoHash编码与面数据的任何GeoHash块编码都匹配不上,所以可以快速确定商品3不属于此面数据。 

实际应用中,原始的海量商品GPS范围散布在全国各地,海量商圈数据也散布在全国各个不同的城市。经过a)步骤的操作后,大部分的商品数据已经确定了与商圈的从属关系。剩下的未能匹配上的商品数据,经过b)步骤的GeoHash匹配后,可以将后续“商品-商圈几何学计算”的运算量从“1个商品 x 全国所有商圈”笛卡尔积的量级,降低为“1个商品 x 1个(或几个)商圈”笛卡尔积的量级,减少了绝大部分不必要的几何学运算,而这部分运算是非常耗时的。

在闲鱼的实际应用中,10亿商品和1万商圈数据,使用本文的快速算法,只需要 10亿次GeoHash点编码 + 1万次GeoHash面编码 + 500万次“点是否在面内部”几何学运算,粗略换算为基本运算需要的次数约为1800亿次,运算量远小于传统方法的2亿亿次基本运算。使用阿里巴巴的离线计算平台,本文的算法在不到一天的时间内就完成了全部计算工作。

另外,对于给定的点和多边形,通过几何学计算包含关系的算法不止一种,最常用的算法是射线法。简单来说,就是从这个点出发做一条射线,判断该射线与多边形的交点个数是奇数还是偶数。如果是奇数,说明点在多边形内;否则,点在多边形外。

▌延伸

面对海量点面数据的空间关系划分,本文采用是的通过GeoHash来降低计算量的思路,本质上来说是利用了空间索引的思想。事实上,在GIS领域有多种实用的空间索引,常见的如R树系列(R树、R+树、R*树)、四叉树、K-D树、网格索引等,这些索引算法各有特点。本文的思路不仅能用来处理点—面关系的相关问题,还可以用来快速处理点—点关系、面—面关系、点—线关系、线—线关系等问题,比如快速确定大范围类的海量公交站台与道路的从属关系、多条道路或铁路是否存在交点等问题。


原文链接
本文为云栖社区原创内容,未经允许不得转载。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

独家揭秘!阿里大规模数据中心的性能分析

阿里妹导读&#xff1a;数据中心已成为支撑大规模互联网服务的标准基础设施。随着数据中心的规模越来越大&#xff0c;数据中心里每一次软件&#xff08;如 JVM&#xff09;或硬件&#xff08;如 CPU&#xff09;的升级改造都会带来高昂的成本。合理的性能分析有助于数据中心的…

云+X案例展 | 金融类:七牛云Pandora 助阵某银行实现日志智能管理

本案例由七牛云投递并参与评选&#xff0c;CSDN云计算独家全网首发&#xff1b;更多关于【云X 案例征集】的相关信息&#xff0c;点击了解详情丨挖掘展现更多优秀案例&#xff0c;为不同行业领域带来启迪&#xff0c;进而推动整个“云行业”的健康发展。银行作为国民经济的重要…

函数运行环境系统动态链接库版本太低?函数计算 fun 神助力分忧解难

背景 最近在处理线上工单的时候&#xff0c;遇到一个用户使用 nodejs runtime 时因为函数计算运行环境的 gcc 版本过低导致无法运行的问题&#xff0c;觉得非常有意思&#xff0c;所以深入的帮用户寻找了解决方案。觉得这个场景应该具有一定的通用性&#xff0c;所以在这篇文章…

蚂蚁金服核心技术:百亿特征实时推荐算法揭秘

文章提出一整套创新算法与架构&#xff0c;通过对TensorFlow底层的弹性改造&#xff0c;解决了在线学习的弹性特征伸缩和稳定性问题&#xff0c;并以GroupLasso和特征在线频次过滤等自研算法优化了模型稀疏性。在支付宝核心推荐业务获得了uvctr的显著提升&#xff0c;并较大地提…

老码农肺腑直言:为什么我不建议你学Python?

关于Python&#xff0c;我们听到最多的一句话就是&#xff1a;代码简洁。目前来看&#xff0c;代码量上C:Java:Python100:10:1。Python简洁度完胜&#xff0c;但这却也是他的“死亡缺点”&#xff01;今天想跟大家分享&#xff0c;学Python的一系列惊天大坑……Python钱多“话少…

如何评估深度学习模型效果?阿里工程师这么做

复杂的深度模型中&#xff0c;如果效果不好&#xff0c;是因为网络设计的欠缺&#xff1f;还是数据天然缺陷&#xff1f;是训练代码的bug&#xff1f;还是Tensorflow自身的问题&#xff1f;基于此&#xff0c;阿里工程师推出了DeepInsight深度学习质量平台&#xff0c;致力于解…

开发者如何赶上 5G 风口?

戳蓝字“CSDN云计算”关注我们哦&#xff01;随着5G正式步入商用&#xff0c;5G 技术引发广泛关注。据信息通信研究院《5G经济社会影响白皮书》预测&#xff0c;2030年&#xff0c;5G将直接带动的总产出、经济增加值、就业机会分别为6.3万亿元、2.9万亿元和800万个。据BOSS直聘…

罗辑思维在全链路压测方面的实践和工作笔记

业务的知名度越高&#xff0c;其背后技术团队承受的压力就越大。一旦出现技术问题&#xff0c;就有可能被放大&#xff0c;尤其是当服务的是对知识获取体验要求颇高的用户群体。 提供知识服务的罗辑思维主张“省时间的获取知识”&#xff0c;那么其技术团队在技术实践方面是如…

能用机器完成的,千万别堆工作量|持续集成中的性能自动化测试

1.背景 当前闲鱼在精益开发模式下&#xff0c;整个技术团队面临了诸多的能力落地和挑战&#xff0c;尤其是效能方面的2-1-1的目标(2周需求交付周期&#xff0c;1周需求开发周期&#xff0c;1小时达到发布标准)&#xff0c;具体可见 闲鱼工程师是如何构建持续集成流水线&#x…

详解GPU技术关键参数和应用场景

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | Hardy责编 | 阿秃随着云计算&#xff0c;大数据和人工智能技术发展&#xff0c;边缘计算发挥着越来越重要的作用&#xff0c;补充数据中心算力需求。计算架构要求多样化&#xff0c;需要不同的CPU架构来满足不断增长的算力需…

5款神器级别Github 的Chrome插件

文章目录1. Chrome插件一&#xff1a;octotree2. Chrome插件二&#xff1a;sourcegraph3. Chrome插件三&#xff1a;Enhanced GitHub4. Chrome插件四&#xff1a;octolinker5. Chrome插件五&#xff1a;gitzip for github1. Chrome插件一&#xff1a;octotree Octotree是一个 …

用AI说再见!“辣眼睛”的买家秀

阿里妹导读&#xff1a;提起买家秀和卖家秀&#xff0c;相信大家脑中会立刻浮现出诸多画面。同一件衣服在不同人、光线、角度下&#xff0c;会呈现完全不同的状态。运营小二需从大量的买家秀中挑选出高质量的图片。如果单纯靠人工来完成&#xff0c;工作量过于巨大。下面&#…

云+X案例展 | 电商零售类:WakeData助力叁拾加数字化变革

本案例由WakeData投递并参与评选&#xff0c;CSDN云计算独家全网首发&#xff1b;更多关于【云X 案例征集】的相关信息&#xff0c;点击了解详情丨挖掘展现更多优秀案例&#xff0c;为不同行业领域带来启迪&#xff0c;进而推动整个“云行业”的健康发展。在新零售时代下&#…

linux环境安装Kafka最新版本 jdk1.8

文章目录一、环境分布二、实战1. kafka下载2. 解压3. 配置4. 编写启动脚本5. 编写关闭脚本6. 赋予脚本可执行权限7. 脚本使用案例一、环境分布 软件版本jdk1.8kafkakafka_2.13-2.5.0 二、实战 kafka官网地址&#xff1a; http://kafka.apache.org/downloads 1. kafka下载 …

基于泛型编程的序列化实现方法

写在前面 序列化是一个转储-恢复的操作过程&#xff0c;即支持将一个对象转储到临时缓冲或者永久文件中和恢复临时缓冲或者永久文件中的内容到一个对象中等操作&#xff0c;其目的是可以在不同的应用程序之间共享和传输数据&#xff0c;以达到跨应用程序、跨语言和跨平台的解耦…

微服务架构下,解决数据一致性问题的实践

随着业务的快速发展&#xff0c;应用单体架构暴露出代码可维护性差、容错率低、测试难度大和敏捷交付能力差等诸多问题&#xff0c;微服务应运而生。微服务的诞生一方面解决了上述问题&#xff0c;但是另一方面却引入新的问题&#xff0c;其中主要问题之一就是&#xff1a;如何…

2019阿里云开年Hi购季满返活动火热报名中!

2019阿里云云上采购季活动已经于2月25日正式开启&#xff0c;从已开放的活动页面来看&#xff0c;活动分为三个阶段&#xff1a; 2月25日-3月04日的活动报名阶段、3月04日-3月16日的新购满返5折抢购阶段、3月16日-3月31日的续费抽豪礼5折抢购阶段。 整个大促活动包含1个主会场…

2019云计算高光时刻:乱云飞渡 传统IT大溃败

前言&#xff1a;2019年&#xff0c;物理机最后一张王牌也败给了云计算&#xff0c;无论从成本还是性能的角度&#xff0c;都没有不选云计算的理由&#xff0c;这是一个时代的终结。 2019的云计算市场格局&#xff0c;依旧是马太效应凸显、大者恒大的趋势继续&#xff0c;但在…

java 集成 kafka 0.8.2.1 适配jdk1.6

文章目录一、版本说明二、实战2.1. 依赖2.2. 生产者代码2.3. 消费端代码2.4. 测试三、小伙伴疑难解答3.1. 首先新建一个maven项目3.2. 把我的依赖和代码复制过去3.3. 把我写的case调试通3.4. 找到左边External Libraries3.5. jar处理3.6. 打开非maven项目&#xff0c;添加jar3.…

阿里云MWC 2019发布7款重磅产品,助力全球企业迈向智能化

当地时间2月25日&#xff0c;在巴塞罗那举行的MWC 2019上&#xff0c;阿里云面向全球发布了7款重磅产品&#xff0c;涵盖无服务器计算、高性能存储、全球网络、企业级数据库、大数据计算等主要云产品&#xff0c;可满足电子商务、物流、金融科技以及制造等各行业企业的数字化转…