如何获取与Redis中特定模式不匹配的密钥?

5jvtdoz2  于 2022-12-03  发布在  Redis
关注(0)|答案(5)|浏览(211)

在Redis中,keys user*将打印所有以user开头的密钥。例如:

keys user*
1) "user2"
2) "user1"

现在,我想打印所有不是以user开头的键。我该怎么做呢?

oyxsuwqo

oyxsuwqo1#

**重要提示:**始终使用SCAN而不是(邪恶KEYS

Redis的模式匹配在功能上有一定的局限性(参见util. c中stringmatchlen的实现),并且不能提供ATM所需要的模式匹配。
1.扩展stringmatchlen以满足您的要求,可能将其作为PR提交。
1.考虑一下你要做的事情--获取键的子集总是效率低下的,除非你索引它们,考虑跟踪所有非用户键的名字(比如在Redis集合中)。
1.如果您真的坚持要扫描整个键空间并与否定模式进行匹配,那么一种实现方法就是使用一点Lua魔法。
请考虑以下数据集和脚本:

127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> set user:1 1
OK
127.0.0.1:6379> set use:the:force luke
OK
127.0.0.1:6379> set non:user a
OK

Lua(保存为scanregex.lua):

local re = ARGV[1]
local nt = ARGV[2]

local cur = 0
local rep = {}
local tmp

if not re then
  re = ".*"
end

repeat
  tmp = redis.call("SCAN", cur, "MATCH", "*")
  cur = tonumber(tmp[1])
  if tmp[2] then
    for k, v in pairs(tmp[2]) do
      local fi = v:find(re) 
      if (fi and not nt) or (not fi and nt) then
        rep[#rep+1] = v
      end
    end
  end
until cur == 0
return rep

输出-第一次常规匹配,第二次补码:

foo@bar:~$ redis-cli --eval scanregex.lua , "^user"
1) "user:1"
foo@bar:~$ redis-cli --eval scanregex.lua , "^user" 1
1) "use:the:force"
2) "non:user"
wkyowqbh

wkyowqbh2#

@Karthikeyan Gopall你在上面的评论中钉住了它,这为我节省了一大堆时间。谢谢!
以下是您如何以各种组合方式使用它来获得您想要的:

redis.domain.com:6379[1]> set "hello" "foo"
OK
redis.domain.com:6379[1]> set "hillo" "bar"
OK
redis.domain.com:6379[1]> set "user" "baz"
OK
redis.domain.com:6379[1]> set "zillo" "bash"
OK
redis.domain.com:6379[1]> scan 0
1) "0"
2) 1) "zillo"
   2) "hello"
   3) "user"
   4) "hillo"
redis.domain.com:6379[1]> scan 0 match "[^u]*"
1) "0"
2) 1) "zillo"
   2) "hello"
   3) "hillo"
redis.domain.com:6379[1]> scan 0 match "[^u^z]*"
1) "0"
2) 1) "hello"
   2) "hillo"
redis.domain.com:6379[1]> scan 0 match "h[^i]*"
1) "0"
2) 1) "hello"
dw1jzc5e

dw1jzc5e3#

根据redis keys documentation,该命令支持glob样式模式,不支持正则表达式
并且如果您查看文档,就会发现“!”字符并不像正则表达式那样特殊。
下面是我在自己的数据库中运行的一个简单测试:

redis 127.0.0.1:6379> set a 0
OK
redis 127.0.0.1:6379> set b 1
OK
redis 127.0.0.1:6379> keys *
1) "a"
2) "b"
redis 127.0.0.1:6379> keys !a   
(empty list or set)                       // I expected "b" here
redis 127.0.0.1:6379> keys !b
(empty list or set)                       // I expected "a" here
redis 127.0.0.1:6379> keys [!b]
1) "b"
redis 127.0.0.1:6379> keys [b]
1) "b"
redis 127.0.0.1:6379> keys [ab]
1) "a"
2) "b"
redis 127.0.0.1:6379> keys ![b]
(empty list or set)

所以我不认为你想通过keys命令实现的目标是可能的。
此外,keys命令不太适合生产环境,因为它会锁定整个redis数据库。
我建议使用scan命令获取所有密钥,将它们存储在本地,然后使用LUA删除它们

o4tp2gmn

o4tp2gmn4#

这里有一个技巧可以用原生的redis命令来实现这一点(不需要Lua脚本或任何东西)。
如果您能够控制插入新密钥(您希望保留的密钥,删除所有其他内容,如您的问题)的时间,您可以:
1.在设置新密钥之前,请将所有现有密钥的过期时间设置为立即过期(see how)(按模式或所有方式)
1.加载新密钥
Redis会自动删除所有旧的密钥,而你只剩下你想要的新密钥。

6za6bjd0

6za6bjd05#

您还可以打印所有键并将其传递给grep。例如:

redis-cli -a <password> keys "*" | grep -v "user"

相关问题