2

Suppose you have a hash 'users' whose entries map numeric IDs to JSON-encoded arrays, so, for instance, the integer 1 maps to the string {name: 'John', surname: 'Doe', occupation: 'plumber'}.

The numeric IDs of items in the hash are stored in various lists. Thus, if 'foobar' is one of these lists, to retrieve the actual data from it I would run a simple Lua script (implementing a server-side join operation). Or, as I've just learned, I could use something like

SORT foobar BY inexistent_key GET user:*

but that implies storing each user's data into a separate key which seems expensive (in my case I have many small collections so I want to take advantage of Redis compression of hashes).

The question is finally this: I need to keep these lists ordered alphabetically by, say, each user's surname, then by name. What is the best way to achieve this, without changing too much the underlying data model (if possible)?

So far the best I could think of was using the SORT command together with the BY and STORE clauses, that is, running

SORT foobar BY surname:* STORE foobar

whenever the list is changed, but that way I'd need many keys. If I could use a hash in the BY clause that would be the ideal solution, it seems to me.

If the fields I want to sort by were somehow limited (as in, just a couple hundred surnames) I could think of mapping strings to integers and use a Redis sorted set, but this doesn't seem to be the case.

4

2 回答 2

3

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

以下示例具有以下结构:

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

user:X是包含重复姓名/姓氏数据的 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修饰符。

于 2012-07-15T16:10:09.233 回答
1

最后,在我看来,解决我的问题的一种方法是使用 Lua 中可用的 table.sort() 函数。除了小散列“用户”和小 ID 列表“foobar”之外,我还引入了另一个小散列,比如“用户:排序字符串”,我在其中存储了我想在 ' 中对 ID 进行排序的字符串foob​​ar'(在虚构的例子中是姓氏和名字的组合)。为了对 'foobar' 进行排序,我将在 Redis 中运行以下 Lua 片段,作为键 '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])
于 2012-07-17T08:31:54.113 回答