redis3.2新功能--GEO地理位置命令介绍

1、概述

redis3.2发布rc版本已经有一段时间了,估计RedisConf 2016左右,3.2版本就能release了。3.2版本中增长的最大功能就是对GEO(地理位置)的支持。提及redis的GEO特性,最大的贡献仍是我们中国人。redis做者在对3.2引进新特性的博客中介绍了为何支持GEO。GEO hashing的api是在Ardb实现的,Ardb是github用户yinqiwen实现的基于redis协议实现的nosql系统,Ardb支持除了redis、还有LevelDB、RocksDB
、LMDB等kv引擎。其中Ardb实现了GEO hashing功能。从Ardb做者的用户名和标识的位置在深圳能够看出Ardb做者应该是咱中国人。Ardb是用c++写的。redis另外一个开发者Matt Stancliff从Ardb提取GEO库,用C语言改写,整合进redis的一个本身的分支,并被redis做者接受,合并进了3.2版本。GEO目前提供如下6个命令。html

  • geoadd:增长某个地理位置的坐标。
  • geopos:获取某个地理位置的坐标。
  • geodist:获取两个地理位置的距离。
  • georadius:根据给定地理位置坐标获取指定范围内的地理位置集合。
  • georadiusbymember:根据给定地理位置获取指定范围内的地理位置集合。
  • geohash:获取某个地理位置的geohash值。

地理位置的坐标是以WGS84为标准,WGS84,全称World Geodetic System 1984,是为GPS全球定位系统使用而创建的坐标系统。c++

2、GEO命令

下面来看看具体每一个命令的用法。git

2.1  GEOADD

geoadd用来增长地理位置的坐标,能够批量添加地理位置,命令格式为:github

GEOADD key longitude latitude member [longitude latitude member ...]

key标识一个地理位置的集合。longitude latitude member标识了一个地理位置的坐标。longitude是地理位置的经度,latitude是地理位置的纬度。member是该地理位置的名称。GEOADD能够批量给集合添加一批地理位置。redis

2.2  GEOPOS

geopos能够获取地理位置的坐标,能够批量获取多个地理位置的坐标,命令格式为:算法

GEOPOS key member [member ...]

2.3  GEODIST

geodist用来获取两个地理位置的距离,命令格式为:sql

GEODIST key member1 member2 [m|km|ft|mi]

单位能够指定为如下四种类型:api

  • m:米,距离单位默认为米,不传递该参数则单位为米。
  • km:千米。
  • mi:英里。
  • ft:英尺。

2.4  GEORADIUS

georadius能够根据给定地理位置坐标获取指定范围内的地理位置集合。命令格式为:框架

GEORADIUS key longitude latitude radius [m|km|ft|mi] [WITHCOORD] [WITHDIST] [ASC|DESC] [WITHHASH] [COUNT count]

longitude latitude标识了地理位置的坐标,radius表示范围距离,距离单位能够为m|km|ft|mi,还有一些可选参数:nosql

  • WITHCOORD:传入WITHCOORD参数,则返回结果会带上匹配位置的经纬度。
  • WITHDIST:传入WITHDIST参数,则返回结果会带上匹配位置与给定地理位置的距离。
  • ASC|DESC:默认结果是未排序的,传入ASC为从近到远排序,传入DESC为从远到近排序。
  • WITHHASH:传入WITHHASH参数,则返回结果会带上匹配位置的hash值。
  • COUNT count:传入COUNT参数,能够返回指定数量的结果。

2.5  GEORADIUSBYMEMBER

georadiusbymember能够根据给定地理位置获取指定范围内的地理位置集合。georadius命令传递的是坐标,georadiusbymember传递的是地理位置。georadius更为灵活,能够获取任何坐标点范围内的地理位置。可是大多数时候,只是想获取某个地理位置附近的其余地理位置,使用georadiusbymember则更为方便。georadiusbymember命令格式为(命令可选参数与georadius含义同样):

GEORADIUSBYMEMBER key member radius [m|km|ft|mi] [WITHCOORD] [WITHDIST] [ASC|DESC] [WITHHASH] [COUNT count]

2.6  GEOHASH

geohash能够获取某个地理位置的geohash值。geohash是将二维的经纬度转换成字符串hash值的算法,后面会具体介绍geohash原理。能够批量获取多个地理位置的geohash值。命令格式为:

GEOHASH key member [member ...]

3、redis GEO实现

redis GEO实现主要包含了如下两项技术:

  • 一、使用geohash保存地理位置的坐标。
  • 二、使用有序集合(zset)保存地理位置的集合。

3.1  GEOHASH

geohash的思想是将二维的经纬度转换成一维的字符串,geohash有如下三个特色:

  • 一、字符串越长,表示的范围越精确。编码长度为8时,精度在19米左右,而当编码长度为9时,精度在2米左右。
  • 二、字符串类似的表示距离相近,利用字符串的前缀匹配,能够查询附近的地理位置。这样就实现了快速查询某个坐标附近的地理位置。
  • 三、geohash计算的字符串,能够反向解码出原来的经纬度。

这三个特性让geohash特别适合表示二维hash值。这篇文章:GeoHash核心原理解析详细的介绍了geohash的原理,想要了解geohash实现的朋友能够参考这篇文章。

3.2  redis GEO命令实现

知道了redis使用有序集合(zset)保存地理位置数据(想了解redis有序集合的,能够参看这篇文章《有序集合对象》),以及geohash的特性,就很容易理解redis是如何实现redis GEO命令了。细心的读者可能发现,redis没有实现地理位置的删除命令。不过因为GEO数据保存在zset中,能够用zrem来删除某个地理位置。

  • geoadd命令增长地理位置的时候,会先计算地理位置坐标的geohash值,而后地理位置做为有序集合的member,geohash做为该member的score。而后使用zadd命令插入到有序集合。
  • geopos命令则先根据地理位置获取geohash值,而后decode获得地理位置的坐标。
  • geodist命令先根据两个地理位置各自获得坐标,而后计算两个坐标的距离。
  • georadius和georadiusbymember使用相同的实现,georadiusbymember多了一步把地理位置转换成对应的坐标。而后查找该坐标和周围对应8个坐标符合距离要求的地理位置。由于geohash获得的值实际上是个格子,并非点,这样经过计算周围对应8个坐标就能解决边缘问题。因为使用有序集合保存地理位置,在对地列位置基于范围查询,就至关于实现了zrange命令,内部的实现确实与zrange命令一致,只是geo有些特别的处理,好比得到的某个地理位置,还须要计算该地理位置是否符合给定的距离访问。
  • geohash则直接返回了地理位置的geohash值。

redis关于geohash使用了Ardb的geohash库geohash-int,redis使用的geohash编码长度为26位。能够精确到0.59m的精度。

4、总结

经过本文,拨开GEO身后的云雾,能够看出redis借助了有序集合(zset)和geohash,加上redis自己实现的命令框架,能够很容易的实现地理位置相关的命令。

相关文章
相关标签/搜索