前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >继续搞【附近】系列---MySQL搞LBS(二)

继续搞【附近】系列---MySQL搞LBS(二)

作者头像
老李秀
发布2019-11-13 16:24:25
1.3K0
发布2019-11-13 16:24:25
举报

又不是不能用...

考虑到在座的各位...都是泥腿子,唯一会做的就是用PHP CRUD,而且即便是只会搞CRUD,也还是离不开MySQL。

没有了MySQL就好像缺了一条腿

如果说利用MySQL搞LBS,是需要分版本的,分水岭是5.7:

  • 5.7之前的MySQL没有内置对GIS查询的支持
  • 5.7以及之后的MySQL直接内置了对GIS查询

然而实际上对于MySQL来说,根据长期以来的一贯印象,它处理GIS查询怎么说呢:

在5.7之前的话,一般说遇到GIS查询量不太大的话,利用MySQL实现LBS都会利用一种叫做GEOHASH的技术。简单说来,就是将一个人所在的经纬度地址通过一种算法转化为一坨字符串,大概就类似下面这种:

121.52413,31.261012 ==> wtw3v6g

121.12415,31.25338 ==> wtw1u1x

经纬度越相近,它们转换成的字符串的前缀就越相似。事情到这里,总体方案就比较明朗了:就是将一个人经纬度的geohash字符串保存到MySQL数据库里,然后通过MySQL的like去模糊匹配geohash前缀就可以了。

所以,从现在开始,我们需要搞明白两件事:

  • 搞明白经纬度到geohash字符串的算法流程
  • 如何在工程代码里具体实现这个过程

我们的地球从东西维度分为东西半球,从南北维度分为南北半球。南北半球中间被中间的赤道分为两半,与赤道平行的线称为纬线,与赤道呈90度垂直相交的线并经过南北极的叫做经线。所以,维度一般称为南北纬,经度一般称为东西经。

假如说,我是说假如,我们将地球表面能够展开的话,我们可以将其“ 抽象 ”成一个平面(那个谁闭嘴,我知道球体的铺不成方的),你们感受一下:

不用搜图了,上面图是我自己做的

有了图的辅助后就会容易理解很多,根据国际公约并结合上图,我们可以得知:

  • 北纬的范围是(0度,90度),南纬的范围是(0度,-90度)
  • 东经的范围是(0度,180度),西经的范围是(0度,-180度)
  • 纬度的0度就是赤道;经度的0度就是本初子午线,转半圈后180度处就是东经和西经的交界线

下面我们利用geohash算法给经纬度(104.07642,38.6518)换算一下字符串(104.07642是经度,38.6518是纬度),你们感受一下过程。


经度

  • 第一次:以0位界限,分为(-180,0)和(0,180)左右两部分,104.07642处于右侧(0,180)之间,标记计为1
  • 第二次:以90位界限,分为(0,90)和(90,180)左右两部分,104.07642处于右侧(90,180)个之间,标记计为1
  • 第三次:以135位界限,分为(90,135)和(135,180)左右两部分,104.07642处于右侧(90,135)之间,标记计为0
  • 第四次:以112.5位界限,分为(90,112.5)和(112.5,135)左右两部分,104.07642处于右侧(90,112.5)之间,标记计为0
  • 第五次:以101.25位界限,分为(90,101.25)和(101.25,112.5)左右两部分,104.07642处于右侧(101.25,112.5)之间,标记计为1
  • 第六次:... ...

...我相信你们一定观察出规律了...

主要我特么快吐了,算不下去了

我们将上述过程的标记依次记录下来:11001。


纬度

人类的本质是什么?复读机

请按照纬度(-90,0)(0,90)范围,结合人类本质去搞定经度的算法。总之,最终结果为:10110。


然后我们按照偶数位置放经度,奇数位置放纬度(注意位置从0开始而不是1)的规则将上面标记位组装起来,形成一个最终的数字字符串(注意第二行是数字位置,第一行是数字字符串):

然后将1110010110五个一组,分开:11100 10110。其中11100十进制转换后为数字28,10110十进制转换后为22。

最后,我需要复制粘贴一张Base32的转换表,但是要注意这个Base32是指geohash的Base32,和通用Base32并不一样,这个Base32少了几个英文字母,你们感受一下:

所以十进制的28就是w,十进制的22则为q。

也就是说,经纬度(104.07642,38.6518)在我们经过了5次运算后得到的geohash字符串长度为两位:wq。

两位长度wq代表啥位置?

有兴趣的同学可以打开下面的链接http://geohash.cn,然后大概定位到银川市、太原市附近,随便点一下,感受到了没有?然后我们结合下图大概说下wq如何定位的点的简单流程。

这张图中,世界被32个网格划分了出来。对于wq而言:

  • 首先将w区域挖出来
  • 然后将w区域再次按照上面的32个网格划分
  • 然后将q区域挖出来

肉眼可知,wq的精确度是十分感人的。它囊括中国西北一大坨地区,包括著名县城 --- 平安县城、甚至连晋西北三大B王的势力范围似乎都被囊括在内了。

如果说我们要继续缩小范围提高精确度,怎么办?那就将上面计算继续复制粘贴多跑几次,这样将会得到长度更长的geohash字符串,精确度会更高。反正我就算个wq能圈住晋西北就行了,我不陪你们玩了,你们谁有兴趣就继续算下去,算的更精确一些,对我来说晋西北就算到家了。

叨逼叨了这么久,问题来了:逻辑实现代码谁来写?

至于你写不写,反正我懒得写。这是一个面向github和stackoverflow的复读机编程年代,业务快速迭代不会给你太多时间去亲自实现。在明白了大概原理的前提下,直接搞代码run起来方显王者风范。好在朦朦胧胧记得大概三年多以前我初次接触geohash的时候,桶哥给我发过他实现的PHP扩展版本的geohash,地址是这个:

https://github.com/shenzhe/geohash

扩展的安装方法我不叨叨了,我假装你们都【精通】这个流程,然后我们尝试把上面的经纬度(104.07642,38.6518)换算成geohash:

<?php

// long经度104.07642,lat维度38.6518, precision为精度,
// precision=12就表示geohash长度为12,估计能找到 坂田联队 了
$longitude = 104.07642;
$latitude  = 38.6518;
$s_hash    = geohash_encode( $latitude, $longitude, $precision = 12 );
echo ' ( 104.07642,38.6518 ) 的geohash为:'.$s_hash.PHP_EOL;

// 根据geohash逆向出经纬度
$a_ret = geohash_decode( $s_hash );
print_r( $a_ret );

上面代码执行一下,结果如下图,你们感受一下:

一些青年似乎注意到了桶哥的扩展API里似乎还有一个叫做geohash_neighbors的实现。这个是干啥用的?我用自己蹩脚的三流英文水准看好像大概就是“ xxx邻居 ”的意思?没事儿找“ 邻居 ”做什么?... ...怎么感觉氛围有点儿怪怪的,你们想什么呢?...

咳咳

那个,是这样的。有一些细心的观众可能已经意识到了一个问题:那就是边界问题。我们用geohash将某个区域划分成32个方块块,然后给每个方块块一坨字符串来标记,有时候会产生一个问题。看下图这种业务场景,你们感受一下:

从人类角度出发,如果说二狗要找TA附近的沙县小吃,那么沙县小吃B应该是TA的最佳选择。但是如果二狗用geohash这种高科技去找沙县小吃,高科技会把TA带到沙县小吃A,因为沙县小吃A和二狗的geohash是完全一样的。肿么办?所以,一般我们在业务中使用geohash的时候,一般不会仅仅使用一块区域的geohash,而是顺带将该区域周遭的八个区域也带上一起查询;在查询完后完毕出来结果后,还需要进行结果进行距离运算,然后按照距离进行排序。以上,为geohash的缺点。

总的来说,geohash是一种轻量级的解决点位置的一种解决方案。如果你业务对LBS使用并不频繁,不想因此引入一个新的应用软件,就可以考虑使用这种方式来实现一下。


后记

去年来我司面试的时候,胡老板偶然之间问起了我geohash的实现原理,无奈当时状态实在是差的要命回答的实在是辣鸡。问的全都是各种业务逻辑实现的细节,对我这种能搞出来0-90但是90-100搞不好的人来说真的是全方位的打击,当时从东软出来后真想一头扎在地上。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能API社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档