網(wǎng)站首頁 編程語言 正文
場景說明
今天我們來模擬一個這樣的場景,我們在本地有多個文本文件,每個文件里面存了很多的32位的字符串作為用戶的唯一標識,每個用戶存做一行,假如我們每天都有非常大規(guī)模的用戶,這樣我們可能在工作中就存在需要對這些用戶進行交集、并集或補集等處理,最簡單的方式是通過Java中的集合來進行運算即可,比如通過HashSet來進行相應的一些運算,但是這樣的運算存在一個局限性,那就是我們一般在JVM運行過程中初始的內(nèi)存是有限的,這樣如果全部在JVM內(nèi)存中進行計算的話,很容易出現(xiàn)內(nèi)存空間不足導致的OOM異常,那么我們今天來介紹一種拓展性更強的方式來進行這樣的一些交并補的運算:通過Redis來實現(xiàn)數(shù)據(jù)的交集、并集、補集
環(huán)境說明
- Redis版本: Redis 6.0.6
- Jedis版本: 4.2.2
- 工具類hutool版本: 5.8.0.M3
pom文件:
<dependencies> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>redis.clients</groupId> ? ? ? ? ? ? <artifactId>jedis</artifactId> ? ? ? ? ? ? <version>4.2.2</version> ? ? ? ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>cn.hutool</groupId> ? ? ? ? ? ? <artifactId>hutool-all</artifactId> ? ? ? ? ? ? <version>5.8.0.M3</version> ? ? ? ? </dependency> </dependencies>
交并補計算
初始化常量
public class RedisCalculateUtils {
? ? static String oneFileString = "/Users/tmp/test-1.txt";
? ? static String twoFileString = "/Users/tmp/test-2.txt";
? ? static String diffFileString = "/Users/tmp/diff-test.txt";
? ? static String interFileString = "/Users/tmp/inter-test.txt";
? ? static String unionFileString = "/Users/tmp/union-test.txt";
? ? static String oneFileCacheKey = "oneFile";
? ? static String twoFileCacheKey = "twoFile";
? ? static String diffFileCacheKey = "diffFile";
? ? static String interFileCacheKey = "interFile";
? ? static String unionFileCacheKey = "unionFile";
}
初始化數(shù)據(jù)到指定文件
/**
* 初始化數(shù)據(jù)并寫入文件中
*/
public static void writeFile() {
? ? ? ? File oneFile = new File(oneFileString);
? ? ? ? List<String> fs = new ArrayList<>(10000);
? ? ? ? for (int i = 10000; i < 15000; i++) {
? ? ? ? ? ? String s = SecureUtil.md5(String.valueOf(i));
? ? ? ? ? ? fs.add(s);
? ? ? ? }
? ? ? ? FileUtil.writeUtf8Lines(fs, oneFile);
? ? ? ? File twoFile = new File(twoFileString);
? ? ? ? fs.clear();
? ? ? ? for (int i = 12000; i < 20000; i++) {
? ? ? ? ? ? String s = SecureUtil.md5(String.valueOf(i));
? ? ? ? ? ? fs.add(s);
? ? ? ? }
? ? ? ? FileUtil.writeUtf8Lines(fs, twoFile);
? ? }
指定文件寫入Redis
/**
* 讀取文件數(shù)據(jù)并寫入Redis
*/
public static void writeCache() {
? ? try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
? ? ? ? Pipeline p = jedis.pipelined();
? ? ? ? List<String> oneFileStringList = FileUtil.readLines(oneFileString, "UTF-8");
? ? ? ? for (String s : oneFileStringList) {
? ? ? ? ? ? p.sadd(oneFileCacheKey, s);
? ? ? ? }
? ? ? ? p.sync();
? ? ? ? List<String> twoFileStringList = FileUtil.readLines(twoFileString, "UTF-8");
? ? ? ? for (String s : twoFileStringList) {
? ? ? ? ? ? p.sadd(twoFileCacheKey, s);
? ? ? ? }
? ? ? ? p.sync();
? ? } catch (Exception e) {
? ? ? ? throw new RuntimeException(e);
? ? }
}
差集的計算
? ? /**
? ? ?* oneKey對應的Set 與 twoKey對應的Set 的差集 并寫入 threeKey
? ? ?* @param oneKey 差集前面的集合Key
? ? ?* @param twoKey 差集后面的集合Key
? ? ?* @param threeKey 差集結(jié)果的集合Key
? ? ?*/
? ? public static void diff(String oneKey, String twoKey, String threeKey) {
? ? ? ? try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
? ? ? ? ? ? long result = jedis.sdiffstore(threeKey, oneKey, twoKey);
? ? ? ? ? ? System.out.println("oneKey 與 twoKey 的差集的個數(shù):" + result);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
? ? }
差集計算結(jié)果寫入到指定文件
? ? /**
? ? ?* 將計算的差集數(shù)據(jù)寫入到指定文件
? ? ?*/
? ? public static void writeDiffToFile() {
? ? ? ? File diffFile = new File(diffFileString);
? ? ? ? try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
? ? ? ? ? ? Set<String> result = jedis.smembers(diffFileCacheKey);
? ? ? ? ? ? FileUtil.writeUtf8Lines(result, diffFile);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
? ? }
交集的計算
/**
? ? ?*
? ? ?* @param cacheKeyArray 交集集合Key
? ? ?* @param destinationKey 交集集合結(jié)果Key
? ? ?*/
? ? public static void inter(String[] cacheKeyArray, String destinationKey) {
? ? ? ? try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
? ? ? ? ? ? long result = jedis.sinterstore(destinationKey, cacheKeyArray);
? ? ? ? ? ? System.out.println("cacheKeyArray 的交集的個數(shù):" + result);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
? ? }
交集計算結(jié)果寫入指定文件
/**
* 將計算的交集數(shù)據(jù)寫入到指定文件
*/
public static void writeInterToFile() {
File interFile = new File(interFileString);
try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
Set<String> result = jedis.smembers(interFileCacheKey);
FileUtil.writeUtf8Lines(result, interFile);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
并集的計算
? ? /**
? ? ?* 計算多個Key的并集并寫入到新的Key
? ? ?* @param cacheKeyArray 求并集的Key
? ? ?* @param destinationKey 并集結(jié)果寫入的KEY
? ? ?*/
? ? ?public static void union(String[] cacheKeyArray, String destinationKey) {
? ? ? ? ?try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
? ? ? ? ? ? ?long result = jedis.sunionstore(destinationKey, cacheKeyArray);
? ? ? ? ? ? ?System.out.println("cacheKeyArray 的并集的個數(shù):" + result);
? ? ? ? ?} catch (Exception e) {
? ? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ? ?}
? ? ?}
并集計算結(jié)果寫入到指定文件
/**
* 將計算的并集數(shù)據(jù)寫入到指定文件
*/
public static void writeUnionToFile() {
File unionFile = new File(unionFileString);
try(Jedis jedis = new Jedis("127.0.0.1", 6379)) {
Set<String> result = jedis.smembers(unionFileCacheKey);
FileUtil.writeUtf8Lines(result, unionFile);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Redis命令說明
SDIFFSTORE destination key [key …]
舉例說明:
key1 = {a,b,c,d}
key2 = {c}
key3 = {a,c,e}
SDIFF key1 key2 key3 = {b,d}
SDIFFSTORE 命令的作用和SDIFF類似,不同的是它將結(jié)果保存到 destination 集合,而把結(jié)果集返回給客戶端。
如果 destination 集合已經(jīng)存在,則將其覆蓋。
返回值
- 結(jié)果集中成員數(shù)量
SINTERSTORE destination key [key …]
舉例說明:
key1 = {a,b,c,d}
key2 = {c}
key3 = {a,c,e}
SINTER key1 key2 key3 = {c}
SINTERSTORE 命令與 SINTER 命令類似,不同的是它并不是直接返回結(jié)果集,而是將結(jié)果保存在 destination 集合中。
如果 destination 集合存在, 則會被覆蓋。
返回值
- 結(jié)果集中成員數(shù)量
SUNIONSTORE destination key [key …]
舉例說明:
key1 = {a,b,c,d}
key2 = {c}
key3 = {a,c,e}
SUNION key1 key2 key3 = {a,b,c,d,e}
SUNIONSTORE 命令的功能類似于 SUNION,不同的是不反回結(jié)果集,而是存儲在 destination 中。
如果 destination 已經(jīng)存在,則被覆蓋。
返回值
- 結(jié)果集中的成員數(shù)量
參考資料: https://www.redis.com.cn/set.html
原文鏈接:https://blog.csdn.net/zhangzehai2234/article/details/124784284
相關推薦
- 2023-07-24 uniapp開發(fā)小程序,包過大解決方案
- 2023-04-27 c++中關于max_element()函數(shù)解讀_C 語言
- 2021-12-06 C語言PlaySound函數(shù)使用方法_C 語言
- 2022-09-08 pytest實現(xiàn)多進程與多線程運行超好用的插件_python
- 2022-07-18 iptables防火墻
- 2022-06-29 一文教會你使用Nginx訪問日志統(tǒng)計PV與UV_nginx
- 2022-09-17 C++?中如何結(jié)束?while?(cin>>str)?的輸入_C 語言
- 2022-03-29 C#算法之兩數(shù)之和_C#教程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支