《Redis in Action》笔记文章投票初始化数据 + 投票 + 发布文章
Posted Meadows of Heaven
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Redis in Action》笔记文章投票初始化数据 + 投票 + 发布文章相关的知识,希望对你有一定的参考价值。
原书用 Python 与 Redis 进行交互,我用 php 来实现。
首先在 Linux 开启 Redis 服务:
[root@localhost ~]# cd /usr/local/redis/ [root@localhost redis]# ./bin/redis-server ./etc/redis.conf [root@localhost redis]# ps aux|grep redis
如果显示:
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
redis.php
<?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):
[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):
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
以上是关于《Redis in Action》笔记文章投票初始化数据 + 投票 + 发布文章的主要内容,如果未能解决你的问题,请参考以下文章