Golang笔记

用LevelDB 作为地理数据库

用Goleveldb 来作地理数据库,用到 Goleveldb、Geohash。

利用leveldb 的byte ordered 特性可以做高效查询。

Geohash 可以把一个地点的经度和纬度(46.770 -71.304)转为一个8位字符串,如:f2m616nn,还能缩成4个字符:f2m61 (46.8 -71.3),只是精度不同。

这样就可以用 4 digits geohash + a uniq id 的方式存放地点的位置信息。

生成一个 int64 uniq id:

// NewKey generates a new key using time prefixed by 'K'
func NewKey() Key {
    return NewKeyWithInt(time.Now().UnixNano())
}

// NewKeyWithInt returns a key prefixed by 'K' with value i
func NewKeyWithInt(id int64) Key {
    key := bytes.NewBufferString("K")
    binary.Write(key, binary.BigEndian, id)
    return key.Bytes()
}

假设要生成的key 是下面这个样子:

G201509262105dhv766K��Ϸ�Y�

完善上面的代码:

// NewGeoKey generates a new key using a position & a key
func NewGeoKey(latitude, longitude float64) GeoKey {
    t := time.Now().UTC()
    kint := t.UnixNano()
    kid := NewKeyWithInt(kint)
    // G + string date + geohash 6 + timestamped key 
    // G201508282105dhv766K....
    gk := geohash.EncodeWithPrecision(latitude, longitude, 6)
    ts := t.Format("2006010215")

    // modulo 10 to store 10mn interval
    m := t.Minute() - t.Minute()%10
    zkey := []byte("G" + ts + fmt.Sprintf("%02d", m) + gk)
    zkey = append(zkey, kid...)
    return zkey
}

生成GeoKey 列表:

// GeoKeyPrefix return prefixes to lookup using a GeoKey and timerange
func GeoKeyPrefix(start, stop time.Time) []string {
    var res []string
    d := 10 * time.Minute
    var t time.Time
    t = start
    for {
        if t.After(stop) {
            break
        }

        key := "G" + t.Format("2006010215") + fmt.Sprintf("%02d", t.Minute()-t.Minute()%10)
        res = append(res, key)
        t = t.Add(d)
    }
    return res
}

查询数据库:

d := time.Duration(-10) * time.Minute
geoPrefixs := GeoKeyPrefix(time.Now().UTC().Add(d), time.Now().UTC())

// find adjacent hashes in m
// 1, 5003530
// 2, 625441
// 3, 123264
// 4, 19545
// 5, 3803
// 6, 610
gk := geohash.EncodeWithPrecision(lat, long, 4)
adjs := geohash.CalculateAllAdjacent(gk)
adjs = append(adjs, gk)

// for each adjacent blocks
for _, gkl := range adjs {

    // for each time range modulo 10
    for _, geoPrefix := range geoPrefixs {
        startGeoKey := []byte(geoPrefix + gkl)
        iter := s.NewIterator(util.BytesPrefix(startGeoKey), nil)

        for iter.Next() {
            log.Println(iter.Value())
        }
        iter.Release()
    }
}

用到的链接

原文《http://blog.nobugware.com/post/2015/leveldb_geohash_golang/ 6

本文网址: https://golangnote.com/topic/84.html (转载注明出处)
关于GolangNote:记录在工作中使用golang 遇到、面临的相关问题及解决方法。如果你在这里获得一些知识或信息,解决你的编程问题,请考虑捐赠给不幸的人或者你喜欢的慈善机构,除捐赠外,种植树木、志愿服务或减少排碳的行为也很有益处。如果你有任何问题可以在下面 留言
Be the first to comment!
Captcha image
Relative Articles