こんにちは。
1,2年くらい前からRedisを使用した案件に携わることが多くなりました。
ここでは、5つあるデータ型と、個人的に考えているそれらの適した使い方についてまとめてみました。
Redisとの疎通
データ型云々以前に、Redisと疎通しないことには始まりません。
使用するには、Redis自体のインストールと、PHPで使用する場合はphpredisというモジュールもインストールする必要があります。(インストール手順はここでは割愛します。)
Redisとの疎通方法は下記です。
1 2 3 4 5 |
<?php $redis = new Redis(); $redis->connect("REDIS_IP","REDIS_PORT"); echo $redis->ping(); |
“REDIS_IP”にはRedisサーバのホスト名を入力し、”REDIS_PORT”にはRedisとの疎通に使用するポート番号を指定します。
Webサーバ内にインストールしている場合は”REDIS_IP”は127.0.0.1などで大丈夫です。サーバ設定次第ですが、ポート番号は6379などが多いようです。
Redisのデータ型について
Redisのデータ型には、下記の5つのものがあります。
- String型
- Hash型
- List型
- Set型
- SortedSet型
それでは、それぞれのデータ型と想定用途について書いていきます。
String型
KeyとValueが1対1の関係で管理されるデータ型です。
1 2 3 |
$redis->set('en', 'Hello'); $redis->set('ja', 'こんにちは'); echo $redis->get('en'); //Helloと表示されます |
Cookieに近い管理のされ方でして、Redisをセッションサーバとして使用する場合はString型でデータ格納すると管理がしやすいかと思います。
また、「setnx」というメソッドで、すでに使用されているKeyならばデータ保存せずfalseを返し、まだ利用されていないKeyであればデータ保存しつつtrueを返すメソッドがあるのですが、こちらを利用してユニークなIDを生成することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function saveID(){ for($i=1;$i<=5;$i++){ //5回までID発行 $id = createID(); //Redisのデータと突合 if($redis->setnx($id, 1)){ //ID発行完了なので値を返却 return $id; } } //処理失敗 return false; } function createID(){ //シリアル発行メソッド } |
Hash型
親Key、子Key、Valueにより管理されるデータ型です。
1 2 3 4 5 6 7 8 9 |
$redis->hSet('item_01', 'name', 'Apple'); $redis->hSet('item_01', 'price', '300円'); $redis->hSet('item_01', 'stock', 1000); $redis->hSet('item_02', 'name', 'Pineapple'); $redis->hSet('item_02', 'price', '500円'); $redis->hSet('item_02', 'stock', 200); echo $redis->hGet('item_01', 'name'); //Appleと出力される print_r($redis->hGetAll('item_02')); //Array(['name'] => 'Pineapple', ['price'] => '500円', ['stock'] => 200) |
例えば、親Keyを商品ID、子キーを商品の属性情報を保存するような形で使用すれば、RDBでのデータ管理に近い考え方で使うことができます。(リレーショナル機能はありませんが)
また、hMSetメソッドを使うことによりデータの登録部分のコードをスッキリ書くことができます。
1 2 3 4 5 6 7 8 |
$item_01 = array( 'name' => 'Apple', 'price' => '300円', 'stock' => 1000 ); $redis->hMSet('item_01', $item_01); print_r($redis->hGetAll('item_01')); //出力結果:Array(['name'] => 'Apple', ['price'] => '300円', ['stock'] => 1000) |
List型
一つのKeyに対してValueを複数管理することができます。Valueは登録された順番も管理されるため、配列のような形でデータを取り扱うことができます。
1 2 3 4 5 |
$redis->rPush('user_id_01', '2017-03-16 10:31:42'); $redis->rPush('user_id_01', '2017-03-16 16:45:23'); $redis->rPush('user_id_01', '2017-03-16 19:12:56'); print_r($redis->lRange('user_id_01', 0, -1)); //出力結果:Array([0] => '2017-03-16 10:31:42', [1] => '2017-03-16 16:45:23', [2] => '2017-03-16 19:12:56') |
上記例では日付を直入れしてますが、例えばdate(‘Y-m-d H:i:s’)みたいに設定しておけば、プログラムにアクセスするたびにアクセスログを貯めていくような使い方ができるなと思いました。もっと細かく情報を取得したい場合は、Hash型の方が向いているとは思いますが・・・
Set型
一つのKeyに対してValueを複数管理できる点はList型と同様ですが、こちらは登録された順番は管理しません。かわりに、異なるKeyで管理されたデータ群同士で、和・差・積を算出することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//A君が好きなもの $redis->sAdd('a_kun_like' , '焼肉'); $redis->sAdd('a_kun_like' , '野球'); //B君が好きなもの $redis->sAdd('b_kun_like' , 'サッカー'); $redis->sAdd('b_kun_like' , '焼肉'); //和を表示 print_r($redis->sUnion('a_kun_like', 'b_kun_like')); //出力結果:Array([0] => '焼肉',[1] => '野球',[2] => 'サッカー') //差を表示 print_r($redis->sDiff('a_kun_like', 'b_kun_like')); //出力結果:Array([0] => '野球',[1] => 'サッカー') //積を表示 print_r($redis->sInter('a_kun_like', 'b_kun_like')); //出力結果:Array([0] => '焼肉') |
こちらの型、未だ有効活用できる場面に遭遇したことがありません・・!活用できる場面などありましたら逆にご教授ください!
SortedSet型
KeyとValueの他に、「Score」をセットすることで、Score順に並んだ形でデータ管理を行うことができます。
1 2 3 4 5 6 7 8 |
$redis->zAdd('game_score' , 1000, 'Yamada'); $redis->zAdd('game_score' , 3000, 'Tanaka'); $redis->zAdd('game_score' , 4000, 'Sato'); $redis->zAdd('game_score' , 2000, 'Suzuki'); //ランキングデータを表示(10位まで表示) $ranking = $redis->zRevRange('game_score', 0, 9, true); print_r($ranking); //出力結果:Array(['Sato'] => 4000, ['Tanaka'] => 3000, ['Suzuki'] => 2000, ['Yamada'] => 1000) |
主にゲームなどの得点管理、ランキング管理などに大きな効果を発揮します。データをMySQLなどにため、PHPで演算することによりランキング情報を出すことも可能ですが、Redisはデータを保存したタイミングですでに得点順も管理されているため、あとはデータを取り出すだけです。そのため、処理が圧倒的に速いというメリットがあります。
ゲームのランキングを表示する際に、同着順位のロジックを組むのは少し大変ですが、下記のような出し方で楽に出すことができます。
1 2 3 4 |
//自分の得点 $score = 100; //自分の順位 $rank = $redis->zCount('game_score', $score + 1, "+inf") + 1; |
まとめ
たまに、「MySQLとどっちがいいの?」という質問を受けるときがあるのですが、一長一短だと思っています。というのも、MySQLは複数テーブル構造ということで複雑なデータを管理しやすく、リレーション・ユニークキーなどデータの整合性を保つのに必要な機能が多く含まれています。一方Redisは、最終的にはサーバ内のディスクにデータが保存されますが、保存直後はメモリに一時保存されるため、データ揮発の可能性はゼロではありません。個人情報などの大事なデータに関しては、MySQLなどRDBに保存したほうがいいかと思います。
その代わり、RedisはI/Oの速さが長所で、消失してもダメージが少ないが、大量アクセスが見込まれるような、ゲームコンテンツなどで使用すると、高い効果を発揮できると思います。