database-design - 使用Redis的地理程序设计建议

标签 database-design redis geolocation geospatial nosql

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

11 个月前关闭。




Improve this question




我正在学习 Redis 并正在构建一个用于学习目的的地理程序。我只想使用 Redis 来存储数据,并试图避免使用任何关系数据库。我的问题是如何最好地设计程序的数据库。这是程序的运行方式:

1) 我将在世界各地创建数百万个随机漫游的机器人,这样它们就可以有不同的地理坐标(有些机器人可以在完全相同的空间中)。

2)每个机器人将随机向服务器发送一个帖子(可能平均每隔几个小时),其中包含:
a) 机器人发送数据的位置(坐标或 geohash 取决于最佳实现思路)
b) 一些小文字

3)我将有一张包含所有机器人的 map ,并希望能够点击一个机器人并获取以下信息:
a) 在我刚刚点击的机器人附近发布的所有帖子

4)由于我将在 AWS 上托管它,我需要每隔几个小时删除一次帖子以保持较低的内存使用率,因此某种类型的到期是强制性的。

我主要关心的是性能,我对如何设计 Redis 数据库感兴趣。

在一天之内(我将计算出随机帖子的数学方法)大约会生成约 500,000,000 个帖子。

到目前为止我不完整的想法:

想法1

1)帖子将被存储为:

`HSET [Geohash of location] [timestamp] [small text] (<-- the value will be used in a later feature to increment the number of manual modification I make to a post).

2)然后我将能够通过发送他所在的 geohash 位置来获取机器人附近的所有帖子。这里的失败是我还需要包括他的 8 个 geohash 邻居,这将需要 8 个更多的查询。这就是为什么我也在研究此功能的空间邻近度概念。
HGETALL [GeoHash Location of robot] 

这将返回字段([时间戳])和值(“0”);

3) 旧职位到期。由于我无法使用 EXPIRE 命令从哈希集中删除字段,因此我需要定期扫描所有哈希集字段并找到旧时间戳并将其删除。由于 Redis 仅允许模式搜索,因此当所有时间戳都不同时,这可能会很困难。

想法2:

使用 Redis-geo ( https://matt.sh/redis-geo )。

1)要存储我将运行的帖子:
geoadd globalSet [posts_long] [posts_lat] "small text";

2) 获取附近机器人的所有帖子信息:
georadius globalSet [robots_long] [robots_lat] [X] km

这将返回 X 公里内机器人附近的所有帖子。

3)然后我现在被困如何删除旧帖子

最佳答案

好的,让我们分开我们的任务:

  • 我们需要一个包含所有机器人的索引,这样我们就可以遍历它们
  • 可能我们需要存储一些关于我们机器人的通用信息
  • 我们需要为每个机器人存储地理历史
  • 我们需要每 X 次清理旧数据

  • 1 ) 让 ZSET 包含机器人 ID,他的 SCORE 将是最后一个事件时间戳,将来我们将能够使用此索引删除非事件机器人。ZADD ZSET:ROBOTS <timestamp> robot:17或者事件更好,只是没有 17robot: 因为 redis 会将整数存储为 4 个字节在 RAM 中。
    2 ) 让我们在 HSET 中存储我们的机器人通用信息HSET HSET:ROBOT:17 name "Best robot ever #17" model "Terminator T-800" 3 ) 通常我们可以使用几种方式来存储它,例如我们可以使用多维索引技术( Multi dimensional indexes ) 取常规ZSET,但是理解起来非常复杂,所以让我们使用更简单的redis GEO
          GEOADD GEO:ROBOT:17 13.361389 38.115556 "<timestamp>:<message-data>"
    
    GEO 内部使用常规 ZSET,因此我们可以通过 ZRANGE or ZRANGEBYSCORE commands 轻松迭代它。
    当然,我们可以根据需要使用 GEO 命令,例如 GEORADIUS。
    4 ) 清理过程。我建议按时间清理,但您可以通过条目数以相同的方式进行清理,只需使用 ZRANGE 代替 ZRANGEBYSCORE让我们找到所有至少一周不活跃的非活跃机器人。
    ZRANGEBYSCORE ZSET:ROBOTS -inf <timestamp-of-week-before>
    
    现在我们需要遍历这些 ID 并删除不需要的 HSET、GEO 键并将其从我们的 index 中删除
    ZREM ZSET:ROBOTS 17
    DEL HSET:ROBOT:17
    DEL GEO:ROBOT:17
    
    现在我们只需要删除旧的 GEO-history 条目,正如我上面所说的,redis 中的 GEO 是引擎盖下的常规 ZSET,所以让我们使用 ZRANGE
    ZRANGE GEO:ROBOT:17 0 -1
    
    我们将获得条目列表,但由于 GEO,它的排序会很奇怪,每个 score 将是 GEO location
    我们的条目格式为“:”,因此我们可以使用 split(':') 并比较时间戳,如果它太旧,我们将其删除。例如我们的时间戳是 12345678 而消息是 hello
    ZDEL GEO:ROBOT:17 1234567:hello
    
    附言我强烈建议您阅读这篇关于 redis 中 ZSET 的精彩文章
    简而言之:Redis 不仅按分数还按键名对项目进行排序,这意味着分数相同的条目将按字母顺序排序,这非常有用!
    ZADD key 0 ccc 0 bbb 0 aaa
    ZRANGE key 0 -1
    
    将返回您排序的集合:
     1. "aaa"
     2. "bbb"
     3. "ccc"
    

    关于database-design - 使用Redis的地理程序设计建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29979085/

    相关文章:

    php - 默认内容放在哪里?代码还是数据库?

    redis - 有没有办法在redis中获取客户端IP?

    cordova - 如何获取phonegap中的当前位置?

    redis - 检查 Redis 服务器版本

    react-native - navigator.geolocation.getCurrentPosition 在使用 React Native 的 iOS 模拟器中未触发

    javascript - 传单 map : update marker using navigator. geolocation.watchPosition?

    mysql - 如何解决这个外键问题 MySQL?

    sql - 具有复杂 WHERE 条件的高效 SELECT - 我是否需要存储具有计算值的列?

    mysql - 处理许多列的数据库

    conf 文件中的 Redis Sentinel 输出