Skip to content

Commit 9bd2296

Browse files
Merge pull request #16 from dengliming/f_cms_command
Add Support for Count-Min Sketch Commands
2 parents 13aa478 + 925f4af commit 9bd2296

File tree

3 files changed

+149
-8
lines changed

3 files changed

+149
-8
lines changed

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ func main() {
6161
| :--- | ----: |
6262
| [BF.RESERVE](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfreserve) | [Reserve](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.Reserve) |
6363
| [BF.ADD](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfadd) | [Add](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.Add) |
64-
| [BF.MADD](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfmadd) | N/A |
64+
| [BF.MADD](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfmadd) | [BfAddMulti](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.BfAddMulti) |
6565
| [BF.INSERT](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfinsert) | N/A |
6666
| [BF.EXISTS](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfexists) | [Exists](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.Exists) |
67-
| [BF.MEXISTS](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfmexists) | N/A |
67+
| [BF.MEXISTS](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfmexists) | [BfExistsMulti](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.BfExistsMulti) |
6868
| [BF.SCANDUMP](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfscandump) | N/A |
6969
| [BF.LOADCHUNK](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfloadchunk) | N/A |
7070
| [BF.INFO](https://oss.redislabs.com/redisbloom/Bloom_Commands/#bfinfo) | [Info](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.Info) |
@@ -89,12 +89,12 @@ func main() {
8989

9090
| Command | Recommended API and godoc |
9191
| :--- | ----: |
92-
| [CMS.INITBYDIM](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsinitbydim) | N/A |
93-
| [CMS.INITBYPROB](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsinitbyprob) | N/A |
94-
| [CMS.INCRBY](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsincrby) | N/A |
95-
| [CMS.QUERY](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsquery) | N/A |
96-
| [CMS.MERGE](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsmerge) | N/A |
97-
| [CMS.INFO](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsinfo) | N/A |
92+
| [CMS.INITBYDIM](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsinitbydim) | [CmsInitByDim](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.CmsInitByDim) |
93+
| [CMS.INITBYPROB](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsinitbyprob) | [CmsInitByProb](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.CmsInitByProb) |
94+
| [CMS.INCRBY](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsincrby) | [CmsIncrBy](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.CmsIncrBy) |
95+
| [CMS.QUERY](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsquery) | [CmsQuery](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.CmsQuery) |
96+
| [CMS.MERGE](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsmerge) | [CmsMerge](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.CmsMerge) |
97+
| [CMS.INFO](https://oss.redislabs.com/redisbloom/CountMinSketch_Commands/#cmsinfo) | [CmsInfo](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.CmsInfo) |
9898

9999
### TopK Filter
100100

client.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,71 @@ func (client *Client) TopkIncrBy(key string, itemIncrements map[string]int64) ([
216216
reply, err := conn.Do("TOPK.INCRBY", args...)
217217
return redis.Strings(reply, err)
218218
}
219+
220+
// Initializes a Count-Min Sketch to dimensions specified by user.
221+
func (client *Client) CmsInitByDim(key string, width int64, depth int64) (string, error) {
222+
conn := client.Pool.Get()
223+
defer conn.Close()
224+
result, err := conn.Do("CMS.INITBYDIM", key, width, depth)
225+
return redis.String(result, err)
226+
}
227+
228+
// Initializes a Count-Min Sketch to accommodate requested capacity.
229+
func (client *Client) CmsInitByProb(key string, error float64, probability float64) (string, error) {
230+
conn := client.Pool.Get()
231+
defer conn.Close()
232+
result, err := conn.Do("CMS.INITBYPROB", key, error, probability)
233+
return redis.String(result, err)
234+
}
235+
236+
// Increases the count of item by increment. Multiple items can be increased with one call.
237+
func (client *Client) CmsIncrBy(key string, itemIncrements map[string]int64) ([]int64, error) {
238+
conn := client.Pool.Get()
239+
defer conn.Close()
240+
args := redis.Args{key}
241+
for k, v := range itemIncrements {
242+
args = args.Add(k, v)
243+
}
244+
result, err := conn.Do("CMS.INCRBY", args...)
245+
return redis.Int64s(result, err)
246+
}
247+
248+
// Returns count for item.
249+
func (client *Client) CmsQuery(key string, items []string) ([]int64, error) {
250+
conn := client.Pool.Get()
251+
defer conn.Close()
252+
args := redis.Args{key}.AddFlat(items)
253+
result, err := conn.Do("CMS.QUERY", args...)
254+
return redis.Int64s(result, err)
255+
}
256+
257+
// Merges several sketches into one sketch.
258+
func (client *Client) CmsMerge(key string, srcs []string, weights []string) (string, error) {
259+
conn := client.Pool.Get()
260+
defer conn.Close()
261+
args := redis.Args{key}.Add(len(srcs)).AddFlat(srcs)
262+
if weights != nil && len(weights) > 0 {
263+
args = args.Add("WEIGHTS").AddFlat(weights)
264+
}
265+
return redis.String(conn.Do("CMS.MERGE", args...))
266+
}
267+
268+
// Returns width, depth and total count of the sketch.
269+
func (client *Client) CmsInfo(key string) (map[string]int64, error) {
270+
conn := client.Pool.Get()
271+
defer conn.Close()
272+
reply, err := conn.Do("CMS.INFO", key)
273+
274+
values, err := redis.Values(reply, err)
275+
if err != nil {
276+
return nil, err
277+
}
278+
if len(values)%2 != 0 {
279+
return nil, errors.New("expects even number of values result")
280+
}
281+
m := make(map[string]int64, len(values)/2)
282+
for i := 0; i < len(values); i += 2 {
283+
m[values[i].(string)] = values[i+1].(int64)
284+
}
285+
return m, err
286+
}

client_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,76 @@ func TestClient_TopkIncrBy(t *testing.T) {
207207
assert.Equal(t, 3, len(rets))
208208
assert.Equal(t, "", rets[2])
209209
}
210+
211+
func TestClient_CmsInitByDim(t *testing.T) {
212+
client.FlushAll()
213+
ret, err := client.CmsInitByDim("test_cms_initbydim", 1000, 5)
214+
assert.Nil(t, err)
215+
assert.Equal(t, "OK", ret)
216+
}
217+
218+
func TestClient_CmsInitByProb(t *testing.T) {
219+
client.FlushAll()
220+
ret, err := client.CmsInitByProb("test_cms_initbyprob", 0.01, 0.01)
221+
assert.Nil(t, err)
222+
assert.Equal(t, "OK", ret)
223+
}
224+
225+
func TestClient_CmsIncrBy(t *testing.T) {
226+
client.FlushAll()
227+
key := "test_cms_incrby"
228+
ret, err := client.CmsInitByDim(key, 1000, 5)
229+
assert.Nil(t, err)
230+
assert.Equal(t, "OK", ret)
231+
results, err := client.CmsIncrBy(key, map[string]int64{"foo": 5})
232+
assert.Nil(t, err)
233+
assert.NotNil(t, results)
234+
assert.Equal(t, int64(5), results[0])
235+
}
236+
237+
func TestClient_CmsQuery(t *testing.T) {
238+
client.FlushAll()
239+
key := "test_cms_query"
240+
ret, err := client.CmsInitByDim(key, 1000, 5)
241+
assert.Nil(t, err)
242+
assert.Equal(t, "OK", ret)
243+
results, err := client.CmsQuery(key, []string{"notexist"})
244+
assert.Nil(t, err)
245+
assert.NotNil(t, 0, results[0])
246+
_, err = client.CmsIncrBy(key, map[string]int64{"foo": 5})
247+
assert.Nil(t, err)
248+
results, err = client.CmsQuery(key, []string{"foo"})
249+
assert.Nil(t, err)
250+
assert.Equal(t, int64(5), results[0])
251+
}
252+
253+
func TestClient_CmsMerge(t *testing.T) {
254+
client.FlushAll()
255+
ret, err := client.CmsInitByDim("A", 1000, 5)
256+
assert.Nil(t, err)
257+
assert.Equal(t, "OK", ret)
258+
ret, err = client.CmsInitByDim("B", 1000, 5)
259+
assert.Nil(t, err)
260+
assert.Equal(t, "OK", ret)
261+
ret, err = client.CmsInitByDim("C", 1000, 5)
262+
assert.Nil(t, err)
263+
assert.Equal(t, "OK", ret)
264+
client.CmsIncrBy("A", map[string]int64{"foo": 5, "bar": 3, "baz": 9})
265+
client.CmsIncrBy("B", map[string]int64{"foo": 2, "bar": 3, "baz": 1})
266+
client.CmsMerge("C", []string{"A", "B"}, nil)
267+
results, err := client.CmsQuery("C", []string{"foo", "bar", "baz"})
268+
assert.Equal(t, []int64{7, 6, 10}, results)
269+
}
270+
271+
func TestClient_CmsInfo(t *testing.T) {
272+
client.FlushAll()
273+
key := "test_cms_info"
274+
ret, err := client.CmsInitByDim(key, 1000, 5)
275+
assert.Nil(t, err)
276+
assert.Equal(t, "OK", ret)
277+
info, err := client.CmsInfo(key)
278+
assert.Nil(t, err)
279+
assert.Equal(t, int64(1000), info["width"])
280+
assert.Equal(t, int64(5), info["depth"])
281+
assert.Equal(t, int64(0), info["count"])
282+
}

0 commit comments

Comments
 (0)