概要
Redisにランキングデータとかをzsetで格納してたのですが、そのランキングデータを使って諸々テストしたくなりまして。
とはいえ、zsetをコピーする術がcommands探してもなかった。かなしい。
そんな中で以下のようなエントリを見つけて、サクッとスクリプト書いたらコピーできちゃったお話です。
RedisのLuaスクリプティング機能について « Rest Term
Redisでlua script書ける
EVAL
ってコマンドを使うと書けるらしい。
bash
# 127.0.0.1:6379 にredis-serverがいるとして
redis-cli
redis-cli
127.0.0.1:6379> EVAL "return 'Hello, world!'" 0
#=> "Hello, world!"
これを読むと、引数も拾える。
redis-cli
127.0.0.1:6379> EVAL "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 key1 key2 1 2
#=> 1) "key1"
#=> 2) "key2"
#=> 3) "1"
#=> 4) "2"
127.0.0.1:6379> EVAL "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 key1 key2
#=> 1) "key1"
#=> 2) "key2"
127.0.0.1:6379> EVAL "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 key1
#=> (error) ERR Number of keys can't be greater than number of args
SCRIPT LOAD
でscriptを登録しておける
SCRIPT LOAD
とEVALSHA
を使えば諸々捗りそう。
(redis-serverが落ちなければ発行されたhashkeyは残るっぽい)
redis-cli
127.0.0.1:6379> SCRIPT LOAD "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}"
#=> "c0d2d6f81be75d67523d7c8ac69a932fbe1aa4e2"
127.0.0.1:6379> EVALSHA c0d2d6f81be75d67523d7c8ac69a932fbe1aa4e2 2 key1 key2
#=> 1) "key1"
#=> 2) "key2"
127.0.0.1:6379> exit
redis-cli
127.0.0.1:6379> EVALSHA c0d2d6f81be75d67523d7c8ac69a932fbe1aa4e2 2 key1 key2 1 2
#=> 1) "key1"
#=> 2) "key2"
#=> 3) "1"
#=> 4) "2"
zsetをコピーするスクリプト
というわけで、この辺を参考に本題のスクリプト書いてみた。
とりあえずサンプルとしてコピー元データを作っとく。
redis-cli
127.0.0.1:6379> ZADD key1 10 1
#=> (integer) 1
127.0.0.1:6379> ZADD key1 20 2
#=> (integer) 1
127.0.0.1:6379> ZADD key1 50 3
#=> (integer) 1
127.0.0.1:6379> ZADD key1 100 4
#=> (integer) 1
127.0.0.1:6379> ZADD key1 30 5
#=> (integer) 1
127.0.0.1:6379> ZADD key1 1 6
#=> (integer) 1
127.0.0.1:6379> ZRANGE key1 0 -1
#=> 1) "6"
#=> 2) "1"
#=> 3) "2"
#=> 4) "5"
#=> 5) "3"
#=> 6) "4"
で、こんなかんじでスクリプト走らせると...
redis-cli
127.0.0.1:6379> EVAL "for i,v in ipairs(redis.call('zrange', KEYS[1], 0, -1)) do redis.call('zadd', KEYS[2], redis.call('zscore', KEYS[1], v), v) end" 2 key1 key2
#=> (nil)
127.0.0.1:6379> ZRANGE key2 0 -1
#=> 1) "6"
#=> 2) "1"
#=> 3) "2"
#=> 4) "5"
#=> 5) "3"
#=> 6) "4"
# ちゃんと`score`もコピーできてるで
127.0.0.1:6379> ZSCORE key2 6
#=> "1"
127.0.0.1:6379> ZSCORE key2 4
#=> "100"
というかんじになります。便利!
おわりに
別の言語でscript書いて実行させてもよいのだけど、カジュアルに実行できるので割と便利かな、という感想です。以上!