参考文章:地理空间距离计算优化
首先,这篇文章讲述了两种地理模型,一种是球体,一种是椭球体。一般网站对精度没有太大的需求,对于网站用户而言,只要得到一个大概结果就可以了,因此下面内容将选用球体展开讲述。
查找附近的点,即需要对数据库中的点与当地点的距离排序。
1.在一个球体上,求任意两点A和B的距离,相当于求一个弧长,公式为:
d = (θ / 360) * (2 * π * r) = θ * π * r / 180
注:周长是弧长的360/θ倍。
只要求出夹角θ,就能求出弧长,即求出距离。
2.然后需要将一个点的经纬度转换为r=1的空间坐标,公式为:
x = r * cos b * cos a = cos b * cos a
y = r * cos b * sin a = cos b * sin a
z = r * sin b = sin b
注:经度和纬度的意义为,先绕x轴旋转的度数为纬度值,再绕z轴旋转的度数为经度值。
计算出A和B的空间坐标分别为(x1, y1, z1)和(x2, y2, z2)。
3.然后再求空间两向量的夹角,公式为:
cosθ = (OA * OB) / (|OA| * |OB|) = (x1 * x2 + y1 * y2 + z1 * z2) / (r * r) = x1 * x2 + y1 * y2 + z1 * z2
最后使用arccos求出夹角θ,那么A和B的弧长,即距离求得。
4.但是,对于所需的距离排序,是否真的需要求出两个点的距离?
假设θ1 < θ2,那么θ1 * π * r / 180 < θ2 * π * r / 180,即d1 < d2。
注:这里的r是地球半径,并不是1。
显然是不需要求出距离的,使用夹角排序代替距离排序。
5.接着是否需要求出两个点代表的向量夹角?
假设cos θ1 < cos θ2,那么arccos(cos θ1) > arccos(cos θ2),即θ1 > θ2。
注:函数y = arccos x, y∈[0, π]的单调性为减函数,证明略。
夹角也是不需要求出的,使用cos θ的排序代替夹角的排序,也间接代替了距离排序。
6.对于范围查找,如查找方圆5公里内。
由于上述公式中,使用cos θ排序代替距离排序,是不能计算出范围进行排除的。
由于已经排序好,就可以使用二分法计算,比较,排除,但SQL如何实现二分法,这是一个疑问。
注:个人感觉可以不做统计,即无具体分页,只有下一页,也无总数显示。这样,每次读取的有序数据,在业务层进行距离比较,然后排除。
有了限定范围的数值,就可以在排序之前进行剪枝,从而减少排序时计算和比较的次数。
剪枝的方法有矩形排除,目前我还研究着是否有更有效率的剪枝方法,其中想到一个方向,就是相加。
不过这个方法只研究在平面上,思路是这样的,平面上任意一个点A(x, y),那么x + y与|OA|的关系。
我们知道x = |OA| * cos a,y = |OA| * sin a。
那么x + y = |OA| * sina + |OA| * cos a = |OA| * √2 * sin(a - 45)。
从公式中看出,当a为45度时,sin(a - 45)取最大值即为1,x + y的最大值为|OA| * √2。
假设我要搜索的范围为10,那么x + y的最大值为10 * √2,使用x + y <= 10 * √2进行前枝,把不符合该不等式的点排除。
进一步,|AB|与固定点B(a, b),任意点A(x, y)的关系,(x - a) + (y - b) <= L * √2,L是给定的已知值。
那么x + y <= L * √2 + a + b,其中x + y可以预先计算存入数据库,L * √2 + a + b是查询前计算出来,这个比较的效率是非常高的。
这种假想的剪枝方法是否适用于地理范围查找,尚在研究中。
到这里,不知道我的思路是否正确,因为这篇文章《地理空间距离计算优化》里并没有讲述到,希望有人能帮我参详一下,查了很多资料也没查找到。
文章只是讲到了一个计算距离的公式优化。
优化1:
对于公式cosθ = x1 * x2 + y1 * y2 + z1 * z2,要计算出夹角θ,就得计算出cosθ,由于cosθ运算比较耗时,文章给出了优化方案。
我们知道sinθ ^ 2 + cosθ ^ 2 = 1,那么公式就变为sinθ = √(1 - (x1 * x2 + y1 * y2 + z1 * z2))。
再者,这种优化方案适用于θ角非常小的情况下,sinθ ≈ θ,即√(1 - (x1 * x2 + y1 * y2 + z1 * z2)) ≈ θ。
优化2:
这种优化方案也是适用于θ角非常小的情况下,使用平面距离公式代替球面弧长公式。
优化3:
采用多项式来拟合cos三角函数,达到消除消除cos三角函数的目的。
关于地理距离排序的其它方法,还有geohash。
这个方法就像我们的居住地址一样,生成一个什么省什么市什么村的地址串。
相关文章:《如何实现按距离排序、范围查找》,《GeoHash核心原理解析》