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

Redis里怎么搞C语言那种模糊匹配,实际操作和思路分享

行,那咱们就直接聊 Redis 里怎么实现类似 C 语言那种字符串模糊匹配的效果。

C 语言里你可能会用 strstr() 找子串,或者用通配符匹配,但在 Redis 里,数据是放在内存键值对中的,你不能直接像遍历本地内存一样去搜每个键的内容,所以得用 Redis 自己提供的一些命令和技巧。

下面我分几个实际的操作方法和思路来说。


对键(key)进行模糊匹配

Redis 本身支持在键名上用通配符查找,主要命令是 KEYSSCAN

  • KEYS pattern
    比如你存了很多键:user:1001user:1002product:2001,想找所有以 user: 开头的键,可以:
    KEYS user:*

    匹配任意多个字符,类似 C 语言如果用 fnmatch() 时的 。
    还有 匹配一个字符,[abc] 匹配括号内的某一个字符。

KEYS 命令在生产环境慎用,因为它会一次性遍历所有键,如果数据量大,会阻塞 Redis 其他操作。

  • SCAN 命令
    这是推荐的方式,增量迭代所有键,不会阻塞太久。
    比如想找 user:*
    SCAN 0 MATCH user:* COUNT 100

    每次返回一部分匹配的键和一个新的游标,你用新游标继续扫描,直到游标为 0 结束。
    这就像 C 语言里你遍历一个很大的数组,分段处理,避免长时间卡住。

    Redis里怎么搞C语言那种模糊匹配,实际操作和思路分享


对值(value)进行模糊匹配

Redis 的 value 可能是 string、hash、list 等结构,Redis 原生命令并不支持直接对任意 value 内容进行模糊搜索(像 SQL 的 LIKE '%abc%')。
所以需要一些变通方法:

二次查询——用键名关联
如果你知道要搜索的内容可能会出现在哪些键里,可以先用 SCAN 拿到键名,再逐个用 GETHGET 等取出来,在客户端用程序代码(Python/Java 的字符串包含判断)做匹配。
这相当于在 C 语言里先确定可能的内存范围,再逐个用 strstr() 检查。
缺点:性能差,数据量大时网络和计算开销大。

维护反向索引
比如你要在字符串值里搜索包含 “apple” 的键,可以额外维护一个集合(Set)或有序集合(Sorted Set),键名为 index:apple,里面存放所有值包含 “apple” 的键的 ID。
当新增数据时,客户端负责提取关键词,然后往对应的索引集合里添加这个数据的键。
搜索时,直接 SMEMBERS index:apple 就能拿到所有包含 “apple” 的键。
这就像 C 语言里事先建立好关键词的哈希表,用空间换时间。

用 RedisSearch 模块(Redis Modules)
Redis 本身不具备全文搜索,但 RediSearch 是一个官方推荐的模块,提供了类似 Elasticsearch 的倒排索引功能。
你可以这样用:

Redis里怎么搞C语言那种模糊匹配,实际操作和思路分享

FT.CREATE myIndex ON HASH PREFIX 1 doc: SCHEMA title TEXT body TEXT
FT.SEARCH myIndex "apple"

它会返回所有包含 “apple” 的哈希键。
这就很强大了,几乎相当于在 Redis 内部实现了高效的字符串模糊匹配,而不需要客户端二次处理。


实际例子:用 Lua 脚本在 Redis 内部做匹配

如果不想用外部模块,又希望减少网络传输,可以用 Redis Lua 脚本在服务器端执行简单的匹配。

比如在 Lua 里用 string.find() 来模拟 C 语言的模糊匹配:

-- 假设我们遍历匹配某个 pattern 的键,并检查值是否包含 "abc"
local keys = redis.call('KEYS', ARGV[1])  -- 先匹配键模式,生产环境应用 SCAN 代替 KEYS
local results = {}
for i, key in ipairs(keys) do
    local val = redis.call('GET', key)
    if string.find(val, ARGV[2]) then
        table.insert(results, key)
    end
end
return results

调用:

EVAL "lua脚本内容" 0 "user:*" "abc"

这样所有键名符合 user:* 且值包含 "abc" 的键会被返回。
但注意,Lua 里用 KEYS 还是有性能问题,Lua 执行会阻塞其他命令,数据量大时不可取。


总结思路

  • 键的模糊匹配:用 SCAN + MATCH,安全。
  • 值的模糊匹配
    • 小数据量可以在客户端做;
    • 大数据量需要预先建立索引(集合或有序集合维护关键词到键的映射);
    • 或者直接使用 RediSearch 模块做全文搜索。
  • 类似 C 语言的灵活匹配:Redis 不直接支持对值的通配符搜索,要么用 Lua 在服务端做(不推荐大数据),要么设计好键名和索引结构。

其实本质就是利用 Redis 的数据结构特点,把模糊查询转换成精确的集合查询,避免全扫描,这跟 C 语言里直接操作内存不同,但思路类似——要么遍历(慢),要么索引(快)。