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

Redis怎么搞模糊查询还能分页,感觉挺实用的功能分享

说到Redis,大家首先想到的就是快,常用来做缓存,但它主要是键值对存储,不像数据库那样有直接的like查询和limit分页,通过巧妙使用Redis提供的一些数据结构,完全可以实现类似“模糊查询+分页”的效果,而且性能非常高,这在处理一些需要快速过滤和浏览的热数据场景时,非常实用。

这里分享几种常见且实用的方法,咱们由浅入深地说。

使用有序集合(ZSet)配合扫描(ZSCAN)

这个方法的思路是,把我们要查询的数据作为成员(member)存放在一个有序集合里,分数(score)可以用来排序,比如用时间戳,然后利用ZSCAN命令进行模糊匹配。

具体怎么搞呢?

  1. 准备数据: 假设我们有一堆用户昵称需要被模糊搜索,我们把所有昵称作为成员(member)放入一个叫user:nicknames的ZSet中,分数可以统一设为0,或者如果你希望按热度、时间排序,可以设置成对应的数值。

    • 命令示例:ZADD user:nicknames 0 "张三" 0 "张无忌" 0 "李四" 0 "李小龙"
  2. 进行模糊查询和分页: ZSCAN命令可以遍历ZSet,并且支持通配符匹配,它返回的结果是一个游标和一批匹配的成员。

    • 模糊查询: 比如我们要找所有以“张”开头的昵称,我们可以使用ZSCAN命令,匹配模式设为张*
    • 分页: ZSCAN命令的游标机制天然支持分页,第一次调用时,游标从0开始,命令会返回一个新的游标和一部分数据,下次查询时带上这个新游标,就能获取下一批数据,直到游标变回0,表示遍历结束。

操作示例: 假设我们要分页查询“张”开头的用户,每页2条。

Redis怎么搞模糊查询还能分页,感觉挺实用的功能分享

  • 第一页:ZSCAN user:nicknames 0 MATCH "张*" COUNT 2
    • 返回结果可能包含游标(比如18)和成员 ["张三", "张无忌"]
  • 第二页:ZSCAN user:nicknames 18 MATCH "张*" COUNT 2
    • 因为匹配项可能就两个,所以这次返回的游标可能就是0,表示没有更多数据了。

优点:

  • 实现相对简单,利用了Redis原生命令。
  • 适合数据量不是特别巨大的场景。

缺点:

  • 如果ZSet非常大,ZSCAN的效率可能会受到影响,因为它本质是遍历。
  • 分页的“页”的大小(COUNT参数)只是个提示,Redis返回的数据量可能略多于或少于指定值,需要客户端做简单处理。

使用集合(Set)或有序集合(ZSet)建立索引

这个方法更高效,尤其适合数据量大、查询频繁的场景,核心思想是“空间换时间”,提前为可能被搜索的字段建立好索引。

具体怎么搞?

我们还是以搜索用户昵称为例,但这次用户信息是存储在Hash结构里的,键名是user:1, user:2等。

Redis怎么搞模糊查询还能分页,感觉挺实用的功能分享

  1. 建立索引: 我们为昵称的每个可能的前缀(或者分词)建立索引集合。

    • 比如用户“张三”,我们将其昵称按前缀拆分(可以按字,也可以按拼音首字母):
      • 前缀为“张”的集合:index:nickname:张
      • 前缀为“张三”的集合:index:nickname:张三
    • 将用户ID(比如1)加入到这些集合中:SADD index:nickname:张 1SADD index:nickname:张三 1
  2. 进行模糊查询:

    • 当用户输入“张”进行搜索时,我们直接取index:nickname:张这个集合,里面就包含了所有昵称以“张”开头的用户ID。
    • 如果输入“张三”,就取index:nickname:张三这个更精确的集合。
  3. 实现分页:

    • 拿到索引集合后(比如index:nickname:张),我们可以使用SMEMBERS获取所有ID(如果集合不大),但更优雅的方式是使用SORT命令。
    • 我们可以使用 SORT index:nickname:张 BY nosort GET user:*->nickname LIMIT 0 2
    • 这个命令的意思是:对集合index:nickname:张进行排序(BY nosort表示不排序,按存储顺序),然后通过GET指令去取出每个ID对应的Hash结构中的昵称字段,最后用LIMIT实现分页。

优点:

  • 查询速度极快,几乎是O(1)的复杂度,因为直接定位到了索引集合。
  • 非常适合前缀匹配型的模糊查询。

缺点:

  • 需要额外的存储空间来存放索引。
  • 写入数据时(新增、修改昵称)需要维护索引,会增加写操作的复杂度,比如改昵称,需要从旧索引集合中删除ID,再加入新的索引集合。

使用RedisSearch模块(终极利器)

Redis怎么搞模糊查询还能分页,感觉挺实用的功能分享

如果条件允许,这是最强大、最省心的方案,RedisSearch是一个外部模块,为Redis提供了完整的全文搜索和二级索引功能,就像在Redis里内置了一个搜索引擎。

它能做什么?

  1. 创建索引: 你可以定义一个索引模式,指定哪些Hash字段需要被索引,以及索引类型(文本、数字、标签等)。
  2. 自动管理: 之后,你往对应的Hash里添加数据时,RedisSearch会自动更新索引,无需手动维护。
  3. 强大查询: 支持丰富的查询语法,包括模糊查询(通配符)、联合查询、范围查询、排序等。
  4. 直接分页: 查询命令直接支持LIMIT offset count参数,实现完美的分页。

操作示例(简化概念):

  • 创建索引:FT.CREATE user_idx ON HASH PREFIX 1 user: SCHEMA nickname TEXT
  • 插入数据:HSET user:1 nickname "张三"
  • 模糊查询加分页:FT.SEARCH user_idx "张*" LIMIT 0 2

优点:

  • 功能强大,媲美专业搜索引擎。
  • 使用简单,无需在应用层处理复杂的索引逻辑。
  • 性能优异。

缺点:

  • 需要安装RedisSearch模块,对Redis环境有要求(比如云服务商可能不支持或需额外收费)。

  • 小打小闹,数据量不大:用ZScan方法,简单快捷。
  • 追求高性能,查询模式固定(如前缀搜索):用预建索引方法,空间换时间,效果显著。
  • 不差钱,需求复杂,想要一劳永逸:直接上RedisSearch,这是最正统、最专业的解决方案。

希望这些直接的方法分享能给你带来启发,具体用哪种,还得看你的实际业务场景和技术选型。