搜索引擎优化知识完全手册(实现一个搜索接口,你会如何实现?(组图) )

优采云 发布时间: 2021-12-16 01:24

  搜索引擎优化知识完全手册(实现一个搜索接口,你会如何实现?(组图)

)

  如果是做后端开发,肯定已经实现了列表查询接口。当然,有些查询条件很简单,一条SQL就可以搞定。

  不过有些查询条件极其复杂,再加上数据库表中各种不合理的设计,使得查询界面特别难写,然后加班等事情就不用说了(不知道你有没有这种感觉~)。

  让我们从一个例子开始。这是某购物网站的搜索条件。如果您要实现这样的搜索界面,您将如何实现它?

  当然你说在搜索引擎的帮助下,比如Elasticsearch,是可以实现的。但是这里我想说的是,如果你想自己实现呢?

  

  从上图可以看出,搜索分为6个类别,每个类别又分为子类别。

  在中间,主要类别的条件是交叉点。每个子类都有单选、多选、自定义的情况,最终输出满足条件的结果集。

  好了,既然需求明确了,我们就开始实施它们。

  达到1

  最先上台的是小A同学,他是写SQL的“高手”。小A自信地说:“不就是一个查询接口吗?看条件,不过以我丰富的SQL经验,这对我来说还是不难的。”

  于是我写了如下一段代码(这里以MySQL为例):

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

  代码在测试环境中运行,结果似乎匹配,所以我准备预发布。有了这个预告,问题就开始暴露了。

  预发布是为了让在线环境尽可能的逼真,所以数据量自然要比测试大很多。那么对于如此复杂的SQL,其执行效率可想而知。考试的同学果断的把小A的密码打了回去。

  实现2

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

  同时将一个复杂的SQL拆分成多个SQL,计算结果在程序内存中进行计算。

  伪代码如下:

  $result_1 = query('select ... from table_1 where ...');<br >$result_2 = query('select ... from table_2 where ...');<br >$result_3 = query('select ... from table_3 where ...');<br >...<br ><br >$result = array_intersect($result_1, $result_2, $result_3, ...);<br >

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

  小B自己也知道,每次查询都会多次查询数据库,有一定的历史原因,有些条件不能单表查询,查询等待时间在所难免。

  达到3

  小C从上述方案中看到了优化的空间。他发现小B的思维没有问题。拆分复杂的条件,计算每个子维度的结果集,最后合并所有子结果集,得到最终想要的结果。

  于是他忽然想,能不能把每个子维度的结果集提前缓存起来,这样在查询的时候,可以直接取出想要的子集,而不用每次都去数据库计算。

  这里,小C使用Redis来存储缓存数据。使用它的主要原因是它提供了多种数据结构,并且很容易在Redis中进行集合交集操作。

  具体方案如图:

  

  这里,对于每个条件,计算出的结果集ID预先存储在对应的Key中,选择的数据结构为Set。

  查询操作包括:

  这其实就是所谓的反向索引。在这里您会发现缺少价格条件。从需求可以看出,价格条件是一个范围,而且是无限的。

  因此,上述条件穷举的Key-Value方法是无法实现的。这里我们使用Redis的另一种数据结构来实现,有序集(Sorted Set):

  

  将所有产品加入到以Key为价格的有序集合中,值为产品ID,每个值对应的score就是产品价格的值。

  这样,在Redis的有序集合中,就可以使用ZRANGEBYSCORE命令,根据score(价格)范围获取对应的结果集。

  至此,方案3的优化已经全部结束,数据查询和计算通过缓存的方式分离。

  在每次搜索中,您只需要搜索 Redis 几次即可获得结果。查询速度满足验收要求。

  扩张

  ①寻呼

  在这里你可能发现了一个严重的功能缺陷,列表查询怎么没有分页。是的,我们马上来看看Redis是如何实现分页的。

  分页主要涉及排序。为简单起见,以创建时间为例。如图所示:

  

  图中蓝色部分为以创建时间为分数的商品有序集合。蓝色下方的结果集是条件计算的结果。通过ZINTERSTORE命令,结果集的权重为0,商品时间结果为1。取交集得到的结果集被赋予一个新的有序的创建时间点集。

  新结果集的操作可以得到所有需要分页的数据:

  ②数据更新

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

  这里需要注意的是,关于索引内容的更新,如果Key被暴力删除,Key需要重新重置。

  因为Redis中的这两个操作不会以原子方式执行,所以中间可能会有空白。建议仅从集合中删除无效元素并添加新元素。

  ③性能优化

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

  通过使用 MULTI 命令,打开一个事务,将 Redis 的多个操作放在一个事务中,最后通过 EXEC 原子地执行。

  注意:这里所谓的事务只是在一个连接中执行多个操作。如果在执行过程中发生故障,则不会回滚。

  总结

  这里只是一个简单的使用Redis优化查询和搜索的demo。与现有的开源搜索引擎相比,重量更轻,学习成本相应更低。

  其次,它的一些想法类似于开源搜索引擎。如果添加词分析,也可以实现类似的全文搜索功能。

  BAT等大厂Java面试经验总结

想获取 Java大厂面试题学习资料扫下方二维码回复「BAT」就好了<br style="outline: 0px;" >
<p style="padding-right: 0em;padding-left: 0em;outline: 0px;white-space: normal;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 1px;line-height: 1.75em;" >回复 【加群】获取github掘金交流群

  回复 【电子书】获取2020电子书教程

  回复 【C】获取全套C语言学习知识手册

  回复 【Java】获取java相关的视频教程和资料

  回复 【爬虫】获取SpringCloud相关多的学习资料

  回复 【Python】即可获得Python基础到进阶的学习教程回复 【idea破解】即可获得intellij idea相关的破解教程关注我gitHub掘金,每天发掘一篇好项目,学习技术不迷路!<br style="outline: 0px;letter-spacing: 0.544px;" >

  

</p>

  

  回复【idea激活】获取idea的激活方法 回复【Java】获取java相关视频教程和资料 回复【SpringCloud】获取SpringCloud相关学习资料 回复【python】获取全套0基础Python知识手册 回复【2020】 】获取2020java相关面试题答案【加群】加入终端研发部相关技术交流群

  

<br style="outline: 0px;" >如果喜欢就给个“在看

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线