原書用 Python 與 Redis 進行交互,我用 PHP 來實現。php
環境:LNMP(CentOS 6.6 + Nginx 1.8.0 + MySQL 5.6.23 + PHP 5.6.9)+ Redis 3.0.7 + phpredis 2.2.4
首先在 Linux 開啓 Redis 服務:html
[root@localhost ~]# cd /usr/local/redis/ [root@localhost redis]# ./bin/redis-server ./etc/redis.conf [root@localhost redis]# ps aux|grep redis
若是顯示:git
root 2239 0.2 0.1 35556 1744 ? Ssl 12:08 0:00 ./bin/redis-server *:6379 root 2243 0.0 0.0 5976 724 pts/0 S+ 12:08 0:00 grep redis
說明 Redis 服務已經開啓,端口號 6379 github
redis.phpredis
<?php // 一週的秒數 $seconds = 7 * 86400; define(ONE_WEEK_IN_SECONDS, $seconds); // 每投一票文章加的分值 define(VOTE_SCORE, 432); // 實例化Redis對象 $redis = new Redis(); // 鏈接到Redis服務器 $conn = $redis->connect('localhost', 6379);
init_data.php 用於添加案例的數據緩存
<?php /* 爲投票網站準備數據 */ require 'redis.php'; //1.根據發佈時間排序文章的有序集合 zset $article_info = [ '100408'=>[ 'time'=>strtotime('2016-4-10'), 'score'=>1332164063.49 ], '100635'=>[ 'time'=>strtotime('2016-4-28'), 'score'=>1332174713.47 ], '100716'=>[ 'time'=>strtotime('2016-4-29'), 'score'=>1332225027.26 ] ]; foreach($article_info as $key => $val) { $redis->zadd('time:', $val['time'], 'article:'.$key); } //2.根據評分排序文章的有序集合 zset foreach($article_info as $key => $val) { $redis->zadd('score:', $val['score'], 'article:'.$key); } //3.爲某篇文章(id:100408)投過票的用戶集合 set $users = [234487, 253378, 364680, 132097, 350917]; foreach($users as $key => $val) { $redis->sadd('voted:100408', $val); }
vote.php 用於給文章投票,其中文章 id(article_id)和投票用戶 id(user_id)經過 get 方式傳遞(代碼清單 1-6 article_vote() 函數)服務器
<?php header('Content-type:text/html;charset=utf-8'); require 'redis.php'; $user_id = empty($_GET['user_id']) ? 0 : (int)$_GET['user_id']; $article_id = empty($_GET['article_id']) ? 0 : (int)$_GET['article_id']; function article_vote($redis, $user_id, $article_id) { $cutoff = time() - ONE_WEEK_IN_SECONDS; // 127.0.0.1:6379> zscore time article:100408 // "1460217600" if(intval($redis->zscore('time:', 'article:'.$article_id)) < $cutoff) { return false; } if($redis->sadd('voted:'.$article_id, $user_id)) { // ZINCRBY key increment member // 爲有序集 score 的成員 article:100408 的 score 值加上增量 increment $score_new = $redis->zincrby('score:', VOTE_SCORE, 'article:'.$article_id); echo $score_new; // HINCRBY key field increment // 爲哈希表key中的域field的值加上增量increment。 // 若是用戶是第一次爲這篇文章投票,那麼增長這篇文章的投票數量和評分 } else { return false; } return true; } if(! article_vote($redis, $user_id, $article_id)) { echo '投票失敗'; } else { echo '投票成功'; }
執行 http://yourdomain/init_data.php,完成 Redis 的鏈接和數據的初始化,能夠進入 Redis 的客戶端查詢文章投票積分的有序集合(zset)和文章 100408 的投票用戶的集合(set):dom
[root@localhost redis]# ./bin/redis-cli 127.0.0.1:6379> zrange score: 0 -1 withscores 1) "article:100408" 2) "1332164063.49" 3) "article:100635" 4) "1332174713.47" 5) "article:100716" 6) "1332225027.26" 127.0.0.1:6379> zrange time: 0 -1 withscores 1) "article:100408" 2) "1460217600" 3) "article:100635" 4) "1461772800" 5) "article:100716" 6) "1461859200"
而後訪問 http://yourdomain/vote.php?user_id=100&article_id=100408 讓 user_id 爲 100 的用戶給編號100408 的文章投票。函數
再次進入 Redis 的客戶端查詢文章投票積分的有序集合(zset)和文章 100408 的投票用戶的集合(set):post
127.0.0.1:6379> zrange score: 0 -1 withscores 1) "article:100408" 2) "1332164495.49" 3) "article:100635" 4) "1332174713.47" 5) "article:100716" 6) "1332225027.26" 127.0.0.1:6379> smembers voted:100408 1) "100" 2) "132097" 3) "234487" 4) "253378" 5) "350917" 6) "364680" 127.0.0.1:6379>
發佈文章 post_article.php(代碼清單 1-7 post_article() 函數)
<?php require 'redis.php'; // @param object $redis redis對象 // @param int $user_id 用戶編號 // @param string $title 文章標題 // @param string $link 文章連接 function post_article($redis, $user_id, $title, $link) { $article_id = $redis->incr('article:'); // 生成新的文章id $voted = 'voted:'.$article_id; $redis->sadd($voted, $user_id); // 將發佈文章的用戶添加到文章已投票的用戶名單中 $redis->expire($voted, ONE_WEEK_IN_SECONDS); // 將投票名單的過時時間設置爲一週 $now = time(); $article = 'article:'.$article_id; $redis->hmset($article, [ 'title' => $title, 'link' => $link, 'poster' => $user_id, 'time' => $now, 'votes'=> 1 ]); // 將文章的信息存儲到一個散列裏 $redis->zadd('score:', $now + VOTE_SCORE, $article); // 把文章添加到根據評分排序的有序集合中 $redis->zadd('time:', $now, $article); // 把文章添加到根據發佈時間排序的有序集合中 return $article_id; } $user_id = isset($_GET['user_id']) ? $_GET['user_id'] : 0; $mtid = mt_rand(0,999); $title = '文章標題'.$mtid; $link = 'http://www.youdomain.com/article/'.$mtid; if(post_article($redis, $user_id, $title, $link)) { echo 'success'; } else { echo 'error'; }
訪問:http://yourdomain/post_article.php
因爲 url 不帶參數而且 Redis 中不存在 article: ,所以會有一個 user_id 爲 0 的用戶發佈 article:1
此時查詢 Redis 中時間和分數的有序集合、article:1 的投票用戶集合以及 article:1 的散列內容:
127.0.0.1:6379> zrange time: 0 -1 withscores 1) "article:100408" 2) "1460217600" 3) "article:100635" 4) "1461772800" 5) "article:100716" 6) "1461859200" 7) "article:1" 8) "1465105632" 127.0.0.1:6379> zrange score: 0 -1 withscores 1) "article:100408" 2) "1332164495.49" 3) "article:100635" 4) "1332174713.47" 5) "article:100716" 6) "1332225027.26" 7) "article:1" 8) "1465106064" 127.0.0.1:6379> smembers voted:1 1) "0" 127.0.0.1:6379> hgetall article:1 1) "title" 2) "\xe6\x96\x87\xe7\xab\xa0\xe6\xa0\x87\xe9\xa2\x9868" 3) "link" 4) "http://www.youdomain.com/article/68" 5) "poster" 6) "0" 7) "time" 8) "1465105632" 9) "votes" 10) "1"
能夠發佈多篇文章用於測試。
get_articles.php 獲取文章列表(代碼清單1-8 get_article() 函數)
<?php require 'redis.php'; define(ARTICLES_PER_PAGE, 5); // 每頁5條數據 // @param object $redis redis對象 // @param int $page 當前頁 // @param string $order 根據$order來排序 // @return array $articles 文章信息 function get_articles($redis, $page, $order = 'score:') { $start = ($page - 1) * ARTICLES_PER_PAGE; $end = $start + ARTICLES_PER_PAGE - 1; $ids = $redis->zrevrange($order, $start, $end); // 獲取多個文件的序號 按 score 值遞減(從大到小)來排列。 $articles = []; foreach($ids as $id) { $article_data = $redis->hgetall($id); $article_data['id'] = $id; $articles[] = $article_data; } return $articles; } $page = isset($_GET['page']) ? $_GET['page'] : 1; $articles = get_articles($redis, $page); echo '<pre>'; print_r($articles);
能夠經過 http://yourdomain/get_articles.php 或 http://yourdomain/get_articles.php?page = 2 來獲取文章列表,能夠獲得:
Array ( [0] => Array ( [title] => 文章標題23 [link] => http://www.youdomain.com/article/23 [poster] => 106 [time] => 1465180517 [votes] => 1 [id] => article:8 ) [1] => Array ( [title] => 文章標題719 [link] => http://www.youdomain.com/article/719 [poster] => 105 [time] => 1465180514 [votes] => 1 [id] => article:7 ) [2] => Array ( [title] => 文章標題811 [link] => http://www.youdomain.com/article/811 [poster] => 104 [time] => 1465180511 [votes] => 1 [id] => article:6 ) [3] => Array ( [title] => 文章標題22 [link] => http://www.youdomain.com/article/22 [poster] => 103 [time] => 1465180508 [votes] => 1 [id] => article:5 ) [4] => Array ( [title] => 文章標題350 [link] => http://www.youdomain.com/article/350 [poster] => 102 [time] => 1465180506 [votes] => 1 [id] => article:4 ) )
添加文章至分組以及從分組中移除文章(代碼清單:1-9 add_remove_groups() 函數)
<?php require 'redis.php'; // @param object $redis // @param int $artile_id // @param array $to_add // @param array $to_remove function add_remove_groups($redis, $article_id, $to_add = [], $to_remove = []) { $article = 'article:'.$article_id; // 將文章添加到所屬的羣組 if(! empty($to_add)) { foreach($to_add as $group) { $redis->sadd('group:'.$group, $article); } } // 將文章從羣組裏面移除 if(! empty($to_remove)) { foreach($to_remove as $group) { $redis->srem('group'.$group, $article); } } }
初始化羣組數據 init_data_group.php
<?php /* 準備羣組數據 */ require 'redis.php'; $article_info = ['article:100408', 'article:100635', 'article:5']; foreach($article_info as $key => $val) { $redis->sadd('group:programming', $val); }
代碼清單 1-10 get_group_articles 函數
function get_group_article($redis, $group, $page, $order = 'score:') { $key = $order.$group; // 爲每一個羣組的每種排列順序都建立一個鍵 if(! $redis->exists($key)) { // 檢查是否已有緩存的排序結果,若是沒有的話則進行排序 $redis->zInter($key, array('group:'.$group, $order), array(1, 1), $aggregate = 'max'); $redis->expire($key, 60); // 60s以後redis刪除有序集合 } return get_articles($redis, $page, $key); } $group = 'programming'; $page = isset($_GET['page']) ? $_GET['page'] : 1; $articles = get_group_article($redis, $group, $page); echo '<pre>'; print_r($articles);
附:
文章案例來自《Redis 實戰》
phpredis 文檔:https://github.com/phpredis/phpredis
Redis 命令參考:http://doc.redisfans.com/sorted_set/zrange.html
php-redis 中文文檔:http://www.cnblogs.com/weafer/archive/2011/09/21/2184059.html
redis在PHP中的基本使用案例:http://www.t086.com/article/4901