当前位置:首页 > 问答 > 正文

Redis里怎么用模糊匹配找Key,正则啥的能不能用起来试试看

在Redis里,你想用模糊匹配的方式找Key,这个需求非常普遍,比如你想看看所有以“user:session:”开头的会话键,或者找出所有包含“temp”的临时键,Redis确实提供了这样的功能,但和你平时在编程里用的正则表达式不太一样,它更简单直接,用的是通配符的模式。

Redis的通配符怎么玩?

Redis主要通过KEYS命令来实现模糊查找,这个命令支持两个特殊的符号:

  1. (星号):这个符号代表“任意数量的任意字符”,你可以把它想象成Windows系统里搜索文件时用的。

    • 你想找所有以“user:”开头的key,就可以用KEYS user:*,这会匹配到user:1001user:profile:1001user:等等。
    • 你想找所有以“123”结尾的key,就用KEYS *123
    • 你想找所有包含“cache”的key,就用KEYS *cache*
  2. (问号):这个符号代表“一个任意字符”,它比星号更精确一点,只占一个字符的位置。

    • KEYS user:? 会匹配像user:1user:A这样的key,但不会匹配user:10user:AB,因为只能代表一个字符。
    • KEYS h?llo 会匹配hallohbllohcllo等。
  3. 字符类(这个稍微高级一点点,但也很简单):用方括号[]表示,匹配方括号内的任意一个字符。

    • KEYS user:[13579] 会匹配user:1user:3user:5user:7user:9,也就是匹配一位奇数的用户ID。
    • KEYS h[ae]llo 会匹配hallohello

重要警告:KEYS命令不能在生产环境乱用!

根据Redis官方文档(来源:Redis官方文档对KEYS命令的说明)的明确警告,KEYS命令是一个非常危险的命令,尤其是在数据量大的生产环境中,原因是:Redis是单线程的,当你在一个拥有数百万个key的Redis实例上执行KEYS *时,这个命令会一次性遍历所有key,并返回所有匹配的结果,在这个命令执行期间,Redis的主线程会被完全阻塞,无法处理任何其他的读写请求,这会导致你的服务瞬间不可用,看起来就像“卡死了”一样。

虽然KEYS命令在测试或者数据量极小的时候用起来很方便,但正规的做法是绝对避免在生产环境使用

那在生产环境该怎么安全地模糊匹配?

既然KEYS命令这么危险,Redis提供了一个安全的替代方案:SCAN命令。

SCAN命令的核心思想是“迭代式遍历”,它不会一次性返回所有结果,而是每次只返回一小部分(比如几十个或几百个),并给你一个“游标”(cursor),你可以拿着这个游标,再次调用SCAN,它就会从上次停下的地方继续遍历,这样就把一个庞大的、可能阻塞服务的操作,拆分成很多个微不足道的小操作,对服务的影响就降到了最低。

SCAN的用法稍微复杂一点点:

  1. 第一次调用时,游标从0开始:SCAN 0 MATCH user:*
  2. Redis会返回两个东西:一个是“下一次迭代的游标”(比如是17),另一个是本次扫描到的key的列表。
  3. 你接着用新的游标调用:SCAN 17 MATCH user:*
  4. 重复这个过程,直到Redis返回的下一个游标是0,这表示整个遍历已经完成。

这里的MATCH参数就是用来做模糊匹配的,它使用的通配符规则和KEYS命令一模一样(, , [])。

SCAN命令的好处是显而易见的:无阻塞、可控制,你可以在应用程序里写一个循环,慢慢地、分批地把所有想要的key找出来,同时Redis还能正常服务其他请求,缺点是编程上稍微麻烦一点,而且因为它是在整个数据集中迭代,可能会返回重复的key(但集合去重很容易),而且在整个遍历过程中,如果数据有变化(有新增或删除的key),可能会体现得不完全一致。

关于正则表达式

现在来回答你的第二个问题:“正则啥的能不能用起来试试看?”

答案是:Redis的命令行本身不支持你想象中的那种复杂的正则表达式。

你不能在KEYSSCAN命令里直接写像\d+(匹配数字)或者[a-zA-Z](匹配字母)这样的完整正则表达式,Redis只支持上面提到的, , []这三种比较简单的通配符模式。

这并不意味着你完全没办法,变通的方法是在客户端处理,具体思路是:

  1. 放宽条件扫描:先用SCAN命令,用一个比较宽泛的模式(比如直接用,或者user:*这样的前缀)把可能相关的key都扫描出来,因为SCAN是安全的,所以即使扫描的key多一点,只要分批进行,问题也不大。
  2. 客户端用正则过滤:在你的应用程序里(比如用Python、Java、Go写的程序),拿到这一批key之后,再用你熟悉的、强大的正则表达式库对这些key进行二次过滤,这样,你就可以使用任何复杂的正则规则了。

你想找出所有以“user:”开头,后面紧跟纯数字的key,Redis的通配符user:*会匹配user:123也会匹配user:abc,不够精确,你可以这样做:

  • 用Redis的 SCAN 0 MATCH user:* 分批获取所有以“user:”开头的key。
  • 在Python程序中,对返回的key列表使用 re.match(r'^user:\d+$', key) 来进行判断,只保留那些符合“user:纯数字”规则的key。

总结一下

  • 快速测试用 KEYS:在本地开发环境或者数据极少的情况下,可以用KEYS pattern来快速查找,方便直接。
  • 生产环境用 SCAN:在任何正式上线的服务中,坚决使用SCAN命令来安全地、非阻塞地进行模糊查找。
  • 复杂正则客户端做:Redis本身不支持复杂正则,如果你的匹配规则超出了、、[]的能力范围,就在用SCAN拿到初步结果后,在应用程序代码里用正则表达式进行过滤。

记住最关键的一点:保护生产环境,远离KEYS命令。

Redis里怎么用模糊匹配找Key,正则啥的能不能用起来试试看