【问题标题】:Redis sorted set by string valuesRedis 按字符串值排序
【发布时间】:2012-07-14 18:47:42
【问题描述】:

假设您有一个哈希“用户”,其条目将数字 ID 映射到 JSON 编码的数组,因此,例如,整数 1 映射到字符串 {name: 'John', surname: 'Doe',occupation:'管道工'}。

散列中项目的数字 ID 存储在各种列表中。因此,如果“foobar”是这些列表之一,要从中检索实际数据,我将运行一个简单的 Lua 脚本(实现服务器端连接操作)。或者,正如我刚刚了解到的,我可以使用类似的东西

SORT foobar BY inexistent_key GET user:*

但这意味着将每个用户的数据存储到一个单独的键中,这似乎很昂贵(在我的情况下,我有很多小集合,所以我想利用 Redis 的哈希压缩)。

问题最终是这样的:我需要按字母顺序排列这些列表,例如,每个用户的姓氏,然后按名称。在不改变太多底层数据模型(如果可能的话)的情况下,实现这一目标的最佳方法是什么?

到目前为止,我能想到的最好的方法是使用 SORT 命令以及 BY 和 STORE 子句,即运行

SORT foobar BY surname:* STORE foobar

每当列表更改时,但那样我需要很多键。如果我可以在 BY 子句中使用散列,那将是理想的解决方案,在我看来。

如果我想要排序的字段受到某种限制(例如,只有几百个姓氏),我可以考虑将字符串映射到整数并使用 Redis 排序集,但情况似乎并非如此。

【问题讨论】:

    标签: language-agnostic redis sorted


    【解决方案1】:

    您可以按哈希键排序,没有 Lua 脚本的复杂性,但您必须将 Json 结构中的键复制到 Redis 的哈希键。

    以下示例具有以下结构:

    users 是一个包含查询中的用户 ID 的集合。

    user:X 是包含重复的 name / surname 数据的 Redis 哈希。

    userdata:X 是您的原始用户 Json 哈希。


    redis> hmset user:1 name First surname User
    OK
    redis> set userdata:1 "{occupation: 'Tester'}"
    OK
    redis> hmset user:2 name Last surname Violet
    OK
    redis> set userdata:2 "{occupation: 'Bookseller'}"
    OK
    redis> hmset user:3 name Middle surname Veredict
    OK
    redis> set userdata:3 "{occupation: 'Judge'}"
    OK
    redis> hmset user:4 name Ultimate surname Veredict
    OK
    redis> set userdata:4 "{occupation: 'Ultimate Judge'}"
    OK
    redis> sadd users 1
    (integer) 1
    redis> sadd users 2
    (integer) 1
    redis> sadd users 3
    (integer) 1
    redis> sadd users 4
    (integer) 1
    redis> sort users by user:*->surname get user:*->name get user:*->surname get userdata:* alpha
    1) "First"
    2) "User"
    3) "{occupation: 'Tester'}"
    4) "Middle"
    5) "Veredict"
    6) "{occupation: 'Judge'}"
    7) "Ultimate"
    8) "Veredict"
    9) "{occupation: 'Ultimate Judge'}"
    10) "Last"
    11) "Violet"
    12) "{occupation: 'Bookseller'}"
    

    编辑

    我忽略了多个By 只考虑最后一个子句。所以你不能在一个命令中按多个键排序。

    此外,用于字典排序的 SORT 命令现在需要 alpha 修饰符。

    【讨论】:

    • 谢谢你的回答,尼洛特。但是,如果我采用了您的解决方案,则必须为每个用户添加一个哈希 user:*,这是我试图避免的。如果我要这样做,我还会将 userdata 哈希与 user:* 哈希合并。我将运行一些测试来查看使用 JSON 编码数据的许多小散列(在示例中为用户组)和每个项目使用一个散列(在示例中为每个用户一个)之间的内存使用差异。跨度>
    • 嗯,在我的情况下,内存使用量的差异正如预期的那样巨大。同时我发现我真正想做的是 SORT foobar BY weights->* GET table->*​​ 但可惜这似乎不可能......
    • 您注意到允许多个BYGET 了吗?您必须像示例中那样为每个字段发出一个。
    • 对不起,我认为我的评论不够清楚。当我说我希望能够 SORT foobar BY weights->* 我的意思是 foobar 中元素 X 的权重是你通过发出 HGET weights X 找到的。因此你会有只有三个键:users(将 JSON 数据与 ID 相关联的哈希) weights(将权重与 ID 相关联的哈希)和 foobar(包含一些 ID 的集合或列表)。相反,如果我遵循您的方案,则“用户”哈希中的每个元素至少需要一个键。我的数据占用了十倍以上的内存(小散列因此自动压缩)。
    • 如果有人对此感到头疼,这个例子在 2.6 中不起作用。您的排序需要添加 ALPHA 修饰符,例如:“sort users by user:*->surname by user:*->name get user:*->name get user:*->surname get userdata:* ALPHA”
    【解决方案2】:

    最后,在我看来,解决我的问题的一种方法是使用 Lua 中可用的 table.sort() 函数。除了小散列“用户”和小 ID 列表“foobar”之外,我还引入了另一个小散列,比如“用户:排序字符串”,我在其中存储了我想要对 ID 进行排序的字符串foob​​ar'(在虚构的例子中是姓氏和名字的组合)。为了对 'foobar' 进行排序,我将在 Redis 中运行以下 Lua sn-p,作为键 'foobar'、'users:sort-strings' 和 'foobar:tmp' (临时键)传递。

    local lst = redis.call('LRANGE', KEYS[1], 0, -1)
    local sort_function = function (id0, id1)
       local s0 = redis.call('HGET', KEYS[2], id0)
       local s1 = redis.call('HGET', KEYS[2], id1)
       return (s0 < s1)
    end
    table.sort(lst, sort_function)
    for key, value in ipairs(lst) do
       redis.call('RPUSH', KEYS[3], value)
    end
    redis.call('DEL', KEYS[1])
    redis.call('RENAME', KEYS[3], KEYS[1])
    

    【讨论】:

    • 有趣!资源消耗对比如何?快吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 2014-10-28
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    相关资源
    最近更新 更多