基于Geohash实现根据经纬度的快速定位

文章介绍了如何基于GeoHash技术改进地理位置定位流程,以提高效率。旧方案使用GeoSpark,但性能不佳。GeoHash能将经纬度转换为字符串,通过匹配预构建的GeoHash网格实现快速定位。通过编写UDF并集成到Hive,实现实时计算GeoHash并进行数据去重,最终提升定位速度并优化数据质量。
摘要由CSDN通过智能技术生成

背景介绍

在项目中,SDK会上报包含用户经纬度信息的一系列数据,我们需要根据经纬度信息定位出此条数据上报时用户所在的位置(包括国家、省、市、区),并和其他信息写入宽表中。

旧方案

旧方案中,主要使用GeoSpark对数据进行定位,考虑到同一个经纬度下会有多条数据,所以我们先对数据做分组,同一个用户同一个会话下相同经纬度的数据分为一组,从每组数据中抽取第一条生成一张临时表,再在临时表上调用GeoSpark算出district_id,city_id,province_id,country_id,之后将临时表与原表关联,用临时表的四个ID填充相同经纬度的其他数据的ID。
在测试过程中,我们发现有很小一部分数据只有district_id或city_id等细粒度数据,却没有与之相对的province_id、country_id等数据,这是老大所不能接受的(在哪个城市都知道了,国家你给我个null??? =。=),所以在计算四个ID之后,会有一个反推的步骤,即:判断是否有下层ID不为空上层ID却为空的情况,如果有,通过下层ID进行反推,得到上层ID,并填充。

中间还有一些其他的过滤排序逻辑不做具体介绍,最后当整个定位逻辑完成后,需要做6~7次的shuffle,我们发现其性能远低于预期,在我们每天将近40亿的数据量下,较大的拖慢了整个流程的运行速度,影响了数据产出,因此需要对这一部分进行优化。经过调研后,本菜鸡决定采用GeoHash的方式进行优化。

什么是Geohash

简单介绍下GeoHash,我们可以用一个经纬度的点(例如点A: 37.788422,-122.391907 )计算出一个GeoHash字符串(9q8yyzh),这个字符串代表一个矩形面,点A以及点A附近的点B(37.787933,-122.392887)虽然经纬度不同,但通过经纬度计算出的GeoHash字符串相同,也就是说AB两个点都在(9q8yyzh)这个面内。这样就将二维的经纬度坐标转换成了一维的字符串表示。

但A附近的多少点会跟A共享相同的字符串呢?也就是这个面的大小是怎么确定的呢?这就取决于GeoHash字符串的长度了,GeoHash的字符串长度越长,意味着这个面也就越小,会有更少的点跟A共享同样的GeoHash值。

geohash简介: geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。geohash有以下几个特点: 首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。 其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。 第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM place WHERE geohash LIKE 'wx4g0e%'),即可查询附近的所有地点。Geohash比直接用经纬度的高效很多。用途: 移动互联网,lbs可以说是一个基础应用,geohash对于解决附近地点搜索提供了一个有效的解决方案。扩展: 这个php扩展,提供了三个函数:/**     *  $latitude    //纬度     *  $longitude   //经度     *  $precision   //精密度, 默认是12     *  返回 $precision 长度的 string     */    geohash_encode($latitude, $longitude, $precision=12);      /**     *  $hash    //geohash_encode后的值     *  返回 array // Array     *                    (     *                        [latitude] => 39.416916975752     *                        [longitude] => 100.92223992571     *                        [north] => 39.416917059571     *                        [east] => 100.92224009335     *                        [south] => 100.92223992571     *                        [west] => 100.92223975807     *                    )     */    geohash_decode($hash);    /**     *  $hash    //geohash_encode后的值     *  返回 在$hash 8个 (东南西北各二个)附近的hash值     */    geohash_neighbors($hash); 标签:geohash
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值