geohash网格图_geoHash的数学局限

本文从数学角度探讨GeoHash的局限性,通过皮亚诺曲线和希尔伯特曲线的比较,揭示GeoHash在空间填充上的不连续性。同时,分析了GeoHash在判断两点相近时可能存在的误差,提出不能仅依赖GeoHash值的相似性,而应结合欧氏距离计算。此外,还讨论了如何有效地寻找附近的GeoHash区块。
摘要由CSDN通过智能技术生成

geoHash的问题这篇博客(https://www.jianshu.com/p/7332dcb978b2)里已经写得非常完善了, 本文从数学方面来解释一下它的一些缺陷。明白GeoHash原理的话可以直接看最后一段

一、皮亚诺曲线的数学论证

以下内容节选自知乎:

皮亚诺曲线很有名气,它是一个“填满单位正方形的曲线”,不过它也让人迷惑,一个坑是它其实有过好几个定义,而即使是维基百科,上面的介绍也是错的;另一个坑是,它是按照曲线族的极限定义的,而极限与曲线族中的任意一条曲线,性质未必相同。

比如维基说:“1890年,意大利数学家[朱塞佩·皮亚诺]发明能填满一个正方形的曲线,叫做皮亚诺曲线“——嗯,到这里,是对的,让我们把这个称为定义一。

维基继续说:”其构造方法如下:取一个正方形并且把它分出九个相等的小正方形,然后从左下角的正方形开始至右上角的正方形结束,依次把小正方形的中心用线段连接起来;下一步把每个小正方形分成九个相等的正方形,然后上述方式把其中中心连接起来……将这种操作手续无限进行下去,最终得到的极限情况的曲线就被称作皮亚诺曲线。”图如下:

——嗯,这个说法也成立,让我们称这个为定义二。

两个都成立阿,那不挺好吗?问题就在于,这两个定义是不等价的——皮亚诺当年的构造方法,跟定义二里的构造方法,是不一样的。

——————分割线——————

OK,让我们从头说起。严谨一点,称“填满一个正方形的曲线,叫做皮亚诺曲线“这种最广义的说法,为定义零。皮亚诺的方法为定义一,上面整整齐齐的构造方法,为定义二。

皮亚诺当初首要目的,是为了填满正方形,他并不在乎如上图那样整整齐齐。与皮亚诺最类似的构造方法,在张筑生老师《数学分析新讲》第三册里有介绍,是索恩伯格(Isaac Jacob Schoenberg)1938年提出的:

image

image

image

image

整个过程比较罗嗦,其实想法也很简单,就是把小数拆开,一分为二——比如有小数0.12345678,按奇偶拆成0.1357和0.2468——这样单位区间上0到1的一个小数,就拆成了两个,让它们是纵横坐标,就指定了一个点,这样就填满正方形了。用数学语言说,我们要在单位区间[0,1]上定义两个函数phi和psai,使得对任意x属于[0,1],phi(x),psai(x)也属于[0,1]。x从跑到1,(phi(x), psai(x))从(phi(0), psai(0))跑到(phi(1), psai(1)),把点连起来,就是曲线,然后想办法找到合适的phi和psai,让这个曲线能走遍正方形的所有点,就大功告成。

一分为二最简单的就是如上面例子所示按奇数和偶数位拆开——小数0.12345678,拆成小数对(0.1357, 0.2468).

这里让我们再进一步,用二进制表示,那么十进小数0.5,换成二进制就是0.1,写成0.100000....,可以拆成二进制的小数对(0.10000, 0.00000),换成十进制就是(0.5,0)。

到这里似乎还好,问题在于,这样拆,是不连续的,即,phi和psai不连续!不连续的话,x从跑到1,(phi(x), psai(x))跑的点连不起来,就不是曲线。

验证一下:十进小数0.49999999....,换成二进制就是0.0111111.......,可以拆成二进制的小数对(0.011111...., 0.11111.....),这就是(0.1, 1.0),换成十进制就是(0.5,1)。这样,x从0.49999...跳到0.5,(phi(x), psai(x))从(0.5,1)跳到了(0.5,0),步子太大,断了。

怎么办?上面Schoenberg的构造方法就是来解决这个问题的,简而言之,他引入了三进制,多了一个缓冲区间,这样就把两边连起来了。

Schoenberg function,是这个样子的:

image

上面张老师的书里的图19-10是基本函数w,Schoenberg fucntion是w的一个无穷级数,即函数序列的极限。

可以证明,Schoenberg function处处连续,处处不可导。

Schoenberg function是phi,phi(3x)是psai(x),形成的曲线是这样的:

image

可以看到,跟上面维基的定义二里的乖宝宝相比,这样形成的皮亚诺曲线(定义一),是狂野的多了。

但不管好不好看,可以看到,任何一个单位正方形内的点,都能合并成一个单位区间的数,换句话说,这样定义的皮亚诺曲线,确实是一个满射,它填满了整个正方形。

——————分割线——————

好,现在让我们讨论定义二的曲线。这个曲线明显舒服的多,它的简化版本是希尔伯特曲线(Hilbert Curve)

image

这个定义很直观,唯一要说明的是一个坑:这样的曲线,似乎每一个条线段端点,至少有一个坐标是有理数,那这样的曲线能否经过两个坐标都是无理数的点呢?比如(1/pi, 1/pi)。

这就回到了开头说的:曲线族的极限与曲线族中的任意一条曲线,性质未必相同。

例如有这样的曲线族fk(x) =1/k,很显然任意一条曲线都有f_k(x)>0,但这个曲线族的极限很显然是f(x)=0。

可以证明,定义二所述的皮亚诺曲线,作为曲线族的极限,是经过正方形内的每一个点的,它也是满射。

——————分割线——————

关于皮亚诺曲线的维度和面积,”等待飞翔“的回答里已经阐述,不再赘述。

——————分割线——————

geoHash问题

Geohash 一个点附近的地方(但不绝对) hash 字符串总是有公共前缀,并且公共前缀的长度越长,这两个点距离越近。

由于这个特性,Geohash 就常常被用来作为唯一标识符。用在数据库里面可用 Geohash 来表示一个点。Geohash 这个公共前缀的特性就可以用来快速的进行邻近点的搜索。越接近的点通常和目标点的 Geohash 字符串公共前缀越长(但是这不一定,也有特殊情况,下面举例会说明)

Geohash 也有几种编码形式,常见的有2种,base 32 和 base 36。

Decimal

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

Base 32

0

1

2

3

4

5

6

7

8

9

b

c

d

e

f

g

Decimal

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

Base 32

h

j

k

m

n

p

q

r

s

t

u

v

w

x

y

z

base 36 的版本对大小写敏感,用了36个字符,“23456789bBCdDFgGhHjJKlLMnNPqQrRtTVWX”。

Decimal

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

Base 36

2

3

4

5

6

7

8

9

b

B

C

d

D

F

g

G

h

H

j

Decimal

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

Base 36

J

K

I

L

M

n

N

P

q

Q

r

R

t

T

V

W

X

Geohash 实际应用举例

接下来的举例以 base-32 为例。举个例子。

假设需要查询距离美罗城最近的餐馆,该如何查询?

第一步我们需要把地图网格化,利用 geohash。通过查表,我们选取字符串长度为6的矩形来网格化这张地图。

经过查询,美罗城的经纬度是[31.1932993, 121.43960190000007]。

先处理纬度。地球的纬度区间是[-90,90]。把这个区间分为2部分,即[-90,0),[0,90]。31.1932993位于(0,90]区间,即右区间,标记为1。然后继续把(0,90]区间二分,分为[0,45),[45,90],31.1932993位于[0,45)区间,即左区间,标记为0。一直划分下去。

左区间

中值

右区间

二进制结果

-90

0

90

1

0

45

90

0

0

22.5

45

1

22.5

33.75

45

0

22.5

28.125

33.75

1

28.125

30.9375

33.75

1

30.9375

32.34375

33.75

0

30.9375

31.640625

32.34375

0

30.9375

31.2890625

31.640625

0

30.9375

31.1132812

31.2890625

1

31.1132812

31.2011718

31.2890625

0

31.1132812

31.1572265

31.2011718

1

31.1572265

31.1791992

31.2011718

1

31.1791992

31.1901855

31.2011718

1

31.1901855

31.1956786

31.2011718

0

再处理经度,一样的处理方式。地球经度区间是[-180,180]

左区间

中值

右区间

二进制结果

-180

0

180

1

0

90

180

1

90

135

180

0

90

112.5

135

1

112.5

123.75

135

0

112.5

118.125

123.75

1

118.125

120.9375

123.75

1

120.9375

122.34375

123.75

0

120.9375

121.640625

122.34375

0

120.9375

121.289062

121.640625

1

121.289062

121.464844

121.640625

0

121.289062

121.376953

121.464844

1

121.376953

121.420898

121.464844

1

121.420898

121.442871

121.464844

0

121.420898

121.431885

121.442871

1

纬度产生的二进制是101011000101110,经度产生的二进制是110101100101101,按照“偶数位放经度,奇数位放纬度”的规则,重新组合经度和纬度的二进制串,生成新的:111001100111100000110011110110,最后一步就是把这个最终的字符串转换成字符,对应需要查找 base-32 的表。11100 11001 11100 00011 00111 10110转换成十进制是 28 25 28 3 7 22,查表编码得到最终结果,wtw37q。

我们还可以把这个网格周围8个各自都计算出来。

image.png

从地图上可以看出,这邻近的9个格子,前缀都完全一致。都是wtw37。

如果我们把字符串再增加一位,会有什么样的结果呢?Geohash 增加到7位。

image.png

当Geohash 增加到7位的时候,网格更小了,美罗城的 Geohash 变成了 wtw37qt。

看到这里,读者应该已经清楚了 Geohash 的算法原理了。咱们把6位和7位都组合到一张图上面来看。

可以看到中间大格子的 Geohash 的值是 wtw37q,那么它里面的所有小格子前缀都是 wtw37q。可以想象,当 Geohash 字符串长度为5的时候,Geohash 肯定就为 wtw37 了。

接下来解释之前说的 Geohash 和 Z 阶曲线的关系。回顾最后一步合并经纬度字符串的规则,“偶数位放经度,奇数位放纬度”。读者一定有点好奇,这个规则哪里来的?凭空瞎想的?其实并不是,这个规则就是 Z 阶曲线。看下图:

image.png

几个问题

GeoHash的缺点

我们发现在前面的皮亚诺曲线推倒的过程中, 把小数拆开, 一分为二的过程其实和GeoHash中将经纬度合二为一是个相反过程。 以base-32 为例, 我们假设有一个地理位置二进制为(11111, 111111)和另一个(100000,000000)显然他们离的很远, 我们把它变为GeoHash值, 则一个为11111111111, 一个为100000000000,转换为十进制后为001zz 和 00200: 在数值上这两个点相差很小, 但是实际距离相差很大。 这里对应的数学现象就是前边提到的, 单纯的奇偶交叉排列二进制下是不连续的, 我们可以把精度设的越来越高, 但是终究它的极限是跳跃的。 再看上图我们发现凡是涉及到进位操作的时候都有可能会有跳跃。

所以我们可以看出GeoHash在使用过程中不能简单通过GeoHash值是否近似来判断是否离的很近, 而应一次获取圆心附近的九个方框(通过前缀是否相同判定, 由于进位的情况会改变前缀所以会把这种跳跃点忽略), 拿到所有点位后, 通过求欧氏距离来算定远近。

如何找到附近的区块

我们很容易联想到如果一个点在格林尼治天文台附近, 那么单纯通过前缀他会忽略掉离自己很近的目标。 事实上所有处于二分位置的线附近都会有一样的问题, 即明明离的很近, 但是前缀完全不同。 事实上查找附近区块是有规律的

image.png

通过这个图我们可以看出来, base32会把空间分为32块, 每一个小空间的空间排序也是一样的, 这样通过简单的排序规则, 我们就可以找到附近的8个区块的前缀, 然后一次获取9个区块, 再进行欧氏距离计算。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值