Redis-08Redis数据结构--基数HyperLogLog
文章目錄
- 概述
- Redis 的 Hyperloglog 命令
- Spring 中操作基數
- 注意
- 代碼
概述
基數是一種算法。
舉個例子 , 一本英文著作由數百萬個單詞組成,你的內存卻不足以存儲它們,那么我們先分析一下業務。英文單詞本身是有限的,在這本書的幾百萬個單詞中有許許多多重復單詞 ,扣去重復的單詞,這本書中也就是幾千到一萬多個單詞而己,那么內存就足夠存儲它們 了。比如數字集合{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 中 | ---- |
分析一下邏輯,首先往一個鍵為 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.xsdhttp://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 接口進行操作 。
代碼
代碼托管到了 https://github.com/yangshangwei/redis_learn
總結
以上是生活随笔為你收集整理的Redis-08Redis数据结构--基数HyperLogLog的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis-07Redis数据结构--有
- 下一篇: Redis-09Redis的基础事务