From b4c1848927ec685523793c9de50b06635799aff5 Mon Sep 17 00:00:00 2001 From: Yang Bodong Date: Sat, 7 Aug 2021 23:58:08 +0800 Subject: [PATCH] Support stralgo command (#2586) * add redis6.0 command `stralgo` support * Support stralgo command StrAlgoParams for pass params to redis and StringMatchResult is the result * Add strAlgoLCSStrings command and remove strings option from StrAlgoLCSParams * Update src/main/java/redis/clients/jedis/resps/LCSMatchResult.java Co-authored-by: ljwlc Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> --- .../redis/clients/jedis/BinaryClient.java | 8 ++ .../java/redis/clients/jedis/BinaryJedis.java | 16 ++- .../clients/jedis/BinaryJedisCluster.java | 22 +++- .../clients/jedis/BinaryShardedJedis.java | 8 ++ .../redis/clients/jedis/BuilderFactory.java | 48 ++++++++ src/main/java/redis/clients/jedis/Client.java | 10 ++ src/main/java/redis/clients/jedis/Jedis.java | 28 +++++ .../redis/clients/jedis/JedisCluster.java | 20 ++++ .../clients/jedis/MultiKeyPipelineBase.java | 12 ++ .../redis/clients/jedis/PipelineBase.java | 16 +++ .../java/redis/clients/jedis/Protocol.java | 4 +- .../redis/clients/jedis/ShardedJedis.java | 8 ++ .../jedis/commands/BinaryJedisCommands.java | 3 + .../jedis/commands/BinaryRedisPipeline.java | 3 + .../clients/jedis/commands/Commands.java | 5 + .../clients/jedis/commands/JedisCommands.java | 4 + .../commands/MultiKeyBinaryCommands.java | 4 + .../MultiKeyBinaryJedisClusterCommands.java | 6 + .../commands/MultiKeyBinaryRedisPipeline.java | 3 + .../jedis/commands/MultiKeyCommands.java | 3 + .../commands/MultiKeyCommandsPipeline.java | 2 + .../MultiKeyJedisClusterCommands.java | 4 + .../clients/jedis/commands/RedisPipeline.java | 4 + .../jedis/params/StrAlgoLCSParams.java | 87 ++++++++++++++ .../clients/jedis/resps/LCSMatchResult.java | 106 ++++++++++++++++++ .../commands/StringValuesCommandsTest.java | 73 ++++++++++++ 26 files changed, 501 insertions(+), 6 deletions(-) create mode 100644 src/main/java/redis/clients/jedis/params/StrAlgoLCSParams.java create mode 100644 src/main/java/redis/clients/jedis/resps/LCSMatchResult.java diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index 77cff527f4..76ee44f8ea 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -1100,6 +1100,14 @@ public void strlen(final byte[] key) { sendCommand(STRLEN, key); } + public void strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params) { + sendCommand(STRALGO, params.getByteParams(Keyword.KEYS, keyA, keyB)); + } + + public void strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params) { + sendCommand(STRALGO, params.getByteParams(Keyword.STRINGS, strA, strB)); + } + /** * @deprecated This will be removed in next major release. */ diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index bc32db0173..6e9220830e 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -21,8 +21,6 @@ import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocketFactory; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; import redis.clients.jedis.args.*; import redis.clients.jedis.commands.AdvancedBinaryJedisCommands; import redis.clients.jedis.commands.BasicCommands; @@ -3710,6 +3708,20 @@ public Long strlen(final byte[] key) { return client.getIntegerReply(); } + @Override + public LCSMatchResult strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params) { + checkIsInMultiOrPipeline(); + client.strAlgoLCSKeys(keyA, keyB, params); + return BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER.build(client.getOne()); + } + + @Override + public LCSMatchResult strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params) { + checkIsInMultiOrPipeline(); + client.strAlgoLCSStrings(strA, strB, params); + return BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER.build(client.getOne()); + } + /** * @deprecated This will be removed in next major release. */ diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCluster.java b/src/main/java/redis/clients/jedis/BinaryJedisCluster.java index b288c4dcf7..10e437a509 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedisCluster.java +++ b/src/main/java/redis/clients/jedis/BinaryJedisCluster.java @@ -1,7 +1,5 @@ package redis.clients.jedis; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; import redis.clients.jedis.args.*; import redis.clients.jedis.commands.BinaryJedisClusterCommands; import redis.clients.jedis.commands.JedisClusterBinaryScriptingCommands; @@ -989,6 +987,26 @@ public Long execute(Jedis connection) { }.runBinary(key); } + @Override + public LCSMatchResult strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params) { + return new JedisClusterCommand(connectionHandler, maxAttempts, maxTotalRetriesDuration) { + @Override + public LCSMatchResult execute(Jedis connection) { + return connection.strAlgoLCSKeys(keyA, keyB, params); + } + }.runBinary(2, keyA, keyB); + } + + @Override + public LCSMatchResult strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params) { + return new JedisClusterCommand(connectionHandler, maxAttempts, maxTotalRetriesDuration) { + @Override + public LCSMatchResult execute(Jedis connection) { + return connection.strAlgoLCSStrings(strA, strB, params); + } + }.runWithAnyNode(); + } + @Override public Long zadd(final byte[] key, final double score, final byte[] member) { return new JedisClusterCommand(connectionHandler, maxAttempts, maxTotalRetriesDuration) { diff --git a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java index cc820f7f47..610eea5057 100644 --- a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java @@ -15,6 +15,7 @@ import redis.clients.jedis.params.GetExParams; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XAddParams; import redis.clients.jedis.params.XAutoClaimParams; import redis.clients.jedis.params.XClaimParams; @@ -23,6 +24,7 @@ import redis.clients.jedis.params.ZAddParams; import redis.clients.jedis.params.ZIncrByParams; import redis.clients.jedis.params.LPosParams; +import redis.clients.jedis.resps.LCSMatchResult; import redis.clients.jedis.util.Hashing; import redis.clients.jedis.util.Sharded; @@ -1342,4 +1344,10 @@ public Object sendBlockingCommand(ProtocolCommand cmd, byte[]... args) { public Object sendCommand(ProtocolCommand cmd) { return sendCommand(cmd, dummyArray); } + + @Override + public LCSMatchResult strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params) { + Jedis j = getShard(""); + return j.strAlgoLCSStrings(strA, strB, params); + } } diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 04f2d20ec2..7de3630c3a 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -10,6 +10,8 @@ import java.util.Map; import java.util.Set; +import redis.clients.jedis.resps.LCSMatchResult.MatchedPosition; +import redis.clients.jedis.resps.LCSMatchResult.Position; import redis.clients.jedis.resps.*; import redis.clients.jedis.util.JedisByteHashMap; import redis.clients.jedis.util.SafeEncoder; @@ -1095,4 +1097,50 @@ private BuilderFactory() { throw new InstantiationError("Must not instantiate this class"); } + public static final Builder STR_ALGO_LCS_RESULT_BUILDER = new Builder() { + @Override + public LCSMatchResult build(Object data) { + if (data == null) { + return null; + } + + if (data instanceof byte[]) { + return new LCSMatchResult(STRING.build(data)); + } else if (data instanceof Long) { + return new LCSMatchResult(LONG.build(data)); + } else { + long len = 0; + List matchedPositions = new ArrayList<>(); + + List objectList = (List) data; + if ("matches".equalsIgnoreCase(STRING.build(objectList.get(0)))) { + List matches = (List)objectList.get(1); + for (Object obj : matches) { + if (obj instanceof List) { + List positions = (List) obj; + Position a = new Position( + LONG.build(((List) positions.get(0)).get(0)), + LONG.build(((List) positions.get(0)).get(1)) + ); + Position b = new Position( + LONG.build(((List) positions.get(1)).get(0)), + LONG.build(((List) positions.get(1)).get(1)) + ); + long matchLen = 0; + if (positions.size() >= 3) { + matchLen = LONG.build(positions.get(2)); + } + matchedPositions.add(new MatchedPosition(a, b, matchLen)); + } + } + } + + if ("len".equalsIgnoreCase(STRING.build(objectList.get(2)))) { + len = LONG.build(objectList.get(3)); + } + return new LCSMatchResult(matchedPositions, len); + } + } + }; + } diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 1e3bc3f06c..20f8b9254e 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -882,6 +882,16 @@ public void strlen(final String key) { strlen(SafeEncoder.encode(key)); } + @Override + public void strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params) { + strAlgoLCSKeys(SafeEncoder.encode(keyA), SafeEncoder.encode(keyB), params); + } + + @Override + public void strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params) { + strAlgoLCSStrings(SafeEncoder.encode(strA), SafeEncoder.encode(strB), params); + } + @Override public void lpushx(final String key, final String... string) { lpushx(SafeEncoder.encode(key), SafeEncoder.encodeMany(string)); diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 3bedd81ba0..427ea5f488 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3024,6 +3024,34 @@ public Long strlen(final String key) { return client.getIntegerReply(); } + /** + * Calculate the longest common subsequence of keyA and keyB. + * @param keyA keyA + * @param keyB keyB + * @param params the params + * @return According to StrAlgoLCSParams to decide to return content to fill LCSMatchResult. + */ + @Override + public LCSMatchResult strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params) { + checkIsInMultiOrPipeline(); + client.strAlgoLCSKeys(keyA, keyB, params); + return BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER.build(client.getOne()); + } + + /** + * Calculate the longest common subsequence of strA and strB. + * @param strA strA + * @param strB strB + * @param params the params + * @return According to StrAlgoLCSParams to decide to return content to fill LCSMatchResult. + */ + @Override + public LCSMatchResult strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params) { + checkIsInMultiOrPipeline(); + client.strAlgoLCSStrings(strA, strB, params); + return BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER.build(client.getOne()); + } + @Override public Long lpushx(final String key, final String... string) { checkIsInMultiOrPipeline(); diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 4b9b30ccaa..41781d86b5 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -1075,6 +1075,26 @@ public Long execute(Jedis connection) { }.run(key); } + @Override + public LCSMatchResult strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params) { + return new JedisClusterCommand(connectionHandler, maxAttempts, maxTotalRetriesDuration) { + @Override + public LCSMatchResult execute(Jedis connection) { + return connection.strAlgoLCSKeys(keyA, keyB, params); + } + }.run(2, keyA, keyB); + } + + @Override + public LCSMatchResult strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params) { + return new JedisClusterCommand(connectionHandler, maxAttempts, maxTotalRetriesDuration) { + @Override + public LCSMatchResult execute(Jedis connection) { + return connection.strAlgoLCSStrings(strA, strB, params); + } + }.runWithAnyNode(); + } + @Override public Long zadd(final String key, final double score, final String member) { return new JedisClusterCommand(connectionHandler, maxAttempts, maxTotalRetriesDuration) { diff --git a/src/main/java/redis/clients/jedis/MultiKeyPipelineBase.java b/src/main/java/redis/clients/jedis/MultiKeyPipelineBase.java index 8d877105ad..cba5b96db0 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyPipelineBase.java +++ b/src/main/java/redis/clients/jedis/MultiKeyPipelineBase.java @@ -1019,4 +1019,16 @@ public Response>>> xreadGroup(final Str client.xreadGroup(groupname, consumer, xReadGroupParams, streams); return getResponse(BuilderFactory.STREAM_READ_RESPONSE); } + + @Override + public Response strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params) { + client.strAlgoLCSKeys(keyA, keyB, params); + return getResponse(BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER); + } + + @Override + public Response strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params) { + client.strAlgoLCSKeys(keyA, keyB, params); + return getResponse(BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER); + } } diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index f24cf0229b..a9118d1acf 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -12,6 +12,7 @@ import redis.clients.jedis.params.GetExParams; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XAddParams; import redis.clients.jedis.params.XAutoClaimParams; import redis.clients.jedis.params.XClaimParams; @@ -20,6 +21,7 @@ import redis.clients.jedis.params.ZAddParams; import redis.clients.jedis.params.ZIncrByParams; import redis.clients.jedis.params.LPosParams; +import redis.clients.jedis.resps.LCSMatchResult; public abstract class PipelineBase extends Queable implements BinaryRedisPipeline, RedisPipeline { @@ -2440,4 +2442,18 @@ public Response sendCommand(final byte[] sampleKey, final ProtocolComman getClient(sampleKey).sendCommand(cmd, args); return getResponse(BuilderFactory.RAW_OBJECT); } + + @Override + public Response strAlgoLCSStrings(final String strA, final String strB, + final StrAlgoLCSParams params) { + getClient("").strAlgoLCSStrings(strA, strB, params); + return getResponse(BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER); + } + + @Override + public Response strAlgoLCSStrings(final byte[] strA, final byte[] strB, + final StrAlgoLCSParams params) { + getClient("").strAlgoLCSStrings(strA, strB, params); + return getResponse(BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER); + } } diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index a29a301993..6a6ea31d08 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -268,7 +268,7 @@ public static enum Command implements ProtocolCommand { READONLY, READWRITE, GEOADD, GEODIST, GEOHASH, GEOPOS, GEORADIUS, GEORADIUS_RO, GEORADIUSBYMEMBER, GEORADIUSBYMEMBER_RO, MODULE, BITFIELD, HSTRLEN, TOUCH, SWAPDB, MEMORY, XADD, XLEN, XDEL, XTRIM, XRANGE, XREVRANGE, XREAD, XACK, XGROUP, XREADGROUP, XPENDING, XCLAIM, XAUTOCLAIM, ACL, XINFO, - BITFIELD_RO, LPOS, SMISMEMBER, ZMSCORE, BZPOPMIN, BZPOPMAX, BLMOVE, LMOVE, COPY, ROLE, FAILOVER; + BITFIELD_RO, LPOS, SMISMEMBER, ZMSCORE, BZPOPMIN, BZPOPMAX, BLMOVE, LMOVE, COPY, ROLE, FAILOVER, STRALGO; private final byte[] raw; @@ -290,7 +290,7 @@ public static enum Keyword implements Rawable { BLOCK, NOACK, STREAMS, KEY, CREATE, MKSTREAM, SETID, DESTROY, DELCONSUMER, MAXLEN, GROUP, ID, IDLE, TIME, RETRYCOUNT, FORCE, USAGE, SAMPLES, STREAM, GROUPS, CONSUMERS, HELP, FREQ, SETUSER, GETUSER, DELUSER, WHOAMI, CAT, GENPASS, USERS, LOG, INCR, SAVE, JUSTID, WITHVALUES, UNBLOCK, - NOMKSTREAM, MINID, DB, ABSTTL, TO, TIMEOUT, ABORT; + NOMKSTREAM, MINID, DB, ABSTTL, TO, TIMEOUT, ABORT, LCS, STRINGS; /** * @deprecated This will be private in future. Use {@link #getRaw()}. diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 576e767352..b62263a466 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -14,6 +14,7 @@ import redis.clients.jedis.params.GetExParams; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XAddParams; import redis.clients.jedis.params.XAutoClaimParams; import redis.clients.jedis.params.XClaimParams; @@ -23,6 +24,7 @@ import redis.clients.jedis.params.ZIncrByParams; import redis.clients.jedis.params.LPosParams; import redis.clients.jedis.resps.KeyedListElement; +import redis.clients.jedis.resps.LCSMatchResult; import redis.clients.jedis.util.Hashing; public class ShardedJedis extends BinaryShardedJedis implements JedisCommands, Closeable { @@ -1315,4 +1317,10 @@ public Object sendBlockingCommand(ProtocolCommand cmd, String... args) { Jedis j = getShard(sampleKey); return j.sendBlockingCommand(cmd, args); } + + @Override + public LCSMatchResult strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params) { + Jedis j = getShard(""); + return j.strAlgoLCSStrings(strA, strB, params); + } } diff --git a/src/main/java/redis/clients/jedis/commands/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/commands/BinaryJedisCommands.java index 80ba490b4a..9fd30d3bec 100644 --- a/src/main/java/redis/clients/jedis/commands/BinaryJedisCommands.java +++ b/src/main/java/redis/clients/jedis/commands/BinaryJedisCommands.java @@ -6,6 +6,7 @@ import redis.clients.jedis.*; import redis.clients.jedis.params.*; +import redis.clients.jedis.resps.LCSMatchResult; /** * Common interface for sharded and non-sharded BinaryJedis @@ -482,4 +483,6 @@ List xautoclaimJustId(byte[] key, byte[] groupName, byte[] consumerName, List xinfoConsumers(byte[] key, byte[] group); List xinfoConsumersBinary(byte[] key, byte[] group); + + LCSMatchResult strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/BinaryRedisPipeline.java b/src/main/java/redis/clients/jedis/commands/BinaryRedisPipeline.java index e456af4b3e..0b23be76e1 100644 --- a/src/main/java/redis/clients/jedis/commands/BinaryRedisPipeline.java +++ b/src/main/java/redis/clients/jedis/commands/BinaryRedisPipeline.java @@ -2,6 +2,7 @@ import redis.clients.jedis.*; import redis.clients.jedis.params.*; +import redis.clients.jedis.resps.LCSMatchResult; import java.util.List; import java.util.Map; @@ -450,4 +451,6 @@ Response> xautoclaimJustId(byte[] key, byte[] group, byte[] consume Response psetex(byte[] key, long milliseconds, byte[] value); Response hincrByFloat(byte[] key, byte[] field, double increment); + + Response strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/Commands.java b/src/main/java/redis/clients/jedis/commands/Commands.java index 6a9ea95c66..989536f62a 100644 --- a/src/main/java/redis/clients/jedis/commands/Commands.java +++ b/src/main/java/redis/clients/jedis/commands/Commands.java @@ -17,6 +17,7 @@ import redis.clients.jedis.params.ClientKillParams; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XAddParams; import redis.clients.jedis.params.XAutoClaimParams; import redis.clients.jedis.params.XClaimParams; @@ -578,4 +579,8 @@ void xautoclaimJustId(String key, String group, String consumerName, void xinfoGroup (String key); void xinfoConsumers (String key, String group); + + void strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params); + + void strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/JedisCommands.java b/src/main/java/redis/clients/jedis/commands/JedisCommands.java index c9438d291a..6928c5777e 100644 --- a/src/main/java/redis/clients/jedis/commands/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/commands/JedisCommands.java @@ -25,6 +25,7 @@ import redis.clients.jedis.params.GetExParams; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XAddParams; import redis.clients.jedis.params.XAutoClaimParams; import redis.clients.jedis.params.XClaimParams; @@ -34,6 +35,7 @@ import redis.clients.jedis.params.ZIncrByParams; import redis.clients.jedis.params.LPosParams; import redis.clients.jedis.resps.KeyedListElement; +import redis.clients.jedis.resps.LCSMatchResult; /** * Common interface for sharded and non-sharded Jedis @@ -689,4 +691,6 @@ Map.Entry> xautoclaimJustId(String key, Strin * to the the group */ List xinfoConsumers (String key, String group); + + LCSMatchResult strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryCommands.java b/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryCommands.java index f1fbfcf7c9..99d7a87efc 100644 --- a/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryCommands.java +++ b/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryCommands.java @@ -7,12 +7,14 @@ import redis.clients.jedis.ScanResult; import redis.clients.jedis.SortingParams; import redis.clients.jedis.Tuple; +import redis.clients.jedis.resps.LCSMatchResult; import redis.clients.jedis.ZParams; import redis.clients.jedis.args.*; import redis.clients.jedis.params.GeoRadiusParam; import redis.clients.jedis.params.GeoRadiusStoreParam; import redis.clients.jedis.params.XReadGroupParams; import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import java.util.List; import java.util.Map; @@ -157,4 +159,6 @@ Long georadiusStore(byte[] key, double longitude, double latitude, double radius Long georadiusByMemberStore(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam); + + LCSMatchResult strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryJedisClusterCommands.java b/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryJedisClusterCommands.java index 2b12209c38..cc58e20db8 100644 --- a/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryJedisClusterCommands.java +++ b/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryJedisClusterCommands.java @@ -11,8 +11,10 @@ import redis.clients.jedis.args.*; import redis.clients.jedis.params.GeoRadiusParam; import redis.clients.jedis.params.GeoRadiusStoreParam; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XReadGroupParams; import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.resps.LCSMatchResult; import java.util.List; import java.util.Map; @@ -143,4 +145,8 @@ Long georadiusStore(byte[] key, double longitude, double latitude, double radius Long georadiusByMemberStore(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam); + + LCSMatchResult strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params); + + LCSMatchResult strAlgoLCSStrings(final byte[] strA, final byte[] strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryRedisPipeline.java b/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryRedisPipeline.java index fb7fd3f2dc..8aa1770e76 100644 --- a/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryRedisPipeline.java +++ b/src/main/java/redis/clients/jedis/commands/MultiKeyBinaryRedisPipeline.java @@ -4,6 +4,7 @@ import redis.clients.jedis.GeoUnit; import redis.clients.jedis.Response; import redis.clients.jedis.SortingParams; +import redis.clients.jedis.resps.LCSMatchResult; import redis.clients.jedis.Tuple; import redis.clients.jedis.ZParams; import redis.clients.jedis.args.*; @@ -142,4 +143,6 @@ Response> xreadGroup(byte[] groupname, byte[] consumer, int count, Response> xreadGroup(byte[] groupname, byte[] consumer, XReadGroupParams xReadGroupParams, Map.Entry... streams); + + Response strAlgoLCSKeys(final byte[] keyA, final byte[] keyB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/MultiKeyCommands.java b/src/main/java/redis/clients/jedis/commands/MultiKeyCommands.java index 3067587b17..86fe73f39d 100644 --- a/src/main/java/redis/clients/jedis/commands/MultiKeyCommands.java +++ b/src/main/java/redis/clients/jedis/commands/MultiKeyCommands.java @@ -2,6 +2,7 @@ import redis.clients.jedis.BitOP; import redis.clients.jedis.GeoUnit; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.resps.KeyedZSetElement; import redis.clients.jedis.StreamEntryID; import redis.clients.jedis.JedisPubSub; @@ -257,4 +258,6 @@ Long georadiusStore(String key, double longitude, double latitude, double radius Long georadiusByMemberStore(String key, String member, double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam); + + LCSMatchResult strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/MultiKeyCommandsPipeline.java b/src/main/java/redis/clients/jedis/commands/MultiKeyCommandsPipeline.java index 40e698b0b9..61d68e2ace 100644 --- a/src/main/java/redis/clients/jedis/commands/MultiKeyCommandsPipeline.java +++ b/src/main/java/redis/clients/jedis/commands/MultiKeyCommandsPipeline.java @@ -151,4 +151,6 @@ Response>>> xreadGroup(String groupname Response>>> xreadGroup(String groupname, String consumer, XReadGroupParams xReadGroupParams, Map streams); + + Response strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/MultiKeyJedisClusterCommands.java b/src/main/java/redis/clients/jedis/commands/MultiKeyJedisClusterCommands.java index 76b6847c9b..38599c1f51 100644 --- a/src/main/java/redis/clients/jedis/commands/MultiKeyJedisClusterCommands.java +++ b/src/main/java/redis/clients/jedis/commands/MultiKeyJedisClusterCommands.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import redis.clients.jedis.params.StrAlgoLCSParams; public interface MultiKeyJedisClusterCommands { Boolean copy(String srcKey, String dstKey, boolean replace); @@ -163,4 +164,7 @@ List>> xreadGroup(String groupname, String c List>> xreadGroup(String groupname, String consumer, XReadGroupParams xReadGroupParams, Map streams); + LCSMatchResult strAlgoLCSKeys(final String keyA, final String keyB, final StrAlgoLCSParams params); + + LCSMatchResult strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/commands/RedisPipeline.java b/src/main/java/redis/clients/jedis/commands/RedisPipeline.java index d0571c58d7..d9cd1e87e6 100644 --- a/src/main/java/redis/clients/jedis/commands/RedisPipeline.java +++ b/src/main/java/redis/clients/jedis/commands/RedisPipeline.java @@ -17,6 +17,7 @@ import redis.clients.jedis.params.GetExParams; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.StrAlgoLCSParams; import redis.clients.jedis.params.XAddParams; import redis.clients.jedis.params.XAutoClaimParams; import redis.clients.jedis.params.XClaimParams; @@ -25,6 +26,7 @@ import redis.clients.jedis.params.ZAddParams; import redis.clients.jedis.params.ZIncrByParams; import redis.clients.jedis.params.LPosParams; +import redis.clients.jedis.resps.LCSMatchResult; import java.util.List; import java.util.Map; @@ -466,4 +468,6 @@ Response>> xautoclaimJustId(String Response psetex(String key, long milliseconds, String value); Response hincrByFloat(String key, String field, double increment); + + Response strAlgoLCSStrings(final String strA, final String strB, final StrAlgoLCSParams params); } diff --git a/src/main/java/redis/clients/jedis/params/StrAlgoLCSParams.java b/src/main/java/redis/clients/jedis/params/StrAlgoLCSParams.java new file mode 100644 index 0000000000..e75a5a9093 --- /dev/null +++ b/src/main/java/redis/clients/jedis/params/StrAlgoLCSParams.java @@ -0,0 +1,87 @@ +package redis.clients.jedis.params; + +import java.util.ArrayList; +import java.util.Collections; + +import redis.clients.jedis.Protocol; +import redis.clients.jedis.Protocol.Keyword; +import redis.clients.jedis.util.SafeEncoder; + +public class StrAlgoLCSParams extends Params { + + private static final String LCS = "lcs"; + private static final String IDX = "idx"; + private static final String LEN = "len"; + private static final String WITHMATCHLEN = "withmatchlen"; + private static final String MINMATCHLEN = "minmatchlen"; + + public StrAlgoLCSParams() { + } + + public static StrAlgoLCSParams StrAlgoLCSParams() { + return new StrAlgoLCSParams(); + } + + /** + * When IDX is given the command returns an array with the LCS length + * and all the ranges in both the strings, start and end offset for + * each string, where there are matches. + * @return StrAlgoParams + */ + public StrAlgoLCSParams idx() { + addParam(IDX); + return this; + } + + /** + * When LEN is given the command returns the length of the longest common substring. + * @return StrAlgoParams + */ + public StrAlgoLCSParams len() { + addParam(LEN); + return this; + } + + /** + * When WITHMATCHLEN is given each array representing a match will also have the length of the match. + * @return StrAlgoParams + */ + public StrAlgoLCSParams withMatchLen() { + addParam(WITHMATCHLEN); + return this; + } + + /** + * Specify the minimum match length. + * @return StrAlgoParams + */ + public StrAlgoLCSParams minMatchLen(long minMatchLen) { + addParam(MINMATCHLEN, minMatchLen); + return this; + } + + public byte[][] getByteParams(Keyword keyword, byte[] argA, byte[] argB) { + ArrayList byteParams = new ArrayList<>(); + byteParams.add(SafeEncoder.encode(LCS)); + byteParams.add(keyword.getRaw()); + byteParams.add(argA); + byteParams.add(argB); + + if (contains(IDX)) { + byteParams.add(SafeEncoder.encode(IDX)); + } + if (contains(LEN)) { + byteParams.add(SafeEncoder.encode(LEN)); + } + if (contains(WITHMATCHLEN)) { + byteParams.add(SafeEncoder.encode(WITHMATCHLEN)); + } + + if (contains(MINMATCHLEN)) { + byteParams.add(SafeEncoder.encode(MINMATCHLEN)); + byteParams.add(Protocol.toByteArray((long) getParam(MINMATCHLEN))); + } + + return byteParams.toArray(new byte[byteParams.size()][]); + } +} diff --git a/src/main/java/redis/clients/jedis/resps/LCSMatchResult.java b/src/main/java/redis/clients/jedis/resps/LCSMatchResult.java new file mode 100644 index 0000000000..4c4d67b18d --- /dev/null +++ b/src/main/java/redis/clients/jedis/resps/LCSMatchResult.java @@ -0,0 +1,106 @@ +package redis.clients.jedis.resps; + +import java.util.Collections; +import java.util.List; + +/** + * Result for STRALGO LCS command. + */ +public class LCSMatchResult { + private String matchString; + + private List matches; + + private long len; + + public LCSMatchResult(String matchString) { + this.matchString = matchString; + } + + public LCSMatchResult(long len) { + this.len = len; + } + + public LCSMatchResult(List matches, long len) { + this.matches = matches; + this.len = len; + } + + /** + * Creates new {@link LCSMatchResult}. + * + * @param matchString + * @param matches + * @param len + */ + public LCSMatchResult(String matchString, List matches, long len) { + this.matchString = matchString; + this.matches = Collections.unmodifiableList(matches); + this.len = len; + } + + public String getMatchString() { + return matchString; + } + + public List getMatches() { + return matches; + } + + public long getLen() { + return len; + } + + /** + * Match position in each string. + */ + public static class MatchedPosition { + + private final Position a; + + private final Position b; + + private final long matchLen; + + public MatchedPosition(Position a, Position b, long matchLen) { + this.a = a; + this.b = b; + this.matchLen = matchLen; + } + + public Position getA() { + return a; + } + + public Position getB() { + return b; + } + + public long getMatchLen() { + return matchLen; + } + } + + /** + * Position range. + */ + public static class Position { + + private final long start; + + private final long end; + + public Position(long start, long end) { + this.start = start; + this.end = end; + } + + public long getStart() { + return start; + } + + public long getEnd() { + return end; + } + } +} diff --git a/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java index 8911f91ab4..d2d2bf10db 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java @@ -9,8 +9,11 @@ import org.junit.Test; +import redis.clients.jedis.resps.LCSMatchResult; +import redis.clients.jedis.resps.LCSMatchResult.MatchedPosition; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.params.GetExParams; +import redis.clients.jedis.params.StrAlgoLCSParams; public class StringValuesCommandsTest extends JedisCommandTestBase { @Test @@ -253,4 +256,74 @@ public void psetex() { long ttl = jedis.ttl("foo"); assertTrue(ttl > 0 && ttl <= 20000); } + + @Test + public void strAlgoLcsWithLen() { + LCSMatchResult stringMatchResult = jedis.strAlgoLCSStrings("ohmytext", "mynewtext", + StrAlgoLCSParams.StrAlgoLCSParams().len()); + assertEquals(stringMatchResult.getLen(), 6); + } + + @Test + public void strAlgoLcs() { + LCSMatchResult stringMatchResult = jedis.strAlgoLCSStrings("ohmytext", "mynewtext", + StrAlgoLCSParams.StrAlgoLCSParams()); + assertEquals(stringMatchResult.getMatchString(), "mytext"); + } + + @Test + public void strAlgoLcsWithIdx() { + LCSMatchResult stringMatchResult = jedis.strAlgoLCSStrings("ohmytext", "mynewtext", + StrAlgoLCSParams.StrAlgoLCSParams().idx().withMatchLen()); + assertEquals(stringMatchResult.getLen(), 6); + assertEquals(2, stringMatchResult.getMatches().size()); + + MatchedPosition position0 = stringMatchResult.getMatches().get(0); + assertEquals(position0.getA().getStart(), 4); + assertEquals(position0.getA().getEnd(), 7); + assertEquals(position0.getB().getStart(), 5); + assertEquals(position0.getB().getEnd(), 8); + assertEquals(position0.getMatchLen(), 4); + + MatchedPosition position1 = stringMatchResult.getMatches().get(1); + assertEquals(position1.getA().getStart(), 2); + assertEquals(position1.getA().getEnd(), 3); + assertEquals(position1.getB().getStart(), 0); + assertEquals(position1.getB().getEnd(), 1); + assertEquals(position1.getMatchLen(), 2); + } + + @Test + public void strAlgoLcsWithKey() { + jedis.mset("key1", "ohmytext", "key2", "mynewtext"); + + LCSMatchResult stringMatchResult = jedis.strAlgoLCSKeys("key1", "key2", + StrAlgoLCSParams.StrAlgoLCSParams()); + assertEquals(stringMatchResult.getMatchString(), "mytext"); + } + + @Test + public void strAlgoLcsWithKeyAndIdx() { + jedis.mset("key1", "ohmytext", "key2", "mynewtext"); + + LCSMatchResult stringMatchResult = jedis.strAlgoLCSKeys( "key1", "key2", + StrAlgoLCSParams.StrAlgoLCSParams().idx().withMatchLen()); + assertEquals(stringMatchResult.getLen(), 6); + assertEquals(2, stringMatchResult.getMatches().size()); + + MatchedPosition position0 = stringMatchResult.getMatches().get(0); + assertEquals(position0.getA().getStart(), 4); + assertEquals(position0.getA().getEnd(), 7); + assertEquals(position0.getB().getStart(), 5); + assertEquals(position0.getB().getEnd(), 8); + assertEquals(position0.getMatchLen(), 4); + + MatchedPosition position1 = stringMatchResult.getMatches().get(1); + assertEquals(position1.getA().getStart(), 2); + assertEquals(position1.getA().getEnd(), 3); + assertEquals(position1.getB().getStart(), 0); + assertEquals(position1.getB().getEnd(), 1); + assertEquals(position1.getMatchLen(), 2); + } + }