golang redis zset合并数据集

举报
鱼弦 发表于 2025/06/19 11:19:45 2025/06/19
【摘要】 在 Go 中使用 Redis 将所有以 event_ 开头的 ZSET(有序集合)合并到 event_4 这个 ZSET 中,可以使用 ​​Redis 的 ZUNIONSTORE​​ 命令。​​步骤​​​​获取所有以 event_ 开头的 ZSET key​​(使用 KEYS 或 SCAN)。​​使用 ZUNIONSTORE 将这些 ZSET 合并到 event_4​​(event_4 可以...

在 Go 中使用 Redis 将所有以 event_ 开头的 ZSET(有序集合)合并到 event_4 这个 ZSET 中,可以使用 ​​Redis 的 ZUNIONSTORE​ 命令。

​步骤​

  1. ​获取所有以 event_ 开头的 ZSET key​​(使用 KEYSSCAN)。
  2. ​使用 ZUNIONSTORE 将这些 ZSET 合并到 event_4​(event_4 可以是一个已存在的 ZSET,也可以是新创建的)。

​1. 使用 KEYS 获取所有 event_ 开头的 ZSET key(不推荐生产环境使用)​

KEYS 命令会阻塞 Redis,​​不推荐在生产环境使用​​,仅适用于测试或小规模数据。

​Go 代码示例​

package main

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
)

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379", // Redis 地址
	})

	ctx := context.Background()

	// 1. 获取所有以 "event_" 开头的 key
	keys, err := rdb.Keys(ctx, "event_*").Result()
	if err != nil {
		panic(err)
	}

	// 2. 过滤出 ZSET 类型的 key(可选,确保 key 是 ZSET)
	var zsetKeys []string
	for _, key := range keys {
		keyType, err := rdb.Type(ctx, key).Result()
		if err != nil {
			panic(err)
		}
		if keyType == "zset" {
			zsetKeys = append(zsetKeys, key)
		}
	}

	// 3. 如果没有符合条件的 ZSET,直接返回
	if len(zsetKeys) == 0 {
		fmt.Println("没有找到以 'event_' 开头的 ZSET")
		return
	}

	// 4. 使用 ZUNIONSTORE 合并到 event_4
	// 参数:destinationKey, numKeys, sourceKeys...
	err = rdb.ZUnionStore(ctx, "event_4", redis.ZStore{
		Weights: nil, // 默认权重 1
	}, zsetKeys...).Err()
	if err != nil {
		panic(err)
	}

	fmt.Printf("成功合并 %d 个 ZSET 到 event_4\n", len(zsetKeys))
}

​2. 使用 SCAN 获取所有 event_ 开头的 ZSET key(推荐生产环境使用)​

SCAN 是 ​​非阻塞​​ 的,适合生产环境使用,避免 KEYS 导致的性能问题。

​Go 代码示例​

package main

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
)

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379", // Redis 地址
	})

	ctx := context.Background()

	// 1. 使用 SCAN 遍历所有以 "event_" 开头的 key
	var zsetKeys []string
	var cursor uint64
	for {
		keys, nextCursor, err := rdb.Scan(ctx, cursor, "event_*", 100).Result() // 每次扫描 100 个 key
		if err != nil {
			panic(err)
		}

		// 2. 过滤出 ZSET 类型的 key
		for _, key := range keys {
			keyType, err := rdb.Type(ctx, key).Result()
			if err != nil {
				panic(err)
			}
			if keyType == "zset" {
				zsetKeys = append(zsetKeys, key)
			}
		}

		// 3. 如果 cursor 回到 0,说明扫描完成
		if nextCursor == 0 {
			break
		}
		cursor = nextCursor
	}

	// 4. 如果没有符合条件的 ZSET,直接返回
	if len(zsetKeys) == 0 {
		fmt.Println("没有找到以 'event_' 开头的 ZSET")
		return
	}

	// 5. 使用 ZUNIONSTORE 合并到 event_4
	err := rdb.ZUnionStore(ctx, "event_4", redis.ZStore{
		Weights: nil, // 默认权重 1
	}, zsetKeys...).Err()
	if err != nil {
		panic(err)
	}

	fmt.Printf("成功合并 %d 个 ZSET 到 event_4\n", len(zsetKeys))
}

​3. 使用 ZUNIONSTORE 合并 ZSET 的注意事项​

  • ZUNIONSTORE 会创建一个新的 ZSET(如果 destinationKey 不存在)或覆盖已有的 ZSET(如果 destinationKey 已存在)​​。
  • Weights 参数​​:可以指定每个源 ZSET 的权重(默认 nil 表示权重 1)。
  • Aggregate 参数​​:可以指定合并方式(SUMMINMAX),默认 SUM

​示例:带权重的合并​

err = rdb.ZUnionStore(ctx, "event_4", redis.ZStore{
    Weights:  []float64{1, 2, 3}, // 每个源 ZSET 的权重
    Aggregate: "SUM",              // 合并方式(SUM/MIN/MAX)
}, zsetKeys...).Err()

​4. 完整代码(推荐 SCAN 方式)​

package main

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
)

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379", // Redis 地址
	})

	ctx := context.Background()

	// 1. 使用 SCAN 获取所有以 "event_" 开头的 ZSET key
	var zsetKeys []string
	var cursor uint64
	for {
		keys, nextCursor, err := rdb.Scan(ctx, cursor, "event_*", 100).Result()
		if err != nil {
			panic(err)
		}

		for _, key := range keys {
			keyType, err := rdb.Type(ctx, key).Result()
			if err != nil {
				panic(err)
			}
			if keyType == "zset" {
				zsetKeys = append(zsetKeys, key)
			}
		}

		if nextCursor == 0 {
			break
		}
		cursor = nextCursor
	}

	if len(zsetKeys) == 0 {
		fmt.Println("没有找到以 'event_' 开头的 ZSET")
		return
	}

	// 2. 合并到 event_4
	err := rdb.ZUnionStore(ctx, "event_4", redis.ZStore{
		Weights:  nil, // 默认权重 1
		Aggregate: "SUM", // 默认 SUM
	}, zsetKeys...).Err()
	if err != nil {
		panic(err)
	}

	fmt.Printf("成功合并 %d 个 ZSET 到 event_4\n", len(zsetKeys))
}

​5. 测试​

  1. ​准备数据​​:
    # 添加几个测试 ZSET
    ZADD event_1 1 "item1" 2 "item2"
    ZADD event_2 3 "item3" 4 "item4"
    ZADD event_3 5 "item5" 6 "item6"
  2. ​运行 Go 程序​​:
    go run main.go
  3. ​检查 event_4​:
    ZRANGE event_4 0 -1 WITHSCORES
    ​预期输出​​:
    1) "item1"
    2) "1"
    3) "item2"
    4) "2"
    5) "item3"
    6) "3"
    7) "item4"
    8) "4"
    9) "item5"
    10) "5"
    11) "item6"
    12) "6"

​总结​

​方法​ ​适用场景​ ​推荐度​
KEYS 测试环境,小数据量 ❌ 不推荐生产环境
SCAN 生产环境,大数据量 ✅ 推荐
ZUNIONSTORE 合并 ZSET ✅ 必须使用

​推荐使用 SCAN + ZUNIONSTORE 的方式​​,避免 KEYS 阻塞 Redis,并确保正确合并 ZSET 数据。 🚀

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。