如何获取与redis中特定模式不匹配的键?

时间:2015-04-29 11:36:38

标签: redis

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

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

现在,我想要打印所有不以user开头的密钥。 我怎么能这样做?

4 个答案:

答案 0 :(得分:23)

重要提示:始终使用SCAN代替(邪恶KEYS
do not use <code>KEYS</code>

Redis'模式匹配在某种程度上受到功能限制(请参阅util.c中的stringmatchlen的实现),并未提供您寻求ATM的内容。也就是说,考虑以下可能的路线:

  1. 扩展stringmatchlen以符合您的要求,可能会将其作为公关提交。
  2. 考虑一下你要做的事情 - 除非你为它们编制索引,否则获取一个密钥子集总是效率低下,考虑跟踪所有非用户密钥的名称(即Redis集中的ieg)。
  3. 如果你真的坚持扫描整个键区并匹配负面模式,那么实现这一点的一种方法就是使用Lua魔法。
  4. 考虑以下数据集和脚本:

    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"
    

答案 1 :(得分:7)

@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"

答案 2 :(得分:4)

根据redis keys documentation,该命令支持 glob 样式模式,不是正则表达式

如果你查看文档,你会看到&#34;!&#34;字符与正则表达式的对立面并不特殊。

这是我在自己的数据库中运行的一个简单测试:

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删除它们

答案 3 :(得分:0)

这里有一个使用原生 redis 命令(不需要 Lua 脚本或任何东西)来实现这一点的技巧。

如果您能够控制插入新密钥的时间(您想要保留的密钥,删除问题中的所有其他内容),您可以:

  1. 在设置新密钥之前,将过期时间设置为所有现有密钥(按模式或所有内容)立即过期 (see how)
  2. 加载新密钥

Redis 会自动删除所有旧的键,而你只会留下你想要的新键。