兄弟篇:【搬砖笔记】 利用GeoHash为地理位置编码——实现篇
一、前言
最近有个需求,要计算出客户坐标附近5公里的所有门店,并按照步行距离排序。
最直接的方法就是遍历该城市下的所有门店,但是该方法明显不可取,因为在门店数量巨大,且还需要计算步行距离并排序的情况下,时间复杂度过高。
突然想到当年做图像遇见一个问题:给定一个视频中连续的三千帧,但是已经乱序,告诉你第一帧,将这三千帧进行排序。遍历图像的所有像素点同样不可取,当时的解决方案是利用感知哈希计算出所有图像的指纹,接着利用明氏距离计算距离第一张最近的图像作为第二张,然后计算距离第二张最近的作为第三张,以此类推。
同样,肯定也有哈希方法可将地理位置转换成某种编码,并且编码可用于地理计算。它就是 GeoHash。
二、相关知识
进入正文之前,先一起回顾一下初中地理:
本初子午线以西为西经,分十二区,每区15度共180度;以东为东经,同样分十二区,共180度。
赤道以北为北纬,共90度;以南为南纬,同样90度。
那么在计算机中,坐标表示为:
西经为负数,东经为正数,因此经度取值
[-180, 180]
。北纬为正数,南纬为负数,因此纬度取值
[-90, 90]
。
我们知道赤道长约四万公里,因此经度上每度约等于111公里。地球实际上是个不规则球体,但为了简便计算,我们假设把纬度上每度约等于222公里。
三、初识 GeoHash
1. 计算二进制编码
首先计算二进制编码,经度上以[-180, 180]
开始,纬度以[-90, 90]
开始,每次将区间进行二分,若输入坐标小于中间值则编码为0
,下次区间取左半区间;若大于则编码为1
,下次区间取右半区间。以此类推,编码越长,越接近坐标值,进而越精确。
以 118°04′04, 24°26′46
为例,首先计算经度的编码:
编码长度 | 区间 | 中间值 | 编码 | 说明 | 精度(千米) |
---|---|---|---|---|---|
1 | [-180, 180] | 0 | 1 | 118°04′04 大于 0°,因此编码1,取右区间 | 19980 |
2 | [0, 180] | 90 | 1 | 118°04′04 大于 90° | 9990 |
3 | [90, 180] | 135 | 0 | 118°04′04 小于 135°,因此编码0,取左区间 | 4995 |
4 | [90, 135] | 112.5 | 1 | 2497.5 | |
5 | [112.5, 135] | 123.75 | 0 | 1248.75 | |
6 |