Redis-08Redis数据结构--基数HyperLogLog
概述
基数是一种算法。
举个例子 , 一本英文著作由数百万个单词组成,你的内存却不足以存储它们,那么我们先分析一下业务。英文单词本身是有限的,在这本书的几百万个单词中有许许多多重复单词 ,扣去重复的单词,这本书中也就是几千到一万多个单词而己,那么内存就足够存储它们 了。比如数字集合{1,2,5,7,9, 1,5,9 }的基数集合为{ 1,2,5,7,9}那么基数(不重复元素)就是 5 , 基数的作用是评估大约需要准备多少个存储单元去存储数据,但是基数的算法一般会存在一定的误差(一般是可控的)。
Redis 对基数数据结构的支持是从版本 2.8.9 开始的。
基数并不是存储元素,存储元素消耗内存空间比较大,而是给某一个有重复元素的数据集合( 一般是很大的数据集合〉评估需要的空间单元数,所以它没有办法进行存储 ,加上在工作中用得不多 ,所以简要介绍一下 Redis的HyperLogLog 命令就可以了.
Redis 的 Hyperloglog 命令
官网:https://redis.io/commands#hyperloglog
命令 | 说明 | 备注 |
---|---|---|
pfadd key element | 添加指定元素到 HyperLogLog 中 | 如果已经存储元素,则返回为 0,添加失败 |
pfcount key | 返回 HyperLogLog 的基数值 | ---- |
pfmerge desKey key1 [key2 key3 …] | 合并多个 HyperLogLog,并将其保存在 desKey 中 | ---- |
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> PFADD h1 a
(integer) 1
127.0.0.1:6379> PFADD h1 b
(integer) 1
127.0.0.1:6379> PFADD h1 c
(integer) 1
127.0.0.1:6379> PFADD h1 d
(integer) 1
127.0.0.1:6379> PFADD h1 a
(integer) 0
127.0.0.1:6379> PFADD h2 a
(integer) 1
127.0.0.1:6379> PFADD h2 z
(integer) 1
127.0.0.1:6379> PFMERGE h3 h1 h2
OK
127.0.0.1:6379> PFCOUNT h3
(integer) 5
127.0.0.1:6379>
分析一下逻辑,首先往一个键为 h1的 HyperLogLog 插入元素 ,让其计算基数,到 了第 5 个命令“ pfadd h1 a”的时候,由于在此以前已经添加过,所以返回了 0。 它 的基数集合是{a,b,c,d},因此求集合长度是4 。
之后再添加第二个基数h2,它的基数是{a,z},所以在合并h1和h2到h3中的时候,它的基数和为{a,b,c,d,z}。所以求它的基数是5.
Spring 中操作基数
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:redis/redis.properties" />
<!--2,注意新版本2.3以后,JedisPoolConfig的property name,不是maxActive而是maxTotal,而且没有maxWait属性,建议看一下Jedis源码或百度。 -->
<!-- redis连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--最大空闲数 -->
<property name="maxIdle" value="${redis.maxIdle}" />
<!--连接池的最大数据库连接数 -->
<property name="maxTotal" value="${redis.maxTotal}" />
<!--最大建立连接等待时间 -->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
<!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟) -->
<property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
<!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 -->
<property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
<!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 -->
<property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
<property name="testOnBorrow" value="true"></property>
<property name="testOnReturn" value="true"></property>
<property name="testWhileIdle" value="true"></property>
</bean>
<!--redis连接工厂 -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<!--IP地址 -->
<property name="hostName" value="${redis.host.ip}"></property>
<!--端口号 -->
<property name="port" value="${redis.port}"></property>
<!--如果Redis设置有密码 -->
<property name="password" value="${redis.password}" />
<!--客户端超时时间单位是毫秒 -->
<property name="timeout" value="${redis.timeout}"></property>
<property name="usePool" value="true" />
<!--<property name="database" value="0" /> -->
</bean>
<!-- 键值序列化器设置为String 类型 -->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory"
p:keySerializer-ref="stringRedisSerializer"
p:defaultSerializer-ref="stringRedisSerializer"
p:valueSerializer-ref="stringRedisSerializer">
</bean>
</beans>
package com.artisan.redis.baseStructure.hyperloglgo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
public class SpringRedisHyperLogLogDemo {
@SuppressWarnings({ "unchecked", "rawtypes", "resource" })
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis-hyperloglog.xml");
RedisTemplate redisTemplate = (RedisTemplate) ctx.getBean("redisTemplate");
// 为确保数据干净,先清除
redisTemplate.delete("h1");
redisTemplate.delete("h2");
redisTemplate.delete("h3");
// 添加指定元素到 HyperLogLog 中
Long count = redisTemplate.opsForHyperLogLog().add("h1", "a", "b", "c", "d", "a");
System.out.println(count);
count = redisTemplate.opsForHyperLogLog().add("h2", "a");
System.out.println(count);
count = redisTemplate.opsForHyperLogLog().add("h2", "z");
System.out.println(count);
Long size = redisTemplate.opsForHyperLogLog().size("h1");
System.out.println(size);
Long size2 = redisTemplate.opsForHyperLogLog().size("h2");
System.out.println(size2);
Long size3 = redisTemplate.opsForHyperLogLog().union("h3", "h1", "h2");
System.out.println(size3);
Long size4 = redisTemplate.opsForHyperLogLog().size("h3");
System.out.println(size4);
}
}
输出
INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@73a8dfcc: startup date [Thu Sep 27 00:11:19 CST 2018]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [spring/spring-redis-hyperloglog.xml]
1
1
1
4
2
5
5
注意
使用 Spring 提供的 RedisTemplate 去展示多个命令可以学习到如何使用 RedisTemplate 操作 Redis 。 实际工作中并不是那么用的,因为每一 个操作会尝试从连接池里获取 一 个新的 Redis 连接,多个命令应该使用SessionCallback 接口进行操作 。
代码
下一篇: 好吃的零食品牌有哪些?
推荐阅读
-
Python数据结构与算法之常见的分配排序法示例【桶排序与基数排序】
-
Redis(十)——HyperLogLog 基数统计和 Bitmap位图场景详解
-
Redis学习手册6—数据结构之HyperLogLog
-
Redis源码剖析--基数统计hyperloglog
-
仿redis的HyperLogLog数据结构
-
Redis-08Redis数据结构--基数HyperLogLog
-
使用HyperLogLog 数据结构进行估数(JAVA)
-
java使用jeids实现redis2.6的HyperLogLog数据结构的操作
-
【Redis】Redis 高级数据结构 - bitmap 和 hyperLogLog
-
redis数据结构HyperLogLog