phpredis速查表
我将参加这次的isucon比赛,所以我制作了一个肯定会用到的phpredis备忘录。
虽然名字相似有点容易混淆,但请注意这不是predis。
predis是php实现的Redis客户端,而这次比赛使用的phpredis是由C语言实现的更快速的Redis客户端。
Redis的数据类型
在使用phpredis之前,我想先了解一下Redis的基本数据类型。
Redis共有五种数据类型。
我认为只要了解字符串类型和哈希类型,大概就足够了,但其他三种类型也很实用。
-
- 文字列型(String)
-
- リスト型(List): 双方向リスト、keyの持たないハッシュっていうか、配列みたいなやつって覚えればいいよ
-
- セット型(Set): 順不同の集合、値が重複しないようになっているので、重複のないリスト作るのに便利
-
- ソート済みセット型(ZSet): 自動的にソートされるセット型、簡易的なランキングを作るのに便利
- ハッシュ型(Hash): key=>valueないわゆる普通のハッシュ
除了字符串类型之外的四个末端数据都将变为字符串类型。
换句话说,这些数据类型用于结构化地处理字符串,最终Redis似乎将所有数据都视为字符串处理。
初始化相关
// 接続
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// データベース切り替え(isuconで複数つかうんかな・・・)
$redis->select(1);
// データ全部消す
// returnは常にTRUE
$redis->flushAll();
// データベース単位で全部消す
// returnは常にTRUE
$redis->flushDb();
与数据类型无关的命令速查表。
// 条件を満たすkeyを全部取得する、'*'がワイルドカード
// 返ってくるのはkeyだけで、valueもとりたいならこの後別のコマンドが必要
$allKeys = $redis->keys('*'); // 全部のkeyがarrayで返ってくる
$keyWithUserPrefix = $redis->keys('user*'); // 'user'ってprefixがついてるkeyがarrayで返ってくる
// 対象のkeyのデータ型を取得する
// Redisクラスで定義されてる定数で返ってくる
// string: Redis::REDIS_STRING set: Redis::REDIS_SET list: Redis::REDIS_LIST zset: Redis::REDIS_ZSET hash: Redis::REDIS_HASH other: Redis::REDIS_NOT_FOUND
$redis->type('key');
文字串类型的速查表
由于是二进制安全的,所以实际上可以插入任何图像、序列化的PHP对象等等。虽然没有在这里写明,但还可以在value末尾添加(append)或者只获得value的某一部分(substr范围)。
// ゲット、あれば文字列が、なければFALSEが返ってくる
$redis->get('key');
// セット、成功すればTRUEが返ってくるけど、失敗時のreturnは不明(ドキュメントに書かれていない)
$redis->set('key', 'value');
// Redis2.6.12以降ならexpireを秒単位で指定できる
$redis->set('key', 'value', 10);
// 既存がない時だけセット
// 成功したらTRUE、失敗したらFALSE
$redis->setNx('key', 'value');
// 置換、置換前のvalueがreturnされる
$beforeValue = $redis->getSet('key', 'newValue');
// 削除、一度に複数削除できて、配列で指定する
// 削除できたkeyの数がreturnされる
$redis->delete(['key3', 'key4']); // return 2
// 存在確認、あればTRUE、なければFALSE・・・らしいんだけど実際にやってみると1と0が返ってくる
$redis->exists('key'); // return 1
// マルチゲット、なかったkeyの部分はFALSEが返ってくる
$redis->mGet(['key1', 'non_exist_key', 'key5']); // return ['value1', `FALSE`, 'value5']
// マルチセット
// 成功したらTRUE、失敗したらFALSEらしいけど、失敗ってどこまでを指してるのだろうか?
$redis->mSet(['key0' => 'value0', 'key1' => 'value1']);
列表型的备忘单
一种类似数组的数据类型,可以从开头或末尾进行推送或弹出操作。
例如,当类似社交网络的足迹功能传递时序数据,并且希望按照其顺序逐个获取时,可能会很方便。
// 要素の先頭へプッシュ(left push)
// 逆に末尾につけたい場合はrPushを使う
$redis->delete('key1');
$redis->lPush('key1', 'C'); // returns 1
$redis->lPush('key1', 'B'); // returns 2
$redis->lPush('key1', 'A'); // returns 3
$redis->lRange('key1', 0, -1); // return [ 'A', 'B', 'C' ]
// 要素の先頭からポップ(left pop)
// 逆に末尾から獲りたい場合はrPopを使う
$redis->lPop('key1'); // return 'A'
$redis->lRange('key1', 0, -1) // return [ 'B', 'C' ]
// 1個だけゲット、配列をインデックスでアクセスするみたいに第2引数に数値渡せばいい
// ポップではないので元の配列から除去されない
$redis->lGet('key1', 0); // return 'B'
// 範囲でゲット、第2、第3引数にstart~endのインデックス番号を渡す
// start: 0, end: -1にすれば全部取れる
// returnはarrayで返ってくる
$redis->lRange('key1', 0, -1); // ['B', 'C']
// 配列サイズの取得
$redis->lSize('key1'); // return 2
套餐式
不重复的集合。
即使在已有的值中插入相同的值,数量也不会增加。
另外,与列表类型不同,没有顺序的概念,所以无法进行“从开头获取前n个”的操作。
例如,像社交网络的好友功能这样的数据不允许重复,并且没有顺序的概念,因此在这种情况下非常方便。
虽然没有在这里提到,但似乎可以与其他集合类型进行合并或取差集。非常方便。
// 追加、一度に複数入れられる、追加した数がreturnされる
// 既存と重複した分は追加されず、returnの数値にも加算されない
$redis->sAdd('key1' , 'value1', 'value2'); // return 2
// 全部取得、arrayで返ってくる
$redis->sMembers('key1'); // ['value1', 'value2']
// メンバの数を取得
$redis->sCard('key1'); // return 2
// valueの存在確認、あればTRUE、なければFALSE
$redis->sIsMember('key1', 'value1'); // return true
// 削除、一度に複数削除できる
$redis->sRem('key1', 'value1', 'value2'); // return 2
已排序的集合类型
各元素具有一个名为”score”的值,并且可以按照该值的排序顺序进行获取的数据类型被称为集合型。在制作简易排行榜时非常方便。说明中指定要将float类型传递给score。那就先暂时放入整数吧,应该没问题。
// 追加、第2引数がscoreで、取得時はこの値でソートされた結果が返ってくる
$redis->zAdd('key', 1, 'value1'); // return 1
$redis->zAdd('key', 0, 'value0'); // return 1
$redis->zAdd('key', 5, 'value5'); // return 1
$redis->zRange('key', 0, -1); // return ['value0', 'value1', 'value5']
// score加算、対象のvalueが存在しない場合は0スタートでaddするので、zAddの代替として使っても良い?
// 加算後のscoreがfloat型でreturnされる
$redis->zIncrBy('key', 1, 'value1'); // return 2.0
// 範囲で取得、scoreでソートされた結果が返ってくる
// 第2、第3引数で取得したい順位(scoreの値ではない)を範囲指定する、順位は0始まり
// scoreの値も欲しい場合は第4引数にtrueを渡す
// ちなみに同率4位が2つあって、4位までを取得すると片方は除去されてしまう
$redis->zRange('key', 0, -1); // return ['value0', 'value1', 'value5']
$redis->zRange('key', 0, -1, true); // return ['value0' => 0.0, 'value1' => 2.0, 'value5' => 5.0]
// scoreの値指定で範囲取得、第2、第3引数にscoreの範囲を指定する
$redis->zRangeByScore('key', 0, 3); // return ['value0', 'value1']
// 要素数を取得、第2、第3引数で指定された範囲のscoreを持つ要素の数が返ってくる(valueは返ってこない)
$redis->zCount('key', 0, 3); // return 2
// 指定したvalueの順位を取得、順位は0始まり
$redis->delete('key');
$redis->zAdd('key', 1, 'one');
$redis->zAdd('key', 2, 'two');
$redis->zRank('key', 'one'); // return 0
$redis->zRank('key', 'two'); // return 1
哈希类型的备忘单
在获取数据方面有两种方法,即hGet和hGetAll,可能会有困扰。基本上只用hMSet和hGetAll就足够了吧。
// セット、returnが微妙
// 既存がなければ1が、あれば既存を置換した上で0が、セットに失敗したらFALSEが返ってくる
$redis->hSet('key', 'hashKey0', 'value0'); // return 1
$redis->hSet('key', 'hashKey1', 'value1'); // return 1
// ゲット、ハッシュの中のkey1つ分とってくる
// あれば文字列が、なければFALSEが返ってくる
$value = $redis->hGet('key', 'hashKey0'); // return 'value0'
// ハッシュ全体をとってくる
// phpのarray型で返ってくる、なければFALSEが返ってくる
$array = $redis->hGetAll('key'); // return ['hashKey0' => 'value0', 'hashKey1' => 'value1']
// 既存がない時だけセット
// セットされたらTRUE、失敗したらFALSEが返ってくる
$redis->hSetNx('key', 'hashKey2', 'value2'); // return true
// マルチセット、複数回hSet実行するくらいならこっち使ったほうが全然早いらしいんで、基本こっち使ったほうが良いかも
// 参考: https://qiita.com/ndxbn/items/11e3895389d5c7c1ff80
$redis->hMSet('user:1', ['name' => 'Joe', 'salary' => 2000]); // return true
// 削除、hashKey単位の削除なので、keyごと削除したいならdeleteつかってね
// 複数個まとめて削除もできるよ
$redis->hDel('key', 'hashKey1', 'hashKey2'); // return 2
// hashKeyの一覧を取得する、valueまでは返ってこないよ
// arrayで返ってくる
$redis->hKeys('user:1'); // return ['name', 'salary']
// valueの一覧を取得する、keyまでは返ってこない、hGetAllで別にいい気がする
// arrayで返ってくる
$redis->hVals('user:1'); // return ['Joe', '2000']
整理
如果想要的话,列表型、集合型和有序集合型可以通过哈希类型实现类似的功能。
我认为,这些类型可以被看作是为了专门针对哈希类型而减少功能而设计的。
由于我很少使用Redis,所以不能确定地说。
如果能通过减少一层嵌套来减少数据量或减少应用程序代码量,我认为应该积极地利用这个机会。