Code前端首页关于Code前端联系我们

Redis实现轻量级搜索引擎的简单演示!

terry 2年前 (2023-09-25) 阅读数 50 #后端开发
Redis实现轻量级的搜索引擎简单 Demo!

图片来自Pexels

但是有些查询条件极其复杂,再加上库表的各种不合理设计,导致查询接口写起来特别困难,那就更不用谈超时了(不知道有没有这样的事)对于这种感觉你会怎么说呢~)。

让我们从一个例子开始。这是购物网站的搜索词。如果让你实现这样一个搜索界面,你会如何实现?

当然你说借助Elasticsearch等搜索引擎肯定能到达。但这里我想说的是如果你想自己做怎么办? Redis实现轻量级的搜索引擎简单 Demo!

如上图所示,搜索分为6个类别,每个类别又分为子类别。

在中间,主要条件类别之间有一个交叉点。每个子类别包括单选、多选和自定义情况。最后发出符合条件的结果集。

好,既然需求明确了,那我们就开始实现吧。 1。实施

第一位申请者是A同学。他是SQL编写界的“专家”。小A自信地说:“不只是一个查询接口?条件很多,但以我丰富的SQL经验,这对我来说不是问题。” 他是这样写这段代码的(这里以MySQL为例):

select ... from table_1
left join table_2
left join table_3
left join (select ... from table_x where ...) tmp_1
...
where ...
order by ...
limit m,n

代码在测试环境中运行,结果似乎相符,所以可以预发布了。正是有了这个初步的介绍,问题才开始出现。

预发布的目的是让线上环境尽可能真实,所以数据量自然比测试的要大很多。那么对于如此复杂的SQL,其执行效率可想而知。测试同学坚定地打回了小A的代码。 2。实施

总结小A失败的教训,小B开始优化SQL。首先它通过explain关键字进行SQL性能分析,并在添加索引的地方添加索引。

将一条复杂的SQL同时拆分成多条SQL,计算结果在程序内存中计算。 伪代码如下:

$result_1 = query('select ... from table_1 where ...');
$result_2 = query('select ... from table_2 where ...');
$result_3 = query('select ... from table_3 where ...');
...

$result = array_intersect($result_1, $result_2, $result_3, ...);

这个方案在性能上明显比第一个方案好很多,但是产品经理在接受功能的时候还是觉得查询速度不够快。

小B自己都知道,每个查询都会多次查询数据库,而且由于某些历史原因,在某些条件下单表查询无法执行,所以查询的等待时间是不可避免的。 3。实现

小C从上面的方案中看到了一种优化的可能。他发现B的想法没有问题。他将复合标准进行拆分,计算每个子维度的结果集,最后将所有子结果集进行聚合组合,得到想要的最终结果。

所以你突然想知道是否可以预先缓存每个子维度的结果集。这将允许他在查询时直接检索所需的子集,而不必每次都检查数据库进行计算。

这里小C使用Redis来存储缓存数据。使用它的主要原因是它提供了多种数据结构,并且非常容易对Redis中的集合执行交集和合并操作。 具体设计如图:

Redis实现轻量级的搜索引擎简单 Demo!

对于每个条件,将计算出的结果集ID预先存储在对应的Key中,选择的数据结构就是Setting。

查询操作为:

  • 子类别单选:直接根据Key条件得到对应的结果集。
  • 选择多个子类别:根据多个条件的key进行连接操作,得到正确的结果集。
  • 最终结果: 将得到的所有子类别的结果集进行交集运算,得到最终结果。

这其实就是所谓的反向索引。在这里您发现缺少价格条件。从需求中可以看出,价格条件是一个范围,而且是无限的。 所以前面提到的穷举条件的key-value方法是不可能的。这里我们使用另一个 Redis 数据结构来实现,有序集:

Redis实现轻量级的搜索引擎简单 Demo!

将所有以价格为键、以商品 ID 为值的商品添加到有序集中,每个值对应的分数就是该商品的值产品的核心就是价格。

这样就可以使用ZRANGEBYSCORE命令根据Redis有序集中的分数(价格)范围得到合适的结果集。

至此方案3优化完成,数据查询和计算通过缓存分开。

每次搜索时,只需搜索Redis几次即可得到结果。投票率符合验收要求。 扩展

①分页

这里你可能发现了一个严重的操作错误,列表查询中怎么没有分页。是的,我们立即看看Redis是如何实现分页的。

铺装主要是选择。为了简单起见,我们以创建时间为例。如图:

Redis实现轻量级的搜索引擎简单 Demo!

图中蓝色部分是按照创建时间排序的产品集合。蓝色下方的结果集是条件计算的结果。使用ZINTERSTORE命令,结果集的权重为0,乘积时间结果为1,将交集得到的结果集赋给新的创建时间分数有序集。

对新结果集进行操作,可以获得分页所需的全部数据:

  • 总页数:ZCOUNT 命令。

  • 当前页面内容:ZRANGE 命令。

  • 如果按相反顺序排列:ZREVRANGE 命令。

②数据更新

有两种方法可以更新索引数据。一种是通过修改产品数据立即发起更新操作,另一种是通过定时脚本进行批量更新。

这里值得注意的是,关于更新索引内容,如果强行删除了key,那么就重置key。

由于这两个操作在 Redis 中不是原子执行的,因此它们之间可能存在间隙。我们建议您仅从集合中删除无效项目并添加新项目。

③性能优化

Redis是内存级别的操作,所以单次查询会非常快。但是,如果我们在实现中执行多个 Redis 操作,则多个 Redis 连接时间可能是不必要的时间要求。

使用MULTI命令启动一个事务,将多个Redis操作放入一个事务中,最后通过EXEC进行原子执行。

注:这里所谓的事务只是用于在一个连接内执行多个操作。如果执行过程中检测到失败,则不会回滚。

总结

这只是一个关于如何使用Redis优化查询搜索的简单教程。与现有的开源搜索引擎相比,它更容易,学习成本也相应更低。

第二,他的一些想法与开源搜索引擎类似。如果加上词解析,就可以使用类似于全文检索的功能。

作者:jasonGeng88

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门