Skip to content

Commit 13aa478

Browse files
authored
Merge pull request #12 from dengliming/master
Add Support for TopK Filter Commands
2 parents b4e2818 + 1cf4bbc commit 13aa478

File tree

3 files changed

+170
-7
lines changed

3 files changed

+170
-7
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ func main() {
100100

101101
| Command | Recommended API and godoc |
102102
| :--- | ----: |
103-
| [TOPK.RESERVE](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkreserve) | N/A |
104-
| [TOPK.ADD](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkadd) | N/A |
105-
| [TOPK.INCRBY](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkincrby) | N/A |
106-
| [TOPK.QUERY](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkquery) | N/A |
107-
| [TOPK.COUNT](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkcount) | N/A |
108-
| [TOPK.LIST](https://oss.redislabs.com/redisbloom/TopK_Commands/#topklist) | N/A |
109-
| [TOPK.INFO](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkinfo) | N/A |
103+
| [TOPK.RESERVE](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkreserve) | [TopkReserve](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkReserve) |
104+
| [TOPK.ADD](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkadd) | [TopkAdd](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkAdd) |
105+
| [TOPK.INCRBY](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkincrby) | [TopkIncrby](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkIncrby) |
106+
| [TOPK.QUERY](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkquery) | [TopkQuery](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkQuery) |
107+
| [TOPK.COUNT](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkcount) | [TopkCount](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkCount) |
108+
| [TOPK.LIST](https://oss.redislabs.com/redisbloom/TopK_Commands/#topklist) | [TopkList](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkList) |
109+
| [TOPK.INFO](https://oss.redislabs.com/redisbloom/TopK_Commands/#topkinfo) | [TopkInfo](https://godoc.org/github.com/RedisBloom/redisbloom-go#Client.TopkInfo) |
110110

111111

112112
## License

client.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package redis_bloom_go
22

33
import (
44
"errors"
5+
"fmt"
56
"github.com/gomodule/redigo/redis"
67
"strconv"
78
"strings"
@@ -131,3 +132,87 @@ func (client *Client) BfExistsMulti(key string, items []string) ([]int64, error)
131132
result, err := conn.Do("BF.MEXISTS", args...)
132133
return redis.Int64s(result, err)
133134
}
135+
136+
// Initializes a TopK with specified parameters.
137+
func (client *Client) TopkReserve(key string, topk int64, width int64, depth int64, decay float64) (string, error) {
138+
conn := client.Pool.Get()
139+
defer conn.Close()
140+
result, err := conn.Do("TOPK.RESERVE", key, topk, width, depth, strconv.FormatFloat(decay, 'g', 16, 64))
141+
return redis.String(result, err)
142+
}
143+
144+
// Adds an item to the data structure.
145+
func (client *Client) TopkAdd(key string, items []string) ([]string, error) {
146+
conn := client.Pool.Get()
147+
defer conn.Close()
148+
args := redis.Args{key}.AddFlat(items)
149+
result, err := conn.Do("TOPK.ADD", args...)
150+
return redis.Strings(result, err)
151+
}
152+
153+
// Returns count for an item.
154+
func (client *Client) TopkCount(key string, items []string) ([]string, error) {
155+
conn := client.Pool.Get()
156+
defer conn.Close()
157+
args := redis.Args{key}.AddFlat(items)
158+
result, err := conn.Do("TOPK.COUNT", args...)
159+
return redis.Strings(result, err)
160+
}
161+
162+
// Checks whether an item is one of Top-K items.
163+
func (client *Client) TopkQuery(key string, items []string) ([]int64, error) {
164+
conn := client.Pool.Get()
165+
defer conn.Close()
166+
args := redis.Args{key}.AddFlat(items)
167+
result, err := conn.Do("TOPK.QUERY", args...)
168+
return redis.Int64s(result, err)
169+
}
170+
171+
// Return full list of items in Top K list.
172+
func (client *Client) TopkList(key string) ([]string, error) {
173+
conn := client.Pool.Get()
174+
defer conn.Close()
175+
result, err := conn.Do("TOPK.LIST", key)
176+
return redis.Strings(result, err)
177+
}
178+
179+
// Returns number of required items (k), width, depth and decay values.
180+
func (client *Client) TopkInfo(key string) (map[string]string, error) {
181+
conn := client.Pool.Get()
182+
defer conn.Close()
183+
reply, err := conn.Do("TOPK.INFO", key)
184+
values, err := redis.Values(reply, err)
185+
if err != nil {
186+
return nil, err
187+
}
188+
if len(values)%2 != 0 {
189+
return nil, errors.New("expects even number of values result")
190+
}
191+
192+
m := make(map[string]string, len(values)/2)
193+
for i := 0; i < len(values); i += 2 {
194+
k := values[i].(string)
195+
switch v := values[i+1].(type) {
196+
case []byte:
197+
m[k] = string(values[i+1].([]byte))
198+
break
199+
case int64:
200+
m[k] = strconv.FormatInt(values[i+1].(int64), 10)
201+
default:
202+
return nil, fmt.Errorf("unexpected element type for (Ints,String), got type %T", v)
203+
}
204+
}
205+
return m, err
206+
}
207+
208+
// Increase the score of an item in the data structure by increment.
209+
func (client *Client) TopkIncrBy(key string, itemIncrements map[string]int64) ([]string, error) {
210+
conn := client.Pool.Get()
211+
defer conn.Close()
212+
args := redis.Args{key}
213+
for k, v := range itemIncrements {
214+
args = args.Add(k, v)
215+
}
216+
reply, err := conn.Do("TOPK.INCRBY", args...)
217+
return redis.Strings(reply, err)
218+
}

client_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,81 @@ func TestClient_BfExistsMulti(t *testing.T) {
129129
assert.Equal(t, int64(1), existsResult[1])
130130
assert.Equal(t, int64(0), existsResult[2])
131131
}
132+
133+
func TestClient_TopkReserve(t *testing.T) {
134+
client.FlushAll()
135+
ret, err := client.TopkReserve("test_topk_reserve", 10, 2000, 7, 0.925)
136+
assert.Nil(t, err)
137+
assert.Equal(t, "OK", ret)
138+
}
139+
140+
func TestClient_TopkAdd(t *testing.T) {
141+
client.FlushAll()
142+
key := "test_topk_add"
143+
ret, err := client.TopkReserve(key, 10, 2000, 7, 0.925)
144+
assert.Nil(t, err)
145+
assert.Equal(t, "OK", ret)
146+
rets, err := client.TopkAdd(key, []string{"test", "test1", "test3"})
147+
assert.Nil(t, err)
148+
assert.Equal(t, 3, len(rets))
149+
}
150+
151+
func TestClient_TopkQuery(t *testing.T) {
152+
client.FlushAll()
153+
key := "test_topk_query"
154+
ret, err := client.TopkReserve(key, 10, 2000, 7, 0.925)
155+
assert.Nil(t, err)
156+
assert.Equal(t, "OK", ret)
157+
rets, err := client.TopkAdd(key, []string{"test"})
158+
assert.Nil(t, err)
159+
assert.NotNil(t, rets)
160+
queryRet, err := client.TopkQuery(key, []string{"test", "nonexist"})
161+
assert.Nil(t, err)
162+
assert.Equal(t, 2, len(queryRet))
163+
assert.Equal(t, int64(1), queryRet[0])
164+
assert.Equal(t, int64(0), queryRet[1])
165+
166+
key1 := "test_topk_list"
167+
ret, err = client.TopkReserve(key1, 3, 50, 3, 0.9)
168+
assert.Nil(t, err)
169+
assert.Equal(t, "OK", ret)
170+
client.TopkAdd(key1, []string{"A", "B", "C", "D", "E", "A", "A", "B", "C",
171+
"G", "D", "B", "D", "A", "E", "E"})
172+
keys, err := client.TopkList(key1)
173+
assert.Nil(t, err)
174+
assert.Equal(t, 3, len(keys))
175+
assert.Equal(t, []string{"D", "A", "B"}, keys)
176+
}
177+
178+
func TestClient_TopkInfo(t *testing.T) {
179+
client.FlushAll()
180+
key := "test_topk_info"
181+
ret, err := client.TopkReserve(key, 10, 2000, 7, 0.925)
182+
assert.Nil(t, err)
183+
assert.Equal(t, "OK", ret)
184+
185+
info, err := client.TopkInfo(key)
186+
assert.Equal(t, "10", info["k"])
187+
assert.Equal(t, "2000", info["width"])
188+
assert.Equal(t, "7", info["depth"])
189+
190+
info, err = client.TopkInfo("notexists")
191+
assert.NotNil(t, err)
192+
}
193+
194+
func TestClient_TopkIncrBy(t *testing.T) {
195+
client.FlushAll()
196+
key := "test_topk_incrby"
197+
ret, err := client.TopkReserve(key, 50, 2000, 7, 0.925)
198+
assert.Nil(t, err)
199+
assert.Equal(t, "OK", ret)
200+
201+
rets, err := client.TopkAdd(key, []string{"foo", "bar", "42"})
202+
assert.Nil(t, err)
203+
assert.NotNil(t, rets)
204+
205+
rets, err = client.TopkIncrBy(key, map[string]int64{"foo": 3, "bar": 2, "42": 30})
206+
assert.Nil(t, err)
207+
assert.Equal(t, 3, len(rets))
208+
assert.Equal(t, "", rets[2])
209+
}

0 commit comments

Comments
 (0)