diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index e7e3388b2c..10436b9925 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -378,6 +378,37 @@ public String toString() { } }; + public static final Builder> STRING_LONG_MAP = new Builder>() { + @Override + @SuppressWarnings("unchecked") + public Map build(Object data) { + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + final Map map = new LinkedHashMap<>(list.size(), 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + map.put(STRING.build(kv.getKey()), LONG.build(kv.getValue())); + } + return map; + } else { + final Map map = new LinkedHashMap<>(list.size() / 2, 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + map.put(STRING.build(iterator.next()), LONG.build(iterator.next())); + } + return map; + } + } + + @Override + public String toString() { + return "Map"; + } + }; + public static final Builder KEYED_LIST_ELEMENT = new Builder() { @Override @SuppressWarnings("unchecked") diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 8afb2c34fe..49a9752d98 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -4056,6 +4056,11 @@ public final CommandObject> topkList(String key) { return new CommandObject<>(commandArguments(TopKCommand.LIST).key(key), BuilderFactory.STRING_LIST); } + public final CommandObject> topkListWithCount(String key) { + return new CommandObject<>(commandArguments(TopKCommand.LIST).key(key) + .add(RedisBloomKeyword.WITHCOUNT), BuilderFactory.STRING_LONG_MAP); + } + public final CommandObject> topkInfo(String key) { return new CommandObject<>(commandArguments(TopKCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP); } diff --git a/src/main/java/redis/clients/jedis/MultiNodePipelineBase.java b/src/main/java/redis/clients/jedis/MultiNodePipelineBase.java index 3fc96eda5d..10608b01f0 100644 --- a/src/main/java/redis/clients/jedis/MultiNodePipelineBase.java +++ b/src/main/java/redis/clients/jedis/MultiNodePipelineBase.java @@ -4231,6 +4231,11 @@ public Response> topkList(String key) { return appendCommand(commandObjects.topkList(key)); } + @Override + public Response> topkListWithCount(String key) { + return appendCommand(commandObjects.topkListWithCount(key)); + } + @Override public Response> topkInfo(String key) { return appendCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index 8e31da064f..c4bd7e1522 100644 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -4180,6 +4180,11 @@ public Response> topkList(String key) { return appendCommand(commandObjects.topkList(key)); } + @Override + public Response> topkListWithCount(String key) { + return appendCommand(commandObjects.topkListWithCount(key)); + } + @Override public Response> topkInfo(String key) { return appendCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/TransactionBase.java b/src/main/java/redis/clients/jedis/TransactionBase.java index 589ef3932d..0f4a7482c6 100644 --- a/src/main/java/redis/clients/jedis/TransactionBase.java +++ b/src/main/java/redis/clients/jedis/TransactionBase.java @@ -4280,6 +4280,11 @@ public Response> topkList(String key) { return appendCommand(commandObjects.topkList(key)); } + @Override + public Response> topkListWithCount(String key) { + return appendCommand(commandObjects.topkListWithCount(key)); + } + @Override public Response> topkInfo(String key) { return appendCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index ba0df50e69..dbf1a9639c 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4534,6 +4534,11 @@ public List topkList(String key) { return executeCommand(commandObjects.topkList(key)); } + @Override + public Map topkListWithCount(String key) { + return executeCommand(commandObjects.topkListWithCount(key)); + } + @Override public Map topkInfo(String key) { return executeCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java b/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java index 7b103e867a..860227254b 100644 --- a/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java +++ b/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java @@ -121,7 +121,7 @@ public byte[] getRaw() { public enum RedisBloomKeyword implements Rawable { CAPACITY, ERROR, NOCREATE, EXPANSION, NONSCALING, BUCKETSIZE, MAXITERATIONS, ITEMS, WEIGHTS, - COMPRESSION, OVERRIDE; + COMPRESSION, OVERRIDE, WITHCOUNT; private final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java index e4ff6bd43a..3071abb4c0 100644 --- a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java +++ b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java @@ -1,5 +1,6 @@ package redis.clients.jedis.bloom.commands; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -35,6 +36,18 @@ public interface TopKFilterCommands { */ List topkAdd(String key, String... items); + /** + * {@code TOPK.INCRBY {key} {item} {increment}} + * + * @param key + * @param item + * @param increment + * @return item dropped from list + */ + default String topkIncrBy(String key, String item, long increment) { + return topkIncrBy(key, Collections.singletonMap(item, increment)).get(0); + } + /** * {@code TOPK.INCRBY {key} {item} {increment} [{item} {increment} ...]} * @@ -72,6 +85,14 @@ public interface TopKFilterCommands { */ List topkList(String key); + /** + * {@code TOPK.LIST {key} WITHCOUNT} + * + * @param key + * @return k (or less) items in Top K list + */ + Map topkListWithCount(String key); + /** * {@code TOPK.INFO {key}} * diff --git a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java index 5d96489c77..d10656b4ea 100644 --- a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java @@ -24,5 +24,7 @@ public interface TopKFilterPipelineCommands { Response> topkList(String key); + Response> topkListWithCount(String key); + Response> topkInfo(String key); } diff --git a/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java b/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java index 4b54d4f7f8..e863a1285b 100644 --- a/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java +++ b/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java @@ -1,10 +1,11 @@ package redis.clients.jedis.modules.bloom; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; -import java.util.TreeSet; +import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; @@ -32,12 +33,20 @@ public void createTopKFilter() { assertEquals(Arrays.asList(1L, 0L, 1L), client.topkCount("aaa", "bb", "gg", "cc")); - assertEquals(new TreeSet<>(Arrays.asList("bb", "cc")), new TreeSet<>(client.topkList("aaa"))); + assertEquals(Arrays.asList("bb", "cc"), client.topkList("aaa")); -// assertEquals(null, client.topkIncrBy("aaa", "ff", 10)); - assertEquals(Collections.singletonList(null), - client.topkIncrBy("aaa", Collections.singletonMap("ff", 10L))); + Map listWithCount = client.topkListWithCount("aaa"); + assertEquals(2, listWithCount.size()); + listWithCount.forEach((item, count) -> { + assertTrue(Arrays.asList("bb", "cc").contains(item)); + assertEquals(Long.valueOf(1), count); + }); + + assertEquals(null, client.topkIncrBy("aaa", "ff", 5)); + assertEquals(Arrays.asList("ff", "bb", "cc"), client.topkList("aaa")); - assertEquals(new TreeSet<>(Arrays.asList("bb", "cc", "ff")), new TreeSet<>(client.topkList("aaa"))); + assertEquals(Collections.singletonList(null), + client.topkIncrBy("aaa", Collections.singletonMap("ff", 8L))); + assertEquals(Long.valueOf(13), client.topkListWithCount("aaa").get("ff")); } }