《Redis in Action》笔记(一)文章投票(1)初始化数据 + 投票 + 发布文章

原书用 Python 与 Redis 进行交互,我用 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 服务:

[[email protected] ~]# cd /usr/local/redis/
[[email protected] redis]# ./bin/redis-server ./etc/redis.conf
[[email protected] 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):

[[email protected] 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"

  

   

附:

文章案例来自《Redis 实战》

Redis 命令参考:http://doc.redisfans.com/sorted_set/zrange.html

php-redis 中文文档:http://www.cnblogs.com/weafer/archive/2011/09/21/2184059.html

时间: 2024-10-29 19:11:35

《Redis in Action》笔记(一)文章投票(1)初始化数据 + 投票 + 发布文章的相关文章

C++学习笔记17,构造函数体内初始化数据成员与构造函数初始化器的区别(一)

在构造体内初始化数据成员是最常见的方法. 例如: #include <iostream> using namespace std; class A { private: int i; string s; public: A(int ii,string ss){ //在构造函数体内初始化数据成员 i=ii; s=ss; cout<<"ctor:i="<<i<<",s="<<s<<endl; } /

Struts2 In Action笔记_页面到动作的数据流入和流出

因为回答百度知道的一个问题,仔细查看了<Struts2 In Action>,深入细致的看了 “数据转移OGNL 和 构建视图-标签”,很多东西才恍然大悟. 一直觉得国外写的书很浮,不具有操作性,但其实,Coding多了,才发现国外的书写的深刻.清晰.能传道解惑. 一.主要收获 1. Struts2 框架的数据流入和流出 使用 Struts2 标签时,所有非字符串属性都被当作 OGNL表达式进行解析. 使用  %{expression} 语法可以强制将字符串属性当作 OGNL表达式解析. 2.

mweb配置发布文章到博客园

这是一篇mweb自动发布的测试文章 转载一篇mweb配置发布文章到博客园的文章 http://www.cnblogs.com/scut-linmaojiang/p/mweb-test.html

Python + Selenium 自动发布文章(一):开源中国

https://blog.csdn.net/qq_28804275/article/details/80891949 https://blog.csdn.net/qq_28804275/article/details/80891949Python + Selenium 自动发布文章系列:Python + Selenium 自动发布文章(一):开源中国Python + Selenium 自动发布文章(二):简书Python + Selenium 自动发布文章(三):CSDNPython + Sel

Solr In Action 笔记(3) 之 SolrCloud基础

Solr In Action 笔记(3) 之 SolrCloud基础 在Solr中,一个索引的实例称之为Core,而在SolrCloud中,一个索引的实例称之为Shard:Shard 又分为leader和replica. 1. SolrCloud的特质 作为分布式搜索引擎的SolrCloud具有以下几个特质: 可扩展性 所谓的可扩展性就是指可以通过扩大集群的规模来实现性能的提升.有两种方式来实现可扩展性,一种是纵向扩展,即加快CPU速度,增加RAM,提升磁盘I/O性能等,另一种是横向扩展,就是分

Redis Essentials 读书笔记 - 第一章: Getting Started (The Baby Steps)

Chapter 1. Getting Started (The Baby Steps) Redis是在内存中运行的NoSQL key-value数据库. Redis的优势除了内存的高性能外,还有其支持丰富的数据类型,如Strings, Hashes, Lists, Sets, Sorted Sets, Bitmaps, 和 HyperLogLogs. Redis同时支持持久化,使用的技术为snapshotting 和 journaling. Redis表示REmote DIctionary Se

Redis Essentials 读书笔记 - 第九章: Redis Cluster and Redis Sentinel (Collective Intelligence)

Chapter 9. Redis Cluster and Redis Sentinel (Collective Intelligence) 上一章介绍了复制,一个master可以对应一个或多个slave(replica), 在以下的情况下是够用的: 1. master有足够内存容纳所有key 2. 通过slave可以扩展读,解决网络吞吐量的问题 3. 允许停止master的维护窗口时间 4. 通过slave做数据冗余 但复制解决不了自动failover和自动resharding的问题,在以下的情

Solr In Action 笔记(2) 之 评分机制(相似性计算)

Solr In Action 笔记(2) 之评分机制(相似性计算) 1 简述 <这就是搜索引擎>里面对相似性计算进行了简单的介绍. 内容的相似性计算由搜索引擎的检索模型建模,它是搜索引擎的理论基础,为量化相关性提供了一种数学模型,否则没法计算.当然检索模型理论研究存在理想化的隐含假设,即假设用户需求已经通过查询非常清晰明确地表达出来了,所以检索模型的任务不牵扯到对用户需求建模,但实际上这个和实际相差较远,即使相同的查询词,不同用户的需求目的可能差异很大,而检索模型对此无能为力.几种常见的检索模

Solr In Action 笔记(4) 之 SolrCloud分布式索引基础

Solr In Action 笔记(4) 之 SolrCloud Index 基础 SolrCloud Index流程研究了两天,还是没有完全搞懂,先简单记下基础的知识,过几天再写个深入点的.先补充上前文来不及写的内容. 1. Solr.xml的重要配置 Solr.xml的内容如下: 1 <solr> 2 <solrcloud> 3 <str name="host">${host:}</str> 4 <int name="