geohash是常用来做地理位置查询,是lbs项目中常用的技术。详细原理就不细说了,可以参考如下链接:

源码:

一般来说,取当前坐标临近坐标常规做法是取当前坐标所在区块的周边一圈区块,即一个九宫格,能够得到充足的数据量,同时避免边界问题。但是实际项目使用过程当中发现除了边界问题,还有一个精度问题。当geohash位数多的情况下,精度高,区块面积小,那么范围内的坐标点就会比较少,甚至出现没有的情况,如果位数少,那么区块面积大,范围内坐标点过多,那么距离计算量就会比较大。在golang版本的源码中,提供了GetNeighbors方法,直接取到九宫格,但是在上述场景下就会比较鸡肋。于是扩展了一下,以类似水波扩散的方式取数据,将每一圈的区块全部取出来。

效果图:

QQ20151026-0@2x.png

fork的golang版本: https://github.com/sillydong/geohash

LoopNeighbors函数,返回结果为二维数组,第一个维度是层,第二个维度的索引对应上图中所示位置

示例:

package main

import (
    "fmt"
    "github.com/sillydong/geohash"
)

func main() {
    latitude := 39.92324
    longitude := 116.3906
    precision := 6

    loopneighbors := geohash.LoopNeighbors(latitude, longitude, precision, 3)
    for loop, hashs := range loopneighbors {
        fmt.Printf("loop: %d\n", loop)
        for _, hash := range hashs {
            fmt.Println("\t"+hash)
        }
    }
}

说明

  • 实际上,当loop的值为1时,取出来的就是一个九宫格,区块的结果与GetNeighbors相同

6位精度下圈数面积对应关系

圈数 宽km 长km 面积(km2)
1 3.6 1.8282 6.58152
2 6 3.047 18.282
3 8.4 4.2658 35.83272
4 10.8 5.4846 59.23368
5 13.2 6.7034 88.48488