跟我一起数据挖掘(21)——redis

什么是Redis

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

Memcached和Redis

Memcached的基本应用模型如下图所示:

redis使用与其相同,将memcached改为redis即可。

Redis支持的数据类型

字符串(Strings)

字符串是Redis值的最基础的类型。Redis字符串是二进制安全的,这意味着一个Redis字符串可以包含任何种类的数据,例如一个JPEG图像或者一个序列化的Ruby对象。 一个字符串值最多可以保存512M字节的内容。 你可以使用Redis的字符串做一些有趣的事情,例如你可以:

  • 在使用命令INCR系列( INCR, DECR, INCRBY)命令时将字符串作为的原子计数器。
  • 使用APPEND命令追加字符串。
  • 将字符串作为GETRANGE 和 SETRANGE的随机访问向量。
  • 在小空间里编码大量数据, 或者使用 GETBIT 和 SETBIT创建一个Redis支持的Bloom过滤器。

列表(Lists)

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边) LPUSH 命令插入一个新的元素导头部, 而 RPUSH插入一个新元素导尾部.当一个这两个操作在一个空的Key上被执行的时候一个新的列表被创建。相似的,如果一个列表操作清空一个列表那么对应的key将被从key空间删除。这是非常方便的语义,因为他们被调用使用一个空列表完全就像他们被调用时使用一个不存在的键值(可以)做为参数。 一些类表操作和结果的例子:

LPUSH mylist a   # 现在类表中是 "a"

LPUSH mylist b   # 现在列表中是 "b","a"

RPUSH mylist c   # 现在类表中是 "b","a","c" (这次RPUSH被使用)

一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。 从时间复杂度的角度来看Redis列表的主要特征是在头和尾的元素插入和删除是固定时间,即便是数以百万计的插入。. 在列表的两端访问元素是非常快的但是如果你试着访问一个非常大的列表的中间的元素是很慢的,因为那是一个O(N)操作。 你可以用Redis列表做很多有趣的事情,比如你可以:

  • 在一个社交网络中建立一个时间线模型,使用LPUSH 去添加新的元素到用户的时间线, 使用LRANGE去接收一些最近插入的元素。
  • 你可以将 LPUSH 和 LTRIM 一起用去创建一个永远也不会超过指定元素数目的列表,但是记住是最后的N个元素。
  • 列表能够被用来作为消息传递primitive[译注:不清楚表达的意思], 例如众所周知的用来创建后台工作的Resque Ruby库.
  • 你可以使用列表做更多的事,这个数据类型支持许多命令,包括像BLPOP这样的阻塞命令。

集合(Sets)

Redis 集合(Set)是一个无序的字符串集合. 你可以以O(1)的时间复杂度 (无论集合中有多少元素时间复杂度都是常量)完成添加,删除,以及测试元素是否存在。 Redis 集合拥有令人满意的不允许包含相同成员的属性。多次添加相同的元素,最终在集合里只会有一个元素。 实际上说这些就是意味着在添加元素的时候无须检测元素是否存在。 一个Redis集合的非常有趣的事情是他支持一些服务端的命令从现有的集合出发去进行集合运算,因此你可以在非常短的时间内进行合并(unions), 求交集(intersections),找出不同的元素(differences of sets)。 一个集合最多可以包含 232 - 1 个元素(4294967295, 每个集合超过40一个元素). 你可以使用集合多很多有趣的事情,比如你能够:

  • 你可以使用集合追踪一件(独一无二的)事情,想要知道所有访问一个博客文章的独立IP? 每次当你处理一个页面访问的事简单的使用SADD。你可以肯定重复的IP是不会被插入的。
  • Redis 集合是很擅长表现关系的。你可以使用Redis集合创建一个tagging系统去表现每一个tag。接下来你能够使用SADD命令将有一个给定tag的所有对象的所有ID添加到一个用来展现这个特定tag的集合里。你想要同时有三个不同tag的所有对象的ID吗?使用SINTER就好了。
  • 使用 SPOP 或者 SRANDMEMBER 命令你可以使用集合去随意的抽取元素。

哈希(Hashes)

Redis Hashes是字符串字段和字符串值之间的映射,因此他们是展现对象的完美数据类型。 (例如:一个有名,姓,年龄等等属性的用户):

@cli

HMSET user:1000 username antirez password P1pp0 age 34

HGETALL user:1000

HSET user:1000 password 12345

HGETALL user:1000

一个带有一些字段(这里的一些意味着高达一百左右)的hash仅仅需要一块很小的空间存储,因此你可以存储数以百万计的对象在一个小的Redis实例中。 哈希主要用来表现对象,他们有能力存储很多对象,因此你可以将哈希用于许多其他的任务。 每一个哈希可以存储超过232 - 1 字段-值 对 (超过40亿).

有序集合(Sorted Sets)

Redis有序集合与普通集合非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的没有成员都关联了一个评分,这个评分被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了。 使用有序集合你可以以非常快的速度(O(log(N)))添加,删除和更新元素。因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。在有序集合中,你可以很快捷的访问一切你需要的东西:有序的元素,快速的存在性测试,快速访问集合的中间元素! 简而言之使用有序集合你可以做完成许多对性能有极端要求的任务,而那些任务使用其他类型的数据库真的是很难完成的。 使用有序集合你可以:

  • 在一个大型的在线游戏中展示一个排行榜,在那里一旦一个新的分数被提交,你可以使用ZADD命令去更新它.你也可用使用 ZRANGE命令来得到顶级的用户,你还可以使用ZRANK命令根据用户名返回该用户在排行榜中的位次。同时使用ZRANK 和 ZRANGE 你可以显示和给定用户分数相同的所有用户。所有这些操作都非常的快速。
  • 有序集合常常被用来索引存储在Redis中的数据。举个例子,如果你有许多的哈希(Hashes)来代表用户,你可以使用一个有序集合,这个集合中的元素的年龄字段被用来当做评分,而ID作为值。因此,使用 ZRANGEBYSCORE 命令,那是微不足道的并且能够很快的接收到给定年龄段的所有用户。

centos安装redis

wget http://download.redis.io/redis-stable.tar.gz

tar xvzf redis-stable.tar.gz

cd redis-stable

make

前面3步应该没有问题,主要的问题是执行make的时候,出现了异常。

异常一:

make[2]: cc: Command not found

异常原因:没有安装gcc

解决方案:yum install gcc-c++

异常二:

zmalloc.h:51:31: error: jemalloc/jemalloc.h: No such file or directory

异常原因:一些编译依赖或原来编译遗留出现的问题

解决方案:make distclean。清理一下,然后再make。

在make成功以后,需要make test。在make test出现异常。

异常一:

couldn‘t execute "tclsh8.5": no such file or directory

异常原因:没有安装tcl

解决方案:yum install -y tcl。

在make成功以后,会在src目录下多出一些可执行文件:redis-server,redis-cli等等。

方便期间用cp命令复制到usr目录下运行。

cp redis-server /usr/local/bin/

cp redis-cli /usr/local/bin/

然后新建目录,存放配置文件

mkdir /etc/redis

mkdir /var/redis

mkdir /var/redis/log

mkdir /var/redis/run

mkdir /var/redis/6379

在redis解压根目录中找到配置文件模板,复制到如下位置。

cp redis.conf /etc/redis/6379.conf

通过vim命令修改

daemonize yes

pidfile /var/redis/run/redis_6379.pid

logfile /var/redis/log/redis_6379.log

dir /var/redis/6379

最后运行redis:

$ redis-server /etc/redis/6379.conf

使用Jedis操作Redis

使用Java操作Redis需要jedis-2.1.0.jar,下载地址:http://files.cnblogs.com/liuling/jedis-2.1.0.jar.zip

如果需要使用Redis连接池的话,还需commons-pool-1.5.4.jar,下载地址:http://files.cnblogs.com/liuling/commons-pool-1.5.4.jar.zip

也可以使用maven引入:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.0.0</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>
package com.test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import redis.clients.jedis.Jedis;

public class TestRedis {
    private Jedis jedis; 

    @Before
    public void setup() {
        //连接redis服务器,192.168.0.100:6379
        jedis = new Jedis("192.168.0.100", 6379);
        //权限认证
        jedis.auth("admin");
    }

    /**
     * redis存储字符串
     */
    @Test
    public void testString() {
        //-----添加数据----------
        jedis.set("name","xinxin");//向key-->name中放入了value-->xinxin
        System.out.println(jedis.get("name"));//执行结果:xinxin  

        jedis.append("name", " is my lover"); //拼接
        System.out.println(jedis.get("name")); 

        jedis.del("name");  //删除某个键
        System.out.println(jedis.get("name"));
        //设置多个键值对
        jedis.mset("name","liuling","age","23","qq","476777389");
        jedis.incr("age"); //进行加1操作
        System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));

    }

    /**
     * redis操作Map
     */
    @Test
    public void testMap() {
        //-----添加数据----------
        Map<String, String> map = new HashMap<String, String>();
        map.put("name", "xinxin");
        map.put("age", "22");
        map.put("qq", "123456");
        jedis.hmset("user",map);
        //取出user中的name,执行结果:[minxr]-->注意结果是一个泛型的List
        //第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变参数
        List<String> rsmap = jedis.hmget("user", "name", "age", "qq");
        System.out.println(rsmap);  

        //删除map中的某个键值
        jedis.hdel("user","age");
        System.out.println(jedis.hmget("user", "age")); //因为删除了,所以返回的是null
        System.out.println(jedis.hlen("user")); //返回key为user的键中存放的值的个数2
        System.out.println(jedis.exists("user"));//是否存在key为user的记录 返回true
        System.out.println(jedis.hkeys("user"));//返回map对象中的所有key
        System.out.println(jedis.hvals("user"));//返回map对象中的所有value 

        Iterator<String> iter=jedis.hkeys("user").iterator();
        while (iter.hasNext()){
            String key = iter.next();
            System.out.println(key+":"+jedis.hmget("user",key));
        }
    }

    /**
     * jedis操作List
     */
    @Test
    public void testList(){
        //开始前,先移除所有的内容
        jedis.del("java framework");
        System.out.println(jedis.lrange("java framework",0,-1));
        //先向key java framework中存放三条数据
        jedis.lpush("java framework","spring");
        jedis.lpush("java framework","struts");
        jedis.lpush("java framework","hibernate");
        //再取出所有数据jedis.lrange是按范围取出,
        // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
        System.out.println(jedis.lrange("java framework",0,-1));  

        jedis.del("java framework");
        jedis.rpush("java framework","spring");
        jedis.rpush("java framework","struts");
        jedis.rpush("java framework","hibernate");
        System.out.println(jedis.lrange("java framework",0,-1));
    }  

    /**
     * jedis操作Set
     */
    @Test
    public void testSet(){
        //添加
        jedis.sadd("user","liuling");
        jedis.sadd("user","xinxin");
        jedis.sadd("user","ling");
        jedis.sadd("user","zhangxinxin");
        jedis.sadd("user","who");
        //移除noname
        jedis.srem("user","who");
        System.out.println(jedis.smembers("user"));//获取所有加入的value
        System.out.println(jedis.sismember("user", "who"));//判断 who 是否是user集合的元素
        System.out.println(jedis.srandmember("user"));
        System.out.println(jedis.scard("user"));//返回集合的元素个数
    }  

    @Test
    public void test() throws InterruptedException {
        //jedis 排序
        //注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的)
        jedis.del("a");//先清除数据,再加入数据进行测试
        jedis.rpush("a", "1");
        jedis.lpush("a","6");
        jedis.lpush("a","3");
        jedis.lpush("a","9");
        System.out.println(jedis.lrange("a",0,-1));// [9, 3, 6, 1]
        System.out.println(jedis.sort("a")); //[1, 3, 6, 9]  //输入排序后结果
        System.out.println(jedis.lrange("a",0,-1));
    }  

    @Test
    public void testRedisPool() {
        RedisUtil.getJedis().set("newname", "中文测试");
        System.out.println(RedisUtil.getJedis().get("newname"));
    }
}

Redis连接池:

package com.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public final class RedisUtil {

    //Redis服务器IP
    private static String ADDR = "192.168.0.100";

    //Redis的端口号
    private static int PORT = 6379;

    //访问密码
    private static String AUTH = "admin";

    //可用连接实例的最大数目,默认值为8;
    //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
    private static int MAX_ACTIVE = 1024;

    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
    private static int MAX_IDLE = 200;

    //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
    private static int MAX_WAIT = 10000;

    private static int TIMEOUT = 10000;

    //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
    private static boolean TEST_ON_BORROW = true;

    private static JedisPool jedisPool = null;

    /**
     * 初始化Redis连接池
     */
    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxActive(MAX_ACTIVE);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWait(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Jedis实例
     * @return
     */
    public synchronized static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                Jedis resource = jedisPool.getResource();
                return resource;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放jedis资源
     * @param jedis
     */
    public static void returnResource(final Jedis jedis) {
        if (jedis != null) {
            jedisPool.returnResource(jedis);
        }
    }
}

总结

在使用缓存的时候,redis比memcached具有更多的优势,并且支持更多的数据类型。

时间: 2024-10-03 23:29:13

跟我一起数据挖掘(21)——redis的相关文章

SylixOS移植Redis库总结

1. Redis简介 Redis是一个开源软件项目(BSD许可),用ANSI C编写,适用于大多数的POSIX系统,是一个可用作数据库.缓存和消息代理的内存数据库.Redis是一个非关系型数据库,Redis可以存储键与五种不同数据结构类型之间的映射,这五种类型分别为:字符串.列表.集合.有序集合和散列.Redis通常将整个数据集保存在内存中,Redis通过两种不同的方式实现持久性:一种是快照,另一种是AOF(AppendOnly File).Redis支持主从复制,来自任何Redis服务器的数据

RedisRepository封装—Redis发布订阅以及StackExchange.Redis中的使用

本文版权归博客园和作者本人吴双共同所有,转载请注明本Redis系列分享地址.http://www.cnblogs.com/tdws/tag/NoSql/ Redis Pub/Sub模式 基本介绍 Redis发布订阅—Pub/Sub模式或者说是观察者模式.我想大家即使没有使用过,也已经耳熟能详了. 先简单举例说明下应用场景,在场景中我们可以分析到其优势在哪. 比如你的线上应用应用,你想设置一个日志报警系统,当应用出现异常的时候,立马发送通知给你,可能是短信的形式,也可能是邮件的形式.当然如果只将报

redis笔记(一)-string数据类型

一.概述: 字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中字符串类型的Value最多可以容纳的数据长度是512M. 二.相关命令列表: 命令原型                                            时间复杂度             返回值 命令描述 APPEND key value O(1) 追加后Value的长度 如果该Key已

Redis教程(二):String数据类型

转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/131.html?1455808279 一.概述: 字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中字符串类型的Value最多可以容纳的数据长度是512M. 二.相关命令列表: 命令原型 时间复杂度 命令描述 返回值 APPENDkeyvalue

redis学习(二)——String数据类型

一.概述 字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中字符串类型的Value最多可以容纳的数据长度是512M. 二.相关命令 1.赋值命令 命令原型:SET key value 时间复杂度:O(1) 命令描述:设定该Key持有指定的字符串Value,如果该Key已经存在,则覆盖其原有值. 返回值:总是返回"OK". 2.取值命令 命令原型:GET key

redis数据类型——string

string不是String 概述: 字符串类型是Redis中最为基础的数据存储类型,该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等. 在Redis中字符串类型的Value最多可以容纳的数据长度是512M. 二.相关命令列表: 命令原型 时间复杂度 命令描述 返回值 APPENDkey value O(1) 如果该Key已经存在,APPEND命令将参数Value的数据追加到已存在Value的末尾.如果该Key不存在,APPEND命令将会创建一个新的Key/Value.

redis命令详解与使用场景举例——String

APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾. 如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样. 可用版本: 2.0.0+ 时间复杂度: 平摊O(1) 返回值: 追加 value 之后, key 中字符串的长度. 对不存在的 key 执行 APPEND redis> EXISTS myphone # 确保 myphone 不

mybatis+redis实现二级缓存

在网上看了很多资料,发现例子都是千篇一律的相互复制.而且,使用的都是jedis的客户端..我这里使用的是redistemplate类实现. 缓存的原理..实现cache类接口,当哪个类需要缓存的时候,就直接将cache标签引入,并且制定我们的缓存类就可以了. 上代码: 1.引入spring-data-redis 1 <!-- redis服务 start--> 2 <dependency> 3 <groupId>org.springframework.data</g

C#中使用Redis学习二 在.NET4.5中使用redis hash操作

C#中使用REDIS学习一 WINDOWS安装REDIS服务器端和客户端 http://www.tuicool.com/articles/uMb2Yjz 摘要 上一篇讲述了安装redis客户端和服务器端,也大体地介绍了一下redis.本篇着重讲解.NET4.0 和 .NET4.5中如何使用redis和C# redis操作哈希表.并且会将封装的一些代码贴一下.在讲解的过程中,我打算结合redis操作命令一起叙述,算是作为对比吧.这样也能让读者清楚了 解,所分装的代码对应的redis的哪一些操作命令

supervisor 启动redis服务

redis 服务很多人都在用 先看如何安装redis.下面是从官网拿来的,不多讲. $ wget http://download.redis.io/releases/redis-3.0.3.tar.gz $ tar xzf redis-3.0.3.tar.gz $ cd redis-3.0.3 $ make src/redis-server $ src/redis-cli redis> set foo bar OK redis> get foo "bar" 默认的配置文件r