Geohash

一.GeoHash编码介绍

参考:

https://hogwartsrico.github.io/2015/01/22/About-GeoHash/

Geohash原理 - 简书 (jianshu.com)

1.Geohash认识

GeoHash本质上是空间索引的一种方式,其基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码。以GeoHash方式建立空间索引,可以提高对空间poi数据进行经纬度检索的效率。

GeoHash将二维的经纬度转换成字符串,比如下图展示了北京9个区域的GeoHash字符串,分别是WX4ER,WX4G2、WX4G3等等,每一个字符串代表了某一矩形区域。也就是说,这个矩形区域内所有的点(经纬度坐标)都共享相同的GeoHash字符串,这样既可以保护隐私(只表示大概区域位置而不是具体的点),又比较容易做缓存。

​ Geohash编码中,字符串相似的表示距离相近(特殊情况后文阐述),这样可以利用字符串的前缀匹配来查询附近的POI信息。如下两个图所示,一个在城区,一个在郊区,城区的GeoHash字符串之间比较相似,郊区的字符串之间也比较相似,而城区和郊区的GeoHash字符串相似程度要低些。此外,不同的编码长度,表示不同的范围区间,字符串越长,表示的范围越精确。

2.GeoHash算法

​ 以经纬度值:(116.389550, 39.928167)进行算法说明,对纬度39.928167进行逼近编码 (地球纬度区间是[-90,90]

a. 区间[-90,90]进行二分为[-90,0),[0,90],称为左右区间,可以确定39.928167属于右区间[0,90],给标记为1

b. 接着将区间[0,90]进行二分为 [0,45),[45,90],可以确定39.928167属于左区间 [0,45),给标记为0

c. 递归上述过程39.928167总是属于某个区间[a,b]。随着每次迭代区间[a,b]总在缩小,并越来越逼近39.928167

d. 如果给定的纬度x(39.928167)属于左区间,则记录0,如果属于右区间则记录1,序列的长度跟给定的区间划分次数有关,如下图

​ e. 同理,地球经度区间是[-180,180],可以对经度116.389550进行编码。通过上述计算, 经度产生的编码为1 1 0 1 0 0 1 0 1 1 0 0 0 1 0,纬度产生的编码为1 0 1 1 1 0 0 0 1 1 0 0 0 1 1

​ f. 合并:偶数位放经度(0,2,4,6,8),奇数位放纬度(1,3,5,7,9),把2串编码组合生成新串如下图(先放经度,后放纬度)

​ g. 首先将11100 11101 00100 01111 0000 01101转成十进制,对应着28、29、4、15,0,13 十进制对应的base32编码就是wx4g0e,如下图.

Base32编码:

首先将二进制串划分每5位一组,不足5位补0。

然后将各组的5位二进制串转成十进制(5bits对应着10进制的数值为0-31)。

用0-9、b-z(去掉a、i、l、o)这32个字母进行Base32编码,即对照下标将其转换为字符串。

​ h. 同理,将编码转换成经纬度的解码算法与之相反。

3.GeoHash原理

​ Geohash其实就是将整个地图或者某个分割所得的区域进行一次划分,由于采用的是base32编码方式,即Geohash中的每一个字母或者数字(如wx4g0e中的w)都是由5bits组成(2^5 = 32,base32),这5bits可以有32中不同的组合(0~31),这样我们可以将整个地图区域分为32个区域,通过00000 ~ 11111来标识这32个区域。第一次对地图划分后的情况如下图所示(每个区域中的编号对应于该区域所对应的编码))。

​ Geohash的0、1串序列是经度0、1序列和纬度0、1序列中的数字交替进行排列的,偶数位对应的序列为经度序列,奇数位对应的序列为纬度序列,在进行第一次划分时,Geohash0、1序列中的前5个bits(11100),那么这5bits中有3bits是表示经度,2bits表示纬度,所以第一次划分时,是将经度划分成8个区段(2^3 = 8),将纬度划分为4个区段(2^2 = 4),这样就形成了32个区域。如下图

​ 同理,可以按照第一次划分所采用的方式对第一次划分所得的32个区域各自再次划分。

​ 上文讲了GeoHash的计算步骤,仅仅说明是什么而没有说明为什么?为什么分别给经度和维度编码?为什么需要将经纬度两串编码交叉组合成一串编码?本节试图回答这一问题。

​ 如图所示,我们将二进制编码的结果填写到空间中,当将空间划分为四块时候,编码的顺序分别是左下角00,左上角01,右下脚10,右上角11,也就是类似于Z的曲线,当我们递归的将各个块分解成更小的子块时,编码的顺序是自相似的(分形),每一个子快也形成Z曲线,这种类型的曲线被称为Peano空间填充曲线

​ 这种类型的空间填充曲线的优点是将二维空间转换成一维曲线(事实上是分形维),对大部分而言,编码相似的距离也相近,但Peano空间填充曲线最大的缺点就是突变性,有些编码相邻但距离却相差很远,比如0111与1000,编码是相邻的,但距离相差很大。

​ 除Peano空间填充曲线外,还有很多空间填充曲线,如图所示,其中效果公认较好是Hilbert空间填充曲线,相较于Peano曲线而言,Hilbert曲线没有较大的突变。但是由于Peano曲线实现更加简单,在使用的时候配合一定的解决手段,可以很好的满足大部分需求,因此TD内部Geohash算法采用的是Peano空间填充曲线。

4.GeoHash优缺点

优点:

Geohash 的优点很明显,它利用 Z 阶曲线进行编码。而 Z 阶曲线可以将二维或者多维空间里的所有点都转换成一维曲线。在数学上成为分形维。并且 Z 阶曲线还具有局部保序性。

Z 阶曲线通过交织点的坐标值的二进制表示来简单地计算多维度中的点的z值。一旦将数据被加到该排序中,任何一维数据结构,例如二叉搜索树,B树,跳跃表或(具有低有效位被截断)哈希表 都可以用来处理数据。通过 Z 阶曲线所得到的顺序可以等同地被描述为从四叉树的深度优先遍历得到的顺序

这也是 Geohash 的另外一个优点,搜索查找邻近点比较快。

缺点:

Geohash 的缺点之一也来自 Z 阶曲线。

Z 阶曲线有一个比较严重的问题,虽然有局部保序性,但是它也有突变性。在每个 Z 字母的拐角,都有可能出现顺序的突变。

Geohash 的另外一个缺点是,如果选择不好合适的网格大小,判断邻近点可能会比较麻烦。

5.使用注意点

a. 由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处。

​ 解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。

b. 我们已经知道现有的GeoHash算法使用的是Peano空间填充曲线,这种曲线会产生突变,造成了编码虽然相似但距离可能相差很大的问题,因此在查询附近餐馆时候,首先筛选GeoHash编码相似的POI点,然后进行实际距离计算。

c. GeoHash Base32编码长度与精度。可以看出,当geohash base32编码长度为8时,精度在19米左右,而当编码长度为9时,精度在2米左右,编码长度需要根据数据情况进行选择。

6.计算围栏内所有Geohash

理解了geohash算法的基本原理之后,本节将介绍一个实际应用中常见的场景:计算围栏范围内所有的Geohash编码。该场景封装为函数可以表示如下:输入组成围栏的点经纬度坐标集合和指定的geohash长度,输出一组geohash编码。

​ public static Set getHashByFence(List points, int length)

​ 具体算法步骤如下:

  1. 输入围栏点坐标集合List points和指定的geohash长度length

  2. 计算围栏的外包矩形的左上角和右下角坐标lat_min、lat_max、lng_min、lng_max

  3. 根据lat_min、lat_max、lng_min、lng_max,计算外包矩形对角定点的距离d

  4. 以外包矩形中心点为圆心,以d/2为半径做一个圆,计算圆覆盖范围内的geohash

4.1 获取圆的外包矩形左上角和右下角定点坐标经纬度,存储到double[] locs

4.2 根据geohash字符长度计算该长度geohash编码对应的经纬度间隔(latA,lngA)

4.3 根据latA和lngA,计算出locs组成的矩形的左上角和右下角定点的经纬度,在geohash划分的网格的索引(也就是第几个),分别记为lat_min,lat_max,lng_min,lng_max

4.4 计算lat_min,lat_max,lng_min,lng_max对应范围内左右geohash的二进制编码,然后将经纬度二进制编码uncode为geohash字符编码,保存为Set sets

  1. 剔除sets中geohash编码对应矩形的中心点不在points围栏范围内的geohash,得到最终的geohash结果集

二.Redis的GEO模块

1.精度问题

reids 在3.2版本以后增加了地理位置Geo模块

GeoHash 算法会继续对这个整数做一次base32编码(09,az,去掉a、i、l、o四个字母)变成一个字符串。在Redis里面,经纬度使用52位的整数进行编码,放进了zset里面,zset的value是元素的key,score是GeoHash的52位整数值。zset的score虽然是浮点数,但是对于52位的整数值,它可以无损存储。

double类型精度为52位;
geohash是以base32(5位一个编码)的方式编码,52bits最高可存储10位geohash值,对应地理区域大小为0.6*0.6米的格子。换句话说经Redis geo转换过的位置理论上会有约0.3 *1.414=0.424米的误差。
【来源:https://python.iitter.com/other/12028.html】

Redis的double类型:

​ Redis的分数类型采用的是double,64位双精度浮点数只有52位有效数字,它能精确表达的整数范围为-253到253,最高只能表示16位十进制整数(最大值为9007199254740992,其实连16位也不能完整表示)。

数据类型的范围与精度:

1)范围

float和double的范围是由指数的位数来决定的。
float的指数位有8位,而double的指数位有11位,分布如下:

  • float:(32位,4字节)
    1bit(符号位) 8bits(指数位) 23bits(尾数位)

  • double:(64位,8字节)
    1bit(符号位) 11bits(指数位) 52bits(尾数位)

    于是,float的指数范围为-127—+128,而double的指数范围为-1023----+1024,并且指数位是按补码的形式来划分的。
    其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
    float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。

2)精度

float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。

2.Redis的Geo指令

问题

我们常见的需求是查找 n米 范围内的点,那么 n米 与 GeoHash 码位数之间的映射如何实现呢?由于 GeoHash 码是由5位二进制码组成,每少一位,精度就会损失 2e(5/2)。

方法当然有的,我们将二进制GeoHash码直接索引就可以,但很长的索引长度会导致 B树 索引查询效率会迅速下降。

方案

于是我们接着寻找解决方案,既然使用 base32 转换为 32进制码 会不好控制精度,保持二进制又导致索引长度过长,那么进制位数和索引长度有没有一个平衡呢?

另外 Redis 的 sorted set 支持 64位 的 double 类型的 score,我们把二进制的 GeoHash 码转为十进制放入 Redis 的 sorted set 中,不是可以实现 log(n)的查询效率了么。

3.Redis 的 Geo 指令基本使用

Redis 提供的 Geo 指令只有 6 个,读者们瞬间就可以掌握。使用时,读者务必再次想起,它只是一个普通的 zset 结构。

geoadd      用来增加地理位置的坐标,可以批量添加地理位置
geodist     用来获取两个地理位置的距离
geopos      可以获取地理位置的坐标,可以批量获取多个地理位置的坐标
geohash     可以获取元素的经纬度编码字符串
georadius   可以根据给定地理位置坐标获取指定范围内的地理位置集合
georadiusbymember  可以根据给定地理位置获取指定范围内的地理位置集合

增加

geoadd 指令携带集合名称以及多个经纬度名称三元组,注意这里可以加入多个三元组

127.0.0.1:6379> geoadd company 116.48105 39.996794 juejin
(integer) 1
127.0.0.1:6379> geoadd company 116.514203 39.905409 ireader
(integer) 1
127.0.0.1:6379> geoadd company 116.489033 40.007669 meituan
(integer) 1
127.0.0.1:6379> geoadd company 116.562108 39.787602 jd 116.334255 40.027400 xiaomi
(integer) 2

距离

geodist 指令可以用来计算两个元素之间的距离,携带集合名称、2 个名称和距离单位。

127.0.0.1:6379> geodist company juejin ireader km
"10.5501"
127.0.0.1:6379> geodist company juejin meituan km
"1.3878"
127.0.0.1:6379> geodist company juejin jd km
"24.2739"
127.0.0.1:6379> geodist company juejin xiaomi km
"12.9606"
127.0.0.1:6379> geodist company juejin juejin km
"0.0000"

我们可以看到掘金离美团最近,因为它们都在望京。距离单位可以是 m、km、ml、ft,分别代表米、千米、英里和尺。

获取元素位置

geopos 指令可以获取集合中任意元素的经纬度坐标,可以一次获取多个。

127.0.0.1:6379> geopos company juejin
1) 1) "116.48104995489120483"2) "39.99679348858259686"
127.0.0.1:6379> geopos company ireader
1) 1) "116.5142020583152771"2) "39.90540918662494363"
127.0.0.1:6379> geopos company juejin ireader
1) 1) "116.48104995489120483"2) "39.99679348858259686"
2) 1) "116.5142020583152771"2) "39.90540918662494363"

我们观察到获取的经纬度坐标和 geoadd 进去的坐标有轻微的误差,原因是 geohash 对二维坐标进行的一维映射是有损的,通过映射再还原回来的值会出现较小的差别。对于「附近的人」这种功能来说,这点误差根本不是事。

获取元素的 hash 值

geohash 可以获取元素的经纬度编码字符串,上面已经提到,它是 base32 编码。 你可以使用这个编码值去 http://geohash.org/${hash}中进行直接定位,它是 geohash 的标准编码值。

127.0.0.1:6379> geohash company ireader
1) "wx4g52e1ce0"
127.0.0.1:6379> geohash company juejin
1) "wx4gd94yjn0"

附近的公司

georadiusbymember 指令是最为关键的指令,它可以用来查询指定元素附近的其它元
素,它的参数非常复杂。

# 范围 20 公里以内最多 3 个元素按距离正排,它不会排除自身
127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 asc
1) "ireader"
2) "juejin"
3) "meituan"
# 范围 20 公里以内最多 3 个元素按距离倒排
127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 desc
1) "jd"
2) "meituan"
3) "juejin"
# 三个可选参数 withcoord withdist withhash 用来携带附加参数
# withdist 很有用,它可以用来显示距离
127.0.0.1:6379> georadiusbymember company ireader 20 km withcoord withdist withhash count 3 asc
1) 1) "ireader"2) "0.0000"3) (integer) 40698860083613984) 1) "116.5142020583152771"2) "39.90540918662494363"
2) 1) "juejin"2) "10.5501"3) (integer) 40698871543881674) 1) "116.48104995489120483"2) "39.99679348858259686"
3) 1) "meituan"2) "11.5748"3) (integer) 40698871790834784) 1) "116.48903220891952515"2) "40.00766997707732031"

除了 georadiusbymember 指令根据元素查询附近的元素,Redis 还提供了根据坐标值来查询附近的元素,这个指令更加有用,它可以根据用户的定位来计算「附近的车」,「附近的餐馆」等。它的参数和 georadiusbymember 基本一致,除了将目标元素改成经纬度坐标值。

127.0.0.1:6379> georadius company 116.514202 39.905409 20 km withdist count 3 asc
1) 1) "ireader"2) "0.0000"
2) 1) "juejin"2) "10.5501"
3) 1) "meituan"2) "11.5748"

小结 & 注意事项

在一个地图应用中,车的数据、餐馆的数据、人的数据可能会有百万千万条,如果使用Redis 的 Geo 数据结构,它们将全部放在一个 zset 集合中。在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。

所以,这里建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。

如果数据量过亿甚至更大,就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 zset 集合的大小。

三、python使用Redis的Geo模块

#redis.Redis.******pool = redis.ConnectionPool(host='10.3.*.*', port=6379,password='123456', decode_responses=True)   # 连接redis
redis_connect = redis.Redis(connection_pool=pool)
redis_connect.geoadd()
 Methods inherited from redis.commands.core.GeoCommands:### 1.添加元素,geohash编码   将指定的地理空间项添加到由“`name``参数标识的指定键。地理空间项目作为``values``参数的 有序 成员提供,每个项目或位置由空间坐标轴经度、纬度和名称组成。values是有序的。-------# values的参数依次是经度、元素名、纬度geoadd(self, name, values, nx=False, xx=False, ch=False)Add the specified geospatial items to the specified key identifiedby the ``name`` argument. The Geospatial items are given as orderedmembers of the ``values`` argument, each item or place is formed bythe triad longitude, latitude and name.# 提示:可以使用ZREM删除元素,其本质是使用zset存储Note: You can use ZREM to remove elements.# nx=True时只创建新元素,不会更新现有元素的值。正常默认为false,会更新现有元素的值``nx`` forces ZADD to only create new elements and not to updatescores for elements that already exist.# xx=true时强制只会更新现有元素的score,不会创建新的元素。正常默认为true,可以正常创建元素``xx`` forces ZADD to only update scores of elements that alreadyexist. New elements will not be added.# ch=true时会将返回值修改为更改的元素数量。更改的元素包括添加的新元素和score更改的元素。``ch`` modifies the return value to be the numbers of elements changed.Changed elements include new elements that were added and elementswhose scores changed.For more information check https://redis.io/commands/geoadd# 2.返回``name``键的``place1``和``place2``成员之间的距离。unit必须是以下单位之一: m, km mi, ft。默认情况下使用m。geodist(self, name, place1, place2, unit=None)Return the distance between ``place1`` and ``place2`` members of the``name`` key.The units must be one of the following : m, km mi, ft. By defaultmeters are used.For more information check https://redis.io/commands/geodist# 3.返回由``name``参数标识的指定键的``values``成员的每个项的geohash字符串。geohash(self, name, *values)Return the geo hash string for each item of ``values`` members ofthe specified key identified by the ``name`` argument.For more information check https://redis.io/commands/geohash# 4.返回每个``values``项的位置,作为``name``参数标识的指定键的成员。每个位置由lon和lat对表示。  geopos(self, name, *values)Return the positions of each item of ``values`` as members ofthe specified key identified by the ``name`` argument. Each positionis represented by the pairs lon and lat.For more information check https://redis.io/commands/geopos### 5.返回由``name``参数标识的指定键的成员,这些成员位于由``纬度``和``经度``位置指定的区域的边界内,并且距离由``半径``值指定的中心的最大距离。-----返回在以(lon,lat)为中心的,以radis为半径的范围内的value元素georadius(self, name, longitude, latitude, radius, unit=None, withdist=False, withcoord=False, withhash=False, count=None, sort=None, store=None, store_dist=None, any=False)Return the members of the specified key identified by the``name`` argument which are within the borders of the area specifiedwith the ``latitude`` and ``longitude`` location and the maximumdistance from the center specified by the ``radius`` value.# 单位可以是m, km mi, ft,默认是mThe units must be one of the following : m, km mi, ft. By default# withdist=true表示返回每个位置的距离,默认为false,不返回。``withdist`` indicates to return the distances of each place.# withcoord=true表示返回每个地方的纬度和经度,默认为false,不返回。``withcoord`` indicates to return the latitude and longitude ofeach place.# withhash=true表示返回每个位置的geohash字符串,默认为false,不返回。``withhash`` indicates to return the geohash string of each place.# count=N表示返回不超过N的元素数,默认不限制个数``count`` indicates to return the number of elements up to N.### sort表示按排序方式返回位置,sort=ASC表示最近到最远,sort=DESC表示最远到最近。``sort`` indicates to return the places in a sorted way, ASC fornearest to fairest and DESC for fairest to nearest.# store表示要将地名保存在以特定键命名的排序集中,目标排序集中的每个元素都将填充从原始地理排序集中获得的score。``store`` indicates to save the places names in a sorted set namedwith a specific key, each element of the destination sorted set ispopulated with the score got from the original geo sorted set.# store_dist表示将地名(value)元素保存在用特定键命名的排序集中,而不是``store``排序集,目的地分数是用距离设置的。``store_dist`` indicates to save the places names in a sorted setnamed with a specific key, instead of ``store`` the sorted setdestination score is set with the distance.For more information check https://redis.io/commands/georadius### 6.此命令与“georadius”完全相同,唯一的区别是,它不以经度和纬度值作为要查询的区域的中心,而是采用已排序集表示的地理空间索引中已存在的成员的名称。---以value元素作为中心georadiusbymember(self, name, member, radius, unit=None, withdist=False, withcoord=False, withhash=False, count=None, sort=None, store=None, store_dist=None, any=False)This command is exactly like ``georadius`` with the sole differencethat instead of taking, as the center of the area to query, a longitudeand latitude value, it takes the name of a member already existinginside the geospatial index represented by the sorted set.For more information check https://redis.io/commands/georadiusbymember###### 7. 返回由``name``参数标识的指定键的成员,这些成员位于给定形状指定区域的边界内。此命令扩展了GEORADIUS命令,因此除了在圆形区域内搜索外,它还支持在矩形区域内搜索。应使用此命令代替不推荐使用的GEORADIUS和GEORADIUSBYMEMBER命令。--------------支持在矩形区域内搜索geosearch(self, name, member=None, longitude=None, latitude=None, unit='m', radius=None, width=None, height=None, sort=None, count=None, any=False, withcoord=False, withdist=False, withhash=False)Return the members of specified key identified by the``name`` argument, which are within the borders of thearea specified by a given shape. This command extends theGEORADIUS command, so in addition to searching within circularareas, it supports searching within rectangular areas.This command should be used in place of the deprecatedGEORADIUS and GEORADIUSBYMEMBER commands.# member使用集合中现存元素的位置??作为中心,不能与``longitude`` and ``latitude`` 参数同时使用``member`` Use the position of the given existingmember in the sorted set. Can't be given with ``longitude``and ``latitude``.# ``longitude`` and ``latitude``指定经纬度作为中心 ,不能与member参数同时使用``longitude`` and ``latitude`` Use the position given bythis coordinates. Can't be given with ``member``# radius指定圆形区域的半径,不能与``height`` and ``width``参数同时使用``radius`` Similar to GEORADIUS, search inside circulararea according the given radius. Can't be given with``height`` and ``width``.# ``height`` and ``width``在轴对齐的矩形内搜索,由给定的高度和宽度确定。不能与radius参数同时使用``height`` and ``width`` Search inside an axis-alignedrectangle, determined by the given height and width.Can't be given with ``radius``# unit单位必须是一下m, km, mi, ft.``unit`` must be one of the following : m, km, mi, ft.`m` for meters (the default value), `km` for kilometers,`mi` for miles and `ft` for feet.# sort表示以一种排序的方式返回元素,sort=ASC代表从最近到最远,sort=DESC代表从最远到最近``sort`` indicates to return the places in a sorted way,ASC for nearest to farest and DESC for farest to nearest.# `count``将结果限制为匹配项的第一个计数。 ``count`` limit the results to the first count matching items.# ``如果将any``设置为True,则只要找到足够的匹配项(count计数),命令就会返回。没有count参数就无法使用``any`` is set to True, the command will return as soon asenough matches are found. Can't be provided without ``count``# ``withdist=true``表示返回每个位置的距离。``withdist`` indicates to return the distances of each place.# ``withcoord=true``指示返回每个地方的纬度和经度。``withcoord`` indicates to return the latitude and longitude ofeach place.# ``withhash`` 表示返回每个地方的hash编码``withhash`` indicates to return the geohash string of each place.For more information check https://redis.io/commands/geosearch# 8. 此命令类似于GEOSEARCH,但将结果存储在“dest”中。默认情况下,它将结果与其地理空间信息一起存储在目标排序集中。如果``store_dist``设置为True,则该命令将存储已排序集合中的项目,以浮点数的形式填充到圆或方框中心的距离。----将排序结果存储在dest集合中geosearchstore(self, dest, name, member=None, longitude=None, latitude=None, unit='m', radius=None, width=None, height=None, sort=None, count=None, any=False, storedist=False)This command is like GEOSEARCH, but stores the result in``dest``. By default, it stores the results in the destinationsorted set with their geospatial information.if ``store_dist`` set to True, the command will stores theitems in a sorted set populated with their distance from thecenter of the circle or box, as a floating-point number.For more information check https://redis.io/commands/geosearchstore

四、Python的geohash编码包

安装:

方式一:不推荐!!Geohash-1.0
(odc) [mca@clu01 ~]$ pip install geohash# 存在问题
(odc) [mca@clu01 ~]$ python
Python 3.8.12   packaged by conda-forge   (default, Oct 12 2021, 21:59:51)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import geohash
Traceback (most recent call last):File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'geohash'

解决问题:

(odc) [mca@clu01 miniconda3]$ find . -name "Geohash"
(odc) [mca@clu01 miniconda3]$ cd envs/odc/lib/python3.8/site-packages/Geohash
(odc) [mca@clu01 Geohash]$ ll
total 8
-rw-rw-r--. 1 mca mca 4021 Jan 17 21:14 geohash.py
-rw-rw-r--. 1 mca mca  839 Jan 17 21:14 __init__.py
drwxrwxr-x. 2 mca mca   67 Jan 17 21:14 __pycache__
(odc) [mca@clu01 Geohash]$ cd ..
(odc) [mca@clu01 site-packages]$ mv Geohash geohash
(odc) [mca@clu01 site-packages]$ cd geohash/
(odc) [mca@clu01 geohash]$ vim __init__.py # 把from geohash import ****修改为 from .geohash

Python 3.5 安装geohash库后import geohash失败 - 海盗Ora - 博客园 (cnblogs.com)

vinsci/geohash: Python module to decode/encode Geohashes to/from latitude and longitude. See http://en.wikipedia.org/wiki/Geohash (github.com)

方式二:python-geohash

可以避免方案一种存在的bug

(odc) [mca@clu01 ~]$ pip install python-geohash

方法:

FUNCTIONS
# 1.解码,将geohash编码解码成经纬度decode(geohash)Decode geohash, returning two strings with latitude and longitudecontaining only relevant digits and with trailing zeroes removed.# 2.精确解码,将geohash解码为其精确值,包括结果的误差范围。返回四个浮点值:纬度、经度、纬度的正负误差(正数)和经度的正负误差(正数)。decode_exactly(geohash)Decode the geohash to its exact values, including the errormargins of the result.  Returns four float values: latitude,longitude, the plus/minus error for latitude (as a positivenumber) and the plus/minus error for longitude (as a positivenumber).# 3.编码,将经纬度编码成geohash编码,可以指定编码位数(与精度有关)encode(latitude, longitude, precision=12)Encode a position given in float arguments latitude, longitude toa geohash which will have the character count precision.# 返回x的以10为底的对数。log10(x, /)Return the base 10 logarithm of x.
方式三:安装mzgeohash
(odc) [mca@clu01 ~]$ pip install mz2geohash

遇到问题的解决方式如下:

(41条消息) Python 安装mzgeohash包失败,包名冲突_Nougats的博客-CSDN博客

方式四:安装mz2geohash
(odc) [mca@clu01 ~]$ pip install mz2geohash

方法:

FUNCTIONS
# 1.返回给定方向的相邻geohashadjacent(geohash, direction)Return the adjacent geohash for a given direction.# 2.解码geohash。返回(lon,lat)对。decode(value)Decode a geohash. Returns a (lon,lat) pair.# 3.将(lon,lat)对编码为GeoHash。encode(lonlat, length=12)Encode a (lon,lat) pair to a GeoHash.# 4.返回所有的邻居geohash编码neighbors(geohash)Return all neighboring geohashes.#   neighborsfit(centroid, points)

实例:

>>> import mz2geohash
>>> mz2geohash.decode('xn76urwe1g9y')
(139.76608408614993, 35.681382017210126)
>>> mz2geohash.encode((139.76608408614993, 35.681382017210126))
'xn76urwe1g9y'
>>> mz2geohash.neighbors('xn76urwe1g9y')
{'c': 'xn76urwe1g9y','e': 'xn76urwe1gdn','n': 'xn76urwe1g9z','ne': 'xn76urwe1gdp','nw': 'xn76urwe1g9x','s': 'xn76urwe1g9v','se': 'xn76urwe1gdj','sw': 'xn76urwe1g9t','w': 'xn76urwe1g9w'}

https://github.com/jason-h-35/mapzen-geohash

Geohash的原理介绍、Redis的Geo命令总结、Python使用Redis的Geo模块相关推荐

  1. linux redis 查看启动命令,linux怎么启动redis

    1.首先为了方便管理,将Redis文件中的conf配置文件和常用命令移动到统一文件中. (1)创建bin和redis.conf文件,"mkdir -p/usr/local/redis/bin ...

  2. python redis list操作_使用Python操作redis

    在使用python操作redis之前,需要先安装redis库: pip install redis. 创建连接方式: StrictRedis:实现大部分官方命令. Redis:是StrictRedis ...

  3. redis 自减命令_Redis 实战 —— 04. Redis 数据结构常用命令简介

    字符串 P39 Redis 的字符串是一个有字节组成的序列,可以存储以下 3 种类型的值:字节串(byte string).整数.浮点数. 在需要的时候, Redis 会将整数转换成浮点数.整数的取值 ...

  4. redis连接相关命令

    redis日常连接命令是用客户端时候用的比较多的命令,下面来介绍一下reids连接相关的命令. 命令 1.auth命令-验证密码是否正确. redis中auth命令用于检测给定的密码和配置文件中的密码 ...

  5. redis的flushall命令

    redis的flushall命令用来清空redis所有的库,我们平时本地调试redis时都是直接flushall,但到生产环境要注意了,其他的库有可能有生产数据,你要清空redis数据,只能清空你对应 ...

  6. redis常用监控命令

    redis常用监控命令 1.实时监控redis服务收到来自应用的所有命令 1 2 3 4 5 6 7 redis-cli 127.0.0.1:6379>monitor 1509964152.13 ...

  7. REDIS 批量删除命令说明

    REDIS 批量删除命令说明 1.访问redis根目录    cd  /usr/local/redis-2.8.19 2.登录redis:redis-cli -h 127.0.0.1 -p 6379 ...

  8. python 操作redis 队列 使用lrange 命令 返回类型格式类型 坑坑坑!!!

    偶然间发现 在使用python 操作队列时   使用rpop 和 lindex 命令时,存储的队列数据为json ,打印时,类型为str字符串类型  但使用lrange 命令取队列数据时,返回的为列表 ...

  9. 【机器学习】逻辑回归原理介绍

    [机器学习]逻辑回归原理介绍 [机器学习]逻辑回归python实现 [机器学习]逻辑回归sklearn实现 Logistic 回归模型是目前广泛使用的学习算法之一,通常用来解决二分类问题,虽然名字中有 ...

最新文章

  1. [umeditor] 多图片一次上传功能
  2. 【sparkStreaming】将DStream保存在MySQL
  3. oracle中字典指的是什么,ORACLE数据库中什么是数据字典及作用
  4. 要闻君说:IBM最新量子计算机真真像个艺术品!鹅厂正式成立了自己的技术委员会哇!联想竟然也试着做了一款智能闹钟?...
  5. Redhat linux 5.3 基于bond的heartbeat
  6. Charles笔记-配置Charles代理抓取HTTP和HTTPS数据包,安卓模拟器连接Charles
  7. 【redis系列】redisTemplate缓存常用工具类
  8. .Net中使用OracleDataAdapter
  9. 操作 Wave 文件(5): 获取 Wave 文件的格式信息
  10. 6.凤凰架构:构建可靠的大型分布式系统 --- 分布式共识
  11. php 查询条件 session,PHP获取不到SESSION信息之一般情况解决方案
  12. java 模拟百度翻译
  13. word文档保护密码忘 了,怎么取消格式和编辑保护
  14. python爬取豆瓣TOP250
  15. 华为服务器故障灯不开机_华为手机开不了机指示灯亮,怎么办
  16. 38.DevOps之基于Jenkins实现的CI与CD
  17. 螺栓校核matlab仿真
  18. 必知C++算法之排列组合基本操作
  19. 阿龙学堂-算法-逻辑回归
  20. 【高老师软件需求分析】20级云班课习题答案合集

热门文章

  1. vs studio2019解决下载慢的问题
  2. 怎么把txt转为html,怎么把TXT转化为HTML格式?
  3. 兰石化计算机专业分数线,兰州石化职业技术学院录取分数线是多少
  4. mongodb未授权漏洞
  5. 环网冗余式CAN/光纤转换器 CAN总线转光纤转换器中继集线器hub光端机
  6. PyTorch处理多维特征的输入
  7. 步步高向腾讯、京东转让股份,共同发展“智慧零售”、“无界零售”
  8. dmbackup和dmrestore使用脱机工具进行备份还原
  9. 阿里巴巴2021年数字IC-笔试题
  10. Qt中主页面跳转下一页面下一页面跳回主页面相关操作