GeoHash

1. 简介

Geohash是一种地理编码,用于将二维经纬度映射成一维编码,方便计算机存储与索引。

2. 基本原理

分别将经纬度进行二等分逼近编码,按照所属区域进行连续编码,最后将两组编码混合进行Base32编码,便生成Geohash编码。

如下所是对经纬度(110.53785, 39.92324)进行Geohash编码:

    经度范围    区间编码:0    区间编码:1    110.53785
1    (-180.000000 180.000000)    (-180.000000, 0.000000)    (0.000000 180.000000)    1
2    (0.000000 180.000000)    (0.000000, 90.000000)    (90.000000 180.000000)    0
3    (90.000000 180.000000)    (90.000000, 135.000000)    (135.000000 180.000000)    1
4    (90.000000 135.000000)    (90.000000, 112.500000)    (112.500000 135.000000)    1
5    (90.000000 112.500000)    (90.000000, 101.250000)    (101.250000 112.500000)    1
6    (101.250000 112.500000)    (101.250000, 106.875000)    (106.875000 112.500000)    0
7    (106.875000 112.500000)    (106.875000, 109.687500)    (109.687500 112.500000)    0
8    (109.687500 112.500000)    (109.687500, 111.093750)    (111.093750 112.500000)    0
9    (109.687500 111.093750)    (109.687500, 110.390625)    (110.390625 111.093750)    1
10    (110.390625 111.093750)    (110.390625, 110.742188)    (110.742188 111.093750)    1
11    (110.390625 110.742188)    (110.390625, 110.566406)    (110.566406 110.742188)    0
12    (110.390625 110.566406)    (110.390625, 110.478516)    (110.478516 110.566406)    0
13    (110.478516 110.566406)    (110.478516, 110.522461)    (110.522461 110.566406)    0
14    (110.522461 110.566406)    (110.522461, 110.544434)    (110.544434 110.566406)    1
15    (110.522461 110.544434)    (110.522461, 110.533447)    (110.533447 110.544434)    1
      纬度范围                   区间编码:0                 区间编码:1              39.92324
1     (-90.000000 90.000000)   (-90.000000, 0.000000)    (0.000000 90.000000)     1
2     (0.000000 90.000000)     (0.000000, 45.000000)     (45.000000 90.000000)    0
3     (0.000000 45.000000)     (0.000000, 22.500000)     (22.500000 45.000000)    1
4     (22.500000 45.000000)    (22.500000, 33.750000)    (33.750000 45.000000)    1
5     (33.750000 45.000000)    (33.750000, 39.375000)    (39.375000 45.000000)    1
6     (39.375000 45.000000)    (39.375000, 42.187500)    (42.187500 45.000000)    0
7     (39.375000 42.187500)    (39.375000, 40.781250)    (40.781250 42.187500)    0
8     (39.375000 40.781250)    (39.375000, 40.078125)    (40.078125 40.781250)    0
9     (39.375000 40.078125)    (39.375000, 39.726562)    (39.726562 40.078125)    1
10    (39.726562 40.078125)    (39.726562, 39.902344)    (39.902344 40.078125)    1
11    (39.902344 40.078125)    (39.902344, 39.990234)    (39.990234 40.078125)    0
12    (39.902344 39.990234)    (39.902344, 39.946289)    (39.946289 39.990234)    0
13    (39.902344 39.946289)    (39.902344, 39.924316)    (39.924316 39.946289)    0
14    (39.902344 39.924316)    (39.902344, 39.913330)    (39.913330 39.924316)    1
15    (39.913330 39.924316)    (39.913330, 39.918823)    (39.918823 39.924316)    1

  经纬度交叉编码(偶数位:经度,奇数位:纬度):

编码    1 1 0 0 1 1 1 1 1 1 0  0  0  0  0  0  1  1  1  1  0  0  0  0  0  0  1  1  1   1
序号    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

 

 Base32 编码:

 

十进制    0    1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25    26    27    28    29    30    31
Base32    0    1    2    3    4    5    6    7    8    9    b    c    d    e    f    g    h    j    k    m    n    p    q    r    s    t    u    v    w    x    y    z

交叉编码进行Base32化(5位二进制对应一个Base32码)

编码    1    1    0    0    1    1    1    1    1    1    0    0    0    0    0    0    1    1    1    1    0    0    0    0    0    0    1    1    1    1
序号    0    1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25    26    27    28    29
    25/T                    31/Z                    0/0                    15/G                    0/0                    15/G                

编码结果:TZ0G0G

3. 精度

(geohash length * 5 == lat bits + lng bits)

4. 查询

1)静态邻域查询

将坐标点编码成Geohash存储在Redis或MySQL(排序进行索引)中,前缀匹配进行邻域查询。 

2)动态邻域查询(动态点、线段、多边形)

对于动态邻域查询需要转换思路,需要将地图进行Geohash切分与编码,具体的实体该在与之相交的格子中。

5. 线与多边形编码

上述主要进行了点的Geohash编码,对于线与多边形就需要转换一下思路,不再对线与多边形进行编码,而对平面空间区域进行Geohash划分。确定精度后,我们可以把地球表面划分成大小相近的四边形格子,每个格子都拥有一个Geohash编码。此时计算与线段或多边形相交的格子,从而得到一组Geohash编码,这组Geohash编码便是该线段或多边形的Geohash编码。

在存储上,这组Geohash节点下都将挂在该线段或多边形,在查询时,其中任何一个Geohash被命中,都将命中该线段或多边形。

7. 问题

1)交叉编码为何精度在前?

精度范围比纬度范围广,同时当Base32的编码位长度为奇数时,精度可以多进行一位编码。

2)Geohash编码为何是Z编码?

坐标Geohash编码后排序,便成为了Z编码,如图。

3)邻域查询

  查询范围内的命中目标?

  方案1:

    1)将查询范围进行Geohash编码,得到一组Geohash编码;

    2)判度每个Geohash的空间范围是否完全在查询范围内:

      YES:该Geohash下的目标都被命中

      NO:该Geohash下的目标与查询范围进行过滤

4)周边格子搜索

  搜索指定个周围8个方向的格子:

  

  如上图所示,经度在划分的时候,从左到右具有递增规律,在同一层级寻找左右方向格子只需要对当前格子进行+-1即可(纬度同理)。

8. 扩展

Geohash作为一种地理编码,不仅可以用于二维数据一维化,还可以用于地理数据索引,在Redis中作为Hash Key进行索引存储。作为地理索引,还可以参考RTree和Google s2。

posted on 2019-04-29 11:37  wanghaiyang1930  阅读(1737)  评论(0编辑  收藏  举报

导航