dot Redis 8 来了——而且是开源的

了解更多

使用 Redis 和地理空间数据追踪大脚怪

我认为 Redis 最酷的功能之一——当我发现它时让我感到惊讶——是地理空间数据结构。既然我认为它很酷,我想你们也会这么认为。所以,我将与你们分享它。

Redis 的地理空间数据结构使用起来相当简单,但也有一些有趣的细节。我们将涵盖这两者。而且,因为我不写一个带有有趣主题的博客文章就无法完成,所以这次我将使用我最喜欢的数据集:大脚怪目击事件

大脚怪数据集

大脚怪数据集有很多很棒的东西。每一行都是对大脚怪目击事件的描述,包括该事件的完整文本、发生时间,甚至还有一个分类。分类是我最喜欢的部分,尽管这些描述也很有趣!

这与我们今天所做的事情无关——我分享这个只是为了好玩——但这是大脚怪目击事件的三个类别

  • A 类:我看到了大脚怪。
  • B 类:我发现了大脚怪的证据,例如脚印或一些毛皮。
  • C 类:有人告诉我他们看到了大脚怪。

今天,我们将只使用大脚怪目击事件的经度、纬度和报告编号。如果您想加载数据并一起玩,我创建了一个存储库,其中包含数据、转换代码以及运行说明。当然,您还需要安装 Redis。

简单直接的部分

Geo Set 是在 Redis 中使用地理空间数据的关键数据结构。它包含一个命名的地球位置集合。向此集合添加和更新成员很容易。只需使用GEOADD命令:

> GEOADD bigfoot:sightings:locations -89.15173 37.61335 report:40120

此命令要求 Redis 将名为report:40120的成员添加到 Geo Set bigfoot:sightings:locations,其经度为-89.15173,纬度为37.61335。如果该成员不存在,则会插入它。如果存在,其位置将被更新。

注意:这种类型的操作称为“upsert”——更新和插入的混合词——是 Redis 中一种流行的模式。您会反复看到的另一种模式是可变参数命令——接受可变数量参数的命令。

GEOADD是一个可变参数命令,因为您也可以更新多个成员。像这样

> GEOADD bigfoot:sightings:locations -89.15173 37.61335 report:40120
-88.55 41.33 report:12140

注意:经度和纬度以该顺序呈现在命令中。经度——然后是纬度。如果您像很多人一样,您的直觉是先输入纬度。这很容易出错。注意它。

很好。我们已经更新了伊利诺伊州南部和芝加哥西部的大脚怪目击事件。如果您在家玩,可以使用以下命令查找它们

> HGETALL bigfoot:sightings:report:40120
> HGETALL bigfoot:sightings:report:12140

您也可以从大脚怪野外研究人员组织网站上的原始来源查找它们。没有办法按报告编号查找它们,但它是链接的一部分,所以您可能会弄清楚。

无论如何,这涵盖了创建和更新。但是读取和查询呢?有几种方法可以做到这一点。如果您只想提取坐标,可以使用GEOPOS命令:

> GEOPOS bigfoot:sightings:locations report:40120

您也可以可变参数地查询成员

> GEOPOS bigfoot:sightings:locations report:40120 report:12140

这将返回坐标,其精度可能比输入时更高。这是它们存储方式的产物,我们稍后会讨论它

1) 1) "-89.15173262357711792"
   2) "37.61334955747530984"
2) 1) "-88.55000048875808716"
   2) "41.330001054529383"

再次注意,返回的两组坐标是先经度,然后是纬度。

您可能想要做一些更复杂的事情。也许您想确定两次大脚怪目击事件之间的距离。您可以使用GEODIST命令找到答案:

> GEODIST bigfoot:sightings:locations report:40120 report:12140

只需将一个键和两个成员交给GEODIST,它会告诉您它们之间的距离,以米为单位。如果您对米不感兴趣,而更喜欢公里或自由单位(即英尺和英里),您只需在命令末尾指定您想要的单位

> GEODIST bigfoot:sightings:locations report:40120 report:12140 m
> GEODIST bigfoot:sightings:locations report:40120 report:12140 km
> GEODIST bigfoot:sightings:locations report:40120 report:12140 ft
> GEODIST bigfoot:sightings:locations report:40120 report:12140 mi

这两次目击事件相距约 260 英里。

您还可以在特定点周围的半径内找到 Geo Set 的成员。该点可以是坐标对,也可以是Geo Set 的另一个成员。俄亥俄州东南部实际上是大脚怪目击事件的热点地区。让我们看看在雅典(该州该地区最大的城市)附近有多少目击事件:

> GEORADIUS bigfoot:sightings:locations -82.109149 39.319950 25 mi

相当多

1) "report:4982"
2) "report:9042"
...省略...
15) "report:8017"
16) "report:10945"

这是相同的命令,但使用成员而不是坐标

> GEORADIUSBYMEMBER bigfoot:sightings:locations report:9042 25 mi

您还可以通过在末尾添加WITHCOORD和/或WITHDIST来请求有关这些位置的额外信息

> GEORADIUS bigfoot:sightings:locations -82.109149 39.319950 25 mi WITHCOORD WITHDIST

1) 1) "report:4982"
   2) "16.2549"
   3) 1) "-82.3997005820274353"
      2) "39.25109119711087402"
   ...snip...
16) 1) "report:10945"
    2) "24.7297"
    3) 1) "-81.85806065797805786"
       2) "39.01971931496525059"

所以这就是GEOADDGEOPOSGEODISTGEORADIUSGEORADIUSBYMEMBER。这些命令允许您在 Redis 中创建、读取和更新地理空间数据。但是,您可能会注意到我只谈到了 CRUD 的四个方面中的三个。删除成员的 GEO-something-or-other 命令在哪里?嗯,这是第一个有趣的地方。

删除在哪里?

所以在我们谈论删除之前,我们需要谈谈地理哈希。地理哈希是一种巧妙地将坐标存储在单个整数中,然后将其表示为 base-32 编码字符串的方法。

地理哈希通过不断细分地球,一次存储一个坐标位。第一次分割沿着本初子午线将地球分为两半。如果位置在西半球,则最高有效位为 0;如果在东半球,则为 1。下一位沿着南北半球分割。北方为 1,南方为 0。您不断像这样分割,先是东西方向,然后是南北方向,并不断添加位,直到达到您满意的分辨率。然后,您对这些位进行编码。

Redis 可以使用 GEOHASH 命令为您执行此操作。它的工作方式与 GEOPOS 类似,但它返回的是地理哈希,而不是坐标。当然,它是可变参数的。

> GEOHASH bigfoot:sightings:locations report:40120 report:12140
1) "dn8tgr39wh0"
2) "dp350gzueq0"

这些是 base-32 编码的数字。这意味着地理集合可以表示为具有数值的集合。Redis 有一种这样的数据类型:有序集合。而这正是 Redis 实现地理集合的方式。

在幕后,地理集合是有序集合。有序集合中的数字是一个 64 位浮点数。代表地理哈希的整数存储在该浮点数中,并且可以安全地不大于 52 位整数(这已经足够了)。当您调用 GEOHASH 时,Redis 获取该数字并进行 base-32 编码。当您调用 GEOPOS 时,Redis 获取该数字并将其转换为坐标,这就是为什么您输入的坐标与您获得的坐标不完全相同的原因。 

由于地理集合是有序集合,因此所有的有序集合命令都适用于地理集合——尽管有些命令有一些注意事项。例如,想要获取地理哈希的底层整数吗?

> ZSCORE bigfoot:sightings:locations report:40120
"1781261397121617"

想要获取所有成员吗?

> ZRANGE bigfoot:sightings:locations 0 -1
1) "report:8059"
2) "report:4886"
3) "report:1031"
...省略...

实际上,不要这样做。请改用ZSCAN

> ZSCAN bigfoot:sightings:locations 0 COUNT 5

那么,如何删除成员呢?使用ZREM

> ZREM bigfoot:sightings:locations report:40120 report:12140

现在,当您去获取它们时,它们已经消失了

> GEOPOS bigfoot:sightings:locations report:40120 report:12140
1) (nil)
2) (nil)

结束寻找大脚怪

这几乎是您能对地理集合做的所有事情。但这当然不是您能利用地理集合做的所有事情。地理空间数据有很多应用。除了有点异想天开的跟踪大脚怪之外,您还可以将地理空间数据与 Pub/Sub 结合起来,以实时跟踪您想要的任何事物——无论是移动应用程序的用户、车队中的卡车,还是环境研究中的非神秘动物。