redis sort 使用外部key排序

使用外部 key 進行排序

有時候你會希望使用外部的 key 作爲權重來比較元素,代替默認的對比方法。

假設現在有用戶(user)數據如下:

id name level
1 admin 9999
2 huangz 10
59230 jack 3
222 hacker 9999
id 數據保存在 key 名爲 user_id 的列表中。
name 數據保存在 key 名爲 user_name_{id} 的列表中
level 數據保存在 user_level_{id} 的 key 中。
# 先將要使用的數據加入到數據庫中

# admin

redis> LPUSH user_id 1
(integer) 1
redis> SET user_name_1 admin
OK
redis> SET user_level_1 9999
OK

# huangz

redis> LPUSH user_id 2
(integer) 2
redis> SET user_name_2 huangz
OK
redis> SET user_level_2 10
OK

# jack

redis> LPUSH user_id 59230
(integer) 3
redis> SET user_name_59230 jack
OK
redis> SET user_level_59230 3
OK

# hacker

redis> LPUSH user_id 222
(integer) 4
redis> SET user_name_222 hacker
OK
redis> SET user_level_222 9999
OK

如果希望按 level 從大到小排序 user_id ,可以使用以下命令:

redis> SORT user_id BY user_level_* DESC
1) "222"    # hacker
2) "1"      # admin
3) "2"      # huangz
4) "59230"  # jack

但是有時候只是返回相應的 id 沒有什麼用,你可能更希望排序後返回 id 對應的用戶名,這樣更友好一點,使用 GET 選項可以做到這一點:

redis> SORT user_id BY user_level_* DESC GET user_name_*
1) "hacker"
2) "admin"
3) "huangz"
4) "jack"

http://manual.csser.com/redis/key/sort.html



>>> conn.rpush('sort-input', 23, 15, 110, 7) #A
4 #A
>>> conn.sort('sort-input') #B
['7', '15', '23', '110'] #B
>>> conn.sort('sort-input', alpha=True) #C
['110', '15', '23', '7'] #C
>>> conn.hset('d-7', 'field', 5) #D
1L #D
>>> conn.hset('d-15', 'field', 1) #D
1L #D
>>> conn.hset('d-23', 'field', 9) #D
1L #D
>>> conn.hset('d-110', 'field', 3) #D
1L #D
>>> conn.sort('sort-input', by='d-*->field') #E
['15', '110', '7', '23'] #E
>>> conn.sort('sort-input', by='d-*->field', get='d-*->field') #F
['1', '3', '5', '9']



This is just off thetop of my head / crazy / no guarantee of

correctness orperformance, just my attempt at minimizing roundtrips:

1) Store each path with a score, doesn't really matterhow. Lets go

with a hash with the url as the key, and the fields xand y with the

score, like this:

path:example.com {x: 10, y: 20}

path:example.com/level1 {x: 22, y: 41}

... etc

2) Store an index of each path returning a score in asorted set

(score 1 so it is sorted alphanumericly), lets call it"paths":

example.com

example.com/level1

example.com/level1/level2

example.com/level1/level2/level3

example.com/level1/level2/level31

3) Each request will need a unique id, a uuid wouldwork. Split the

requested url into paths of different depths. forexample:

split http://example.com/level1/level2/level3/anythingelse/somefile.html into:

example.com

example.com/level1

example.com/level1/level2

example.com/level1/level2/level3

example.com/level1/level2/level3/anythingelse

example.com/level1/level2/level3/anythingelse/somefile.html

4) Now send the request to the redis server:

MULTI

// add each path to a unique sorted set

ZADD req:uuid 1 example.com

ZADD req:uuid 1 example.com/level1

ZADD req:uuid 1 example.com/level1/level2

ZADD req:uuid 1 example.com/level1/level2/level3

ZADD req:uuid 1 example.com/level1/level2/level3/anythingelse

ZADD req:uuid 1 example.com/level1/level2/level3/anythingelse/somefile.html

// store all the intersecting paths in another sortedset

ZINTERSTORE res:uuid 2 paths req:uuid

// get the last matching path from the intersection(this is the only

value you need)

ZREVRANK res:uuid 0

//clean up

DEL req:uuid res:uuid

EXEC

The return value for the ZREVRANK command should bethe deepest path

that matches the request. From there you can query forthe scores. It

might be possible to do this all in one request bydoing this instead

of the ZREVRANK:

SORT res:uuid LIMIT 0 1 GET # GET path:*->x GETpath:*->y ALPHA DESC

Using SORT might also allow you to just use plain setsinstead of

sorted sets since it will be sorting them anyways,which would save on

memory.

-- 

Derek

 

來自 <https://groups.google.com/forum/#!topic/redis-db/v9bdyGz8ZAM


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章