使用Redis按需搜索(“包含”类型搜索,而不是“开头为”类型搜索)

时间:2019-11-07 12:43:35

标签: search redis autocomplete

我正在使用Redis开发按需搜索功能。我需要的搜索类型是“ 包括”类型搜索,而不是是“ 开头”类型搜索。我已经知道ZRANGEBYLEX非常适合“ 开头”搜索,但无法满足我的需求。例如,如果用户键入“ a”,他们将看到“ A lly”,“ a vril”,“ D a ve”和“ Lind a ”。如果他们键入“ av”,他们将看到“ av ril”和“ D av e”。搜索还必须不区分大小写,并返回N个结果,按字母顺序排序。

  1. 对于这种类型的搜索,是否有任何方法可以克服线性时间?
  2. 如果没有,您是否看到优化以下线性时间算法的任何方法?

要存储:

  • 创建一个名为“用户”的设置键
  • 对于每个用户,请添加“用户”,“ {小写用户名}:{原始用户名}”

要搜索:

  • 运行SCARD以获取集合的大小
  • 在小写搜索词上使用MATCH运行单个SSCAN(并指定比SCARD大的COUNT)以获取所有匹配项
  • 从匹配的每个条目中删除小写的用户名
  • 按字母顺序对结果进行排序
  • 返回前N个结果

一些其他注意事项: 用户数上限为20,000。这就是为什么我只用光标做一个SSCAN而不循环播放的原因。

谢谢!

1 个答案:

答案 0 :(得分:1)

您可以使用排序集构建n元语法索引:

Ally 的n-gram列表是:

  • a al all ally
  • l ll lly
  • l ly
  • y

对于每个n-gram,调用ZADD以将项目添加到排序集中。每个项目包括3个部分:

n-gram-in-lowercase : word-in-lowercase : original-word

例如:

zadd kkk 0 a:ally:Ally 0 al:ally:Ally 0 all:ally:Ally 0 ally:ally:Ally
zadd kkk 0 l:ally:Ally 0 ll:ally:Ally 0 lly:ally:Ally
zadd kkk 0 l:ally:Ally 0 ly:ally:Ally
zadd kkk 0 y:ally:Ally

索引所有单词后,您可以使用ZRANGEBYLEX命令进行搜索:

127.0.0.1:6379> zrangebylex kkk [a "[a\xff" limit 0 10
 1) "a:ally:Ally"
 2) "a:avril:avril"
 3) "a:dave:Dave"
 4) "a:linda:Linda"
 5) "al:ally:Ally"
 6) "all:ally:Ally"
 7) "ally:ally:Ally"
 8) "av:avril:avril"
 9) "av:dave:Dave"
10) "ave:dave:eDave"

结果已排序,但可能包含重复项,因此您需要在客户端删除这些重复项。

此解决方案将建立一个很大的索引,还有另一种解决方案可以通过在客户端上进行额外的工作来减小索引大小:仅n-gram索引的索引部分:< / p>

zadd k 0 ally:Ally
zadd k 0 lly:Ally
zadd k 0 ly:Ally
zadd k 0 y:Ally

搜索时,ZRANGEBYLEX命令 的结果未排序,并且可能包含重复的项目 。因此,您需要删除重复的项目并在客户端对结果进行排序。另外,由于未排序,因此无法使用LIMIT offset count选项,而必须检索所有匹配项以找出前N个匹配项。