1
0
mirror of https://github.com/redis/go-redis.git synced 2026-10-22 19:49:00 +03:00

feat(bloom): add cellSize param to cms init (#4023)

This commit is contained in:
Vladislav Kotsev
2026-10-07 13:24:59 +03:00
committed by GitHub
parent e4a198a8c7
commit 07b88b5dcd
2 changed files with 78 additions and 2 deletions

View File

@@ -2,11 +2,14 @@ package redis
import (
"context"
"errors"
"fmt"
"github.com/redis/go-redis/v9/internal/proto"
)
var errCMSInvalidCellSize = errors.New("redis: invalid cell size (must be 1, 2, 4 or 8)")
type ProbabilisticCmdable interface {
BFAdd(ctx context.Context, key string, element interface{}) *BoolCmd
BFCard(ctx context.Context, key string) *IntCmd
@@ -48,7 +51,9 @@ type ProbabilisticCmdable interface {
CMSIncrBy(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd
CMSInfo(ctx context.Context, key string) *CMSInfoCmd
CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd
CMSInitByDimCellSize(ctx context.Context, key string, width, depth, cellSize int64) *StatusCmd
CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd
CMSInitByProbCellSize(ctx context.Context, key string, errorRate, probability float64, cellSize int64) *StatusCmd
CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd
CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int64) *StatusCmd
CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd
@@ -912,21 +917,55 @@ func (c cmdable) CMSInfo(ctx context.Context, key string) *CMSInfoCmd {
// CMSInitByDim creates an empty Count-Min Sketch filter with the specified dimensions.
// For more information - https://redis.io/commands/cms.initbydim/
func (c cmdable) CMSInitByDim(ctx context.Context, key string, width, depth int64) *StatusCmd {
args := []interface{}{"CMS.INITBYDIM", key, width, depth}
args := []any{"CMS.INITBYDIM", key, width, depth}
cmd := NewStatusCmd(ctx, args...)
_ = c(ctx, cmd)
return cmd
}
// CMSInitByDimCellSize creates an empty Count-Min Sketch filter with the specified dimensions and number of bytes per cell (valid cell sizes: 1,2,4,8).
// For more information - https://redis.io/commands/cms.initbydim/
func (c cmdable) CMSInitByDimCellSize(ctx context.Context, key string, width, depth, cellSize int64) *StatusCmd {
args := []any{"CMS.INITBYDIM", key, width, depth, "CELL_SIZE", cellSize}
cmd := NewStatusCmd(ctx, args...)
if !isValidCMSCellSize(cellSize) {
cmd.SetErr(errCMSInvalidCellSize)
return cmd
}
_ = c(ctx, cmd)
return cmd
}
// CMSInitByProb creates an empty Count-Min Sketch filter with the specified error rate and probability.
// For more information - https://redis.io/commands/cms.initbyprob/
func (c cmdable) CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd {
args := []interface{}{"CMS.INITBYPROB", key, errorRate, probability}
args := []any{"CMS.INITBYPROB", key, errorRate, probability}
cmd := NewStatusCmd(ctx, args...)
_ = c(ctx, cmd)
return cmd
}
// CMSInitByProbCellSize creates an empty Count-Min Sketch filter with the specified error rate, probability and number of bytes per cell (valid cell sizes: 1,2,4,8).
// For more information - https://redis.io/commands/cms.initbyprob/
func (c cmdable) CMSInitByProbCellSize(ctx context.Context, key string, errorRate, probability float64, cellSize int64) *StatusCmd {
args := []any{"CMS.INITBYPROB", key, errorRate, probability, "CELL_SIZE", cellSize}
cmd := NewStatusCmd(ctx, args...)
if !isValidCMSCellSize(cellSize) {
cmd.SetErr(errCMSInvalidCellSize)
return cmd
}
_ = c(ctx, cmd)
return cmd
}
func isValidCMSCellSize(cellSize int64) bool {
switch cellSize {
case 1, 2, 4, 8:
return true
}
return false
}
// CMSMerge merges multiple Count-Min Sketch filters into a single filter.
// The destination filter must not exist and will be created with the dimensions of the first source filter.
// The number of items in each source filter must be equal.

View File

@@ -502,6 +502,43 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() {
Expect(info).To(BeAssignableToTypeOf(redis.CMSInfo{}))
})
It("should CMSInitByDimCellSize", Label("cms", "cmsinitbydim", "cmsinfo"), func() {
SkipBeforeRedisVersion("8.12", "CMS.INITBYDIM CELL_SIZE since Redis 8.12")
err := client.CMSInitByDimCellSize(ctx, "testcms1", 5, 10, 8).Err()
Expect(err).NotTo(HaveOccurred())
info, err := client.CMSInfo(ctx, "testcms1").Result()
Expect(err).NotTo(HaveOccurred())
Expect(info.Width).To(BeEquivalentTo(int64(5)))
Expect(info.Depth).To(BeEquivalentTo(int64(10)))
Expect(info.CellSize).To(BeEquivalentTo(int64(8)))
})
It("should CMSInitByProbCellSize", Label("cms", "cmsinitbyprob", "cmsinfo"), func() {
SkipBeforeRedisVersion("8.12", "CMS.INITBYPROB CELL_SIZE since Redis 8.12")
err := client.CMSInitByProbCellSize(ctx, "testcms1", 0.002, 0.01, 2).Err()
Expect(err).NotTo(HaveOccurred())
info, err := client.CMSInfo(ctx, "testcms1").Result()
Expect(err).NotTo(HaveOccurred())
Expect(info).To(BeAssignableToTypeOf(redis.CMSInfo{}))
Expect(info.CellSize).To(BeEquivalentTo(int64(2)))
})
It("should reject invalid cell size without calling the server", Label("cms", "cmsinitbydim", "cmsinitbyprob"), func() {
err := client.CMSInitByDimCellSize(ctx, "testcms1", 5, 10, 3).Err()
Expect(err).To(MatchError("redis: invalid cell size (must be 1, 2, 4 or 8)"))
err = client.CMSInitByProbCellSize(ctx, "testcms1", 0.002, 0.01, 0).Err()
Expect(err).To(MatchError("redis: invalid cell size (must be 1, 2, 4 or 8)"))
exists, err := client.Exists(ctx, "testcms1").Result()
Expect(err).NotTo(HaveOccurred())
Expect(exists).To(BeEquivalentTo(int64(0)))
})
It("should CMSMerge, CMSMergeWithWeight and CMSQuery", Label("cms", "cmsmerge", "cmsquery", "NonRedisEnterprise"), func() {
err := client.CMSMerge(ctx, "destCms1", "testcms2", "testcms3").Err()
Expect(err).To(HaveOccurred())