热门IT资讯网

解决geohash编码跨区域问题

发表于:2024-11-25 作者:热门IT资讯网编辑
编辑最后更新 2024年11月25日,在上一篇文章中提出用geohash解决匹配点的性能问题,该算法有个缺陷也就是如果在边界上的时候,该点附近的点可能就跨界了,也就是通过该点的geohash值无法找到对应的点。例如:图中蓝色点为需要绑路映

在上一篇文章中提出用geohash解决匹配点的性能问题,该算法有个缺陷也就是如果在边界上的时候,该点附近的点可能就跨界了,也就是通过该点的geohash值无法找到对应的点。例如:

图中蓝色点为需要绑路映射的点
下方的红点为绑路计算之后的点
导致偏移的原因是
随州街上的点数据 在geohashcode分区时都属于蓝点上方的分区
在数据库中查询出来的结果显示 和蓝色点在一个分区的路网数据位于下图

所以找到的数据均位于下方的道路上 导致偏移问题
为了解决这个问题提出扩散hashcode的代码查找附近范围的geohashcode代码
代码如下
所以找到的数据均位于下方的道路上 导致偏移问题
为了解决这个问题提出扩散hashcode的代码查找附近范围的geohashcode代码
代码如下

"""A simple GeoHash implementation."""`# Forward and reverse base 32 mapBASESEQUENCE = '0123456789bcdefghjkmnpqrstuvwxyz'BASE32MAP = dict((k, count) for count, k in enumerate(BASESEQUENCE))BASE32MAPR = dict((count, k) for count, k in enumerate(BASESEQUENCE))def _bits_to_float(bits, lower=-90.0, middle=0.0, upper=90.0):    """Convert GeoHash bits to a float."""    for i in bits:        if i:            lower = middle        else:            upper = middle        middle = (upper + lower) / 2    return middledef _float_to_bits(value, lower=-90.0, middle=0.0, upper=90.0, length=15):    """Convert a float to a list of GeoHash bits."""    ret = []    for i in range(length):        if value >= middle:            lower = middle            ret.append(1)        else:            upper = middle            ret.append(0)        middle = (upper + lower) / 2    return retdef _geohash_to_bits(value):    """Convert a GeoHash to a list of GeoHash bits."""    b = map(BASE32MAP.get, value)    ret = []    for i in b:        out = []        for z in range(5):            out.append(i & 0b1)            i = i >> 1        ret += out[::-1]    return retdef _bits_to_geohash(value):    """Convert a list of GeoHash bits to a GeoHash."""    ret = []    # Get 5 bits at a time    for i in (value[i:i + 5] for i in range(0, len(value), 5)):        # Convert binary to integer        # Note: reverse here, the slice above doesn't work quite right in reverse.        total = sum([(bit * 2 ** count) for count, bit in enumerate(i[::-1])])        ret.append(BASE32MAPR[total])    # Join the string and return    return "".join(ret)# Publicdef decode(value):    """Decode a geohash. Returns a (lon,lat) pair."""    assert value, "Invalid geohash: %s" % value    # Get the GeoHash bits    bits = _geohash_to_bits(value)    # Unzip the GeoHash bits.    lon = bits[0::2]    lat = bits[1::2]    # Convert to lat/lon    return (        _bits_to_float(lon, lower=-180.0, upper=180.0),        _bits_to_float(lat)    )def encode(lonlat, length=12):    """Encode a (lon,lat) pair to a GeoHash."""    assert len(lonlat) == 2, "Invalid lon/lat: %s" % lonlat    # Half the length for each component.    length /= 2    lon = _float_to_bits(lonlat[0], lower=-180.0, upper=180.0, length=length * 5)    lat = _float_to_bits(lonlat[1], lower=-90.0, upper=90.0, length=length * 5)    # Zip the GeoHash bits.    ret = []    for a, b in zip(lon, lat):        ret.append(a)        ret.append(b)    return _bits_to_geohash(ret)def adjacent(geohash, direction):    """Return the adjacent geohash for a given direction."""    # Based on an MIT licensed implementation by Chris Veness from:    #   http://www.movable-type.co.uk/scripts/geohash.html    assert direction in 'nsew', "Invalid direction: %s" % direction    assert geohash, "Invalid geohash: %s" % geohash    neighbor = {        'n': ['p0r21436x8zb9dcf5h7kjnmqesgutwvy', 'bc01fg45238967deuvhjyznpkmstqrwx'],        's': ['14365h7k9dcfesgujnmqp0r2twvyx8zb', '238967debc01fg45kmstqrwxuvhjyznp'],        'e': ['bc01fg45238967deuvhjyznpkmstqrwx', 'p0r21436x8zb9dcf5h7kjnmqesgutwvy'],        'w': ['238967debc01fg45kmstqrwxuvhjyznp', '14365h7k9dcfesgujnmqp0r2twvyx8zb']    }    border = {        'n': ['prxz', 'bcfguvyz'],        's': ['028b', '0145hjnp'],        'e': ['bcfguvyz', 'prxz'],        'w': ['0145hjnp', '028b']    }    last = geohash[-1]    parent = geohash[0:-1]    t = len(geohash) % 2    # Check for edge cases    if (last in border[direction][t]) and (parent):        parent = adjacent(parent, direction)    return parent + BASESEQUENCE[neighbor[direction][t].index(last)]def neighbors(geohash):    """Return all neighboring geohashes."""    return {        'n': adjacent(geohash, 'n'),        'ne': adjacent(adjacent(geohash, 'n'), 'e'),        'e': adjacent(geohash, 'e'),        'se': adjacent(adjacent(geohash, 's'), 'e'),        's': adjacent(geohash, 's'),        'sw': adjacent(adjacent(geohash, 's'), 'w'),        'w': adjacent(geohash, 'w'),        'nw': adjacent(adjacent(geohash, 'n'), 'w'),        'c': geohash    }def neighborsfit(centroid, points):    centroid = encode(centroid)    points = map(encode, points)    for i in range(1, len(centroid)):        g = centroid[0:i]        n = set(neighbors(g).values())        unbounded = [point for point in points if (point[0:i] not in n)]        if unbounded:            break    return g[0:-1]
0