上周有个兄弟找我救火,说他的地图APP在低端安卓机上卡成PPT。
我一看代码,好家伙。
他在每次用户移动时,都实时计算两点间的球面距离。
用的还是最原始的大圆距离公式。
还要把经纬度转弧度,再三角函数一顿操作。
这哪是开发,这是在给CPU做有氧运动。
我直接让他把核心逻辑改了。
不再用传统的经纬度字符串或者浮点数对。
而是引入了geo为单位的坐标体系。
这玩意儿,真的香。
先说个场景。
做外卖配送或者共享单车调度。
你需要判断用户是否在某个商圈的5公里范围内。
如果用传统经纬度,你得写一堆复杂的几何判断。
还要处理地球曲率带来的误差。
稍微不注意,边界上的点就可能被误判。
但用了geo为单位的坐标。
比如GeoHash或者S2 Geometry。
它们把二维的地球表面,映射成一维的字符串或者整数。
这就厉害了。
你可以直接比较字符串的大小。
或者对整数进行范围查询。
数据库索引一建,查询速度提升不止一个档次。
我那个兄弟改完之后,低端机帧率从20帧提到了55帧。
用户反馈说,滑动地图丝般顺滑。
当然,这不是说传统方法一无是处。
但在海量数据面前,geo为单位的坐标优势太明显了。
特别是当你需要处理百万级的POI数据时。
传统方法每次查询都要全表扫描或者复杂的空间索引。
而基于geo为单位的坐标,可以直接利用B+树索引。
甚至可以用简单的范围查询搞定。
这里有个坑,大家注意。
很多人以为用了GeoHash就万事大吉。
其实GeoHash有个致命弱点,就是边界效应。
比如两个点,经纬度非常接近。
但因为刚好跨了边界,它们的Hash值可能天差地别。
这会导致相邻的点被分到不同的桶里。
这时候,你就需要更高级的方案。
比如Google的S2或者Uber的H3。
这些方案把地球划分成六边形或者四边形网格。
不仅计算效率高,而且相邻区域的编码有规律。
我最近在一个物流项目中,就用了H3。
它把全球划分成不同层级的六边形网格。
高层级网格大,低层级网格小。
我们可以根据业务需求,动态调整精度。
比如,城市级配送用低精度,小区级配送用高精度。
这样既保证了性能,又保证了精度。
而且,H3的编码是整数。
在数据库里存储和索引都非常方便。
不需要像经纬度那样占用8字节甚至更多。
节省了大量的存储空间。
对于移动端来说,流量就是金钱。
传输一个短字符串,比传输两个浮点数要快得多。
特别是弱网环境下,这点优势会被放大。
我还发现一个有趣的现象。
很多大厂内部系统,虽然对外接口还是经纬度。
但在内部微服务之间传递位置信息时。
都会转换成geo为单位的坐标。
因为内部数据量大,对性能要求极高。
这种细节,往往决定了系统的上限。
别小看这几个字节的差异。
在亿级用户面前,那就是几百万的服务器成本。
所以,如果你也在做地图相关的开发。
或者需要处理大量的地理位置数据。
真的建议你去研究一下geo为单位的坐标。
别死磕经纬度了。
真的,试过就回不去了。
我现在看到那种还在用经纬度做范围查询的代码。
心里就难受。
就像看到有人骑自行车去送快递一样。
不是不行,是太慢了。
最后提醒一下。
选型的时候,要考虑你的业务场景。
如果只需要简单的附近搜索,GeoHash够用。
如果需要复杂的区域聚合或者高精度的空间分析。
S2或者H3可能更适合你。
别盲目跟风,也别固步自封。
技术选型,永远没有银弹。
只有最适合的。
希望这篇干货,能帮你少走弯路。
毕竟,头发掉得越快,代码写得越烂。
咱们还是稳一点好。
加油,打工人。