前回の
Redisのデータ型
次に、
文字列型
文字列型はRedisで扱うことのできる最もシンプルなデータ型です。バイナリセーフですので、
ただし、use utf8
プラグマを宣言していると思います。そのような場合、
use utf8;
use Encode qw(encode_utf8 decode_utf8);
# 書き込むときはエンコード
$redis->set('key' => encode_utf8 '日本語');
# 読み込むときはデコード
my $val = decode_utf8 $redis->get('key');
リスト型
リスト型は複数の値を順番に並べて、
# push @key, qw(a b c); に相当
$redis->rpush(key => qw(a b c));
# pop @key; に相当
my $v = $redis->rpop('key');
# $key[1]; に相当
$redis->lindex('key', 1);
リスト型のジョブキューとしての応用
筆者の携わったサービスでは、
ジョブキューとして利用する場合、BRPOP
コマンドはRPOP
コマンドと同様にリストの末尾から値を1つ取り出すコマンドですが、BRPOP
コマンドを用いることで、
BRPOP
コマンドの簡単なサンプルを用意しました。worker.
はジョブのワーカです。ジョブキューにジョブが投入されるのを待ち、enqueue.
はジョブを投入するプログラムです。
use Redis::Fast;
my $redis = Redis::Fast->new(
server => 'localhost:6379'
);
while(1) {
my ($keyname, $job) = $redis->blpop("jobqueue", 30);
print "$keyname: $job\n";
}
use Redis::Fast;
my $redis = Redis::Fast->new(
server => 'localhost:6379'
);
$redis->rpush("jobqueue", "awesome job");
では、worker.
を実行してみましょう。この時点ではジョブキューに何も入っていないので、
$ perl worker.pl
次に、enqueue.
を実行します。
$ perl enqueue.pl
ジョブが投入されたので、worker.
を実行した端末に受け取ったジョブの内容が表示されるはずです。
jobqueue: awesome job
BRPOP
コマンドの動作イメージはつかめたでしょうか。この例ではワーカが1つだけでしたが、worker.
をたくさん起動してからジョブを投入したり、worker.
とenqueue.
の実行順を変えたりなどして、
ハッシュ型
ハッシュ型はPerlにおけるハッシュ変数にあたる型で、
# %key = (
# a => 1,
# b => 2,
# );
# をRedisに書き込む
$redis->hmset( key => (
a => 1,
b => 2,
) );
# $key{a} を取得
print $redis->hget('key', 'a');
セット型
セット型は値の集合を扱うための型です。セット型に保存されている値は順序を持たず、
# a, b, cを含む集合を作成
$redis->sadd(key => qw(a b c));
# 'a'が集合に含まれるか
print $redis->sismember('key', 'a');
同じ要素が重複しないことを利用して、
ただし、
集合の中からランダムに要素を取得するSRANDMEMBER
コマンドも便利です。ゲームではマッチング処理などでランダムな要素取得を多用しますが、
次のプログラムはSRANDMEMBER
コマンドの利用例です。one、
$redis->sadd(myset=>qw(one two three));
print $redis->srandmember('myset');
ソート済みセット型
ソート済みセット型はセット型と同様に集合を扱う型ですが、
# one: スコア50
# two: スコア100
$redis->zadd( key => (
50 => one,
100 => two,
) );
# 'one'の順位を取得
print $redis->zrank('key', 'one');
Luaスクリプト
Redisにはデータ保存機能だけでなく、
利点
Perlを使えば複雑なデータ処理も簡単に書くことができるのに、
それは、
Luaスクリプトの実行
Luaスクリプトの実行にはEVAL
コマンドを利用します。たとえばSET
コマンドを実行するLuaスクリプトを実行してみましょう。
my $lua = 'return redis.call("set",KEYS[1],ARGV[1])';
$redis->eval($lua, 1, 'key', 'value');
EVAL
コマンドの引数の
Luaスクリプトのキャッシュ
EVAL
コマンドを使った方法では毎回スクリプトをRedisに転送するため、SCRIPT LOAD
コマンドでスクリプトを保存したあと、EVALSHA
コマンドで呼び出せます。
# スクリプトをキャッシュに保存
my $lua = 'return redis.call("set",KEYS[1],ARGV[1])';
my $sha = $redis->script_load($lua);
# 保存したスクリプトを呼び出す
$redis->evalsha($sha, 1, 'key', 'value');
しかし今度は、EVAL
コマンドのドキュメントではこの問題を解決するために、EVALSHA
を実行してみてNOSCRIPT
のエラーが出たら、EVAL
を実行する」EVAL
コマンドはスクリプトの実行と同時にキャッシュも行うので、EVALSHA
が成功するようになります。
この処理を簡単に行えるよう筆者が開発したのが、
use Redis::Script;
my $lua = 'return redis.call("set",KEYS[1],ARGV[1])';
my $s = Redis::Script->new(script => $lua);
$s->eval($redis, ['key'], ['value']);
<続きの
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現! - 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう - 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT