当前位置: 首页 > 科技观察

全文搜索功能的搜索之路是如何实现的

时间:2023-03-13 07:57:57 科技观察

介绍时间回到20年前。张胖子学校图书馆网站上线了。张胖子去浏览了一下,发现没有关键词搜索书籍的功能。我也有数据库相关的知识,说不定能实现这个功能呢!想到这里,张胖子赶紧搜索联系方式,抱着试一试的态度给图书馆管理员发了一封邮件,表达了实现这个搜索功能的信心和决心。没想到,他居然收到了回信。管理员王先生让他下午2点30分到图书馆三楼307室。星期四聊天。周四下午,张胖子洗完澡换好衣服后如约而至。一番寒暄和介绍后,王老师正式进入正题:你们打算如何实现这个全文搜索功能?张胖子说:“我可以用SQL的Like来实现。”王老师笑道:“数据量小的时候点赞还好,数据量大的时候效率就很低了。”张胖子有些不解:“那怎么办?怎么办?”王老师说:“你得用倒排索引。”张胖子知道什么是索引,倒排索引倒是没听说过。这到底是什么?王老爷子看他一脸懵逼,就知道这小子胆子虽大,但还是欠缺本事,鼓励道:“那你回去好好研究一下倒排索引,然后实现这个全文检索功能。”倒排索引张胖子心灰意冷的回到宿舍,赶紧拨通网络查看倒排索引。张胖子发现很多人把他翻译成倒排索引。虽然听起来有点奇怪,但实际上是一个非常简单的概念。比如有两个文档:文档1的内容:计算机是一种可以执行操作的设备文档2的内容:早期的计算机是大设备提取这两篇文章中的词,记录下这些词出现在哪篇文章中文档,这形成了一个简单粗暴的倒排索引。通过这个“倒排索引”,只要给出一个词,就可以快速定位到在哪个文档中。非常适合全文搜索。但是上面的倒排索引有点“粗”,还可以“细化”。1、对于a、is、to、that、can、the、are这些词搜索没有意义,用户几乎不使用它们来搜索,可以过滤掉。2、虽然用户在搜索时输入了计算机,但他也希望找到计算机,因此需要恢复复数词和过去时词。3、用户虽然输入了device,但是他还想搜索Device,所以需要把所有的大写字母都改成小写字母。这样转换后,文档1和文档2的关键字变成了这样:文档1:[computer][device][execute][operation]文档2:[early][computer][big][device]相应地,倒置index变成这样:当用户要搜索设备时,我们可以告诉它文档1和文档2都存在。为了更好地统计和突出搜索结果,您还可以记录关键词在文章中的数量和位置(例如:字数)。结构就明白什么是倒排索引了,张大发认为只要把那些书的书名、介绍、作者等信息抽出来,就可以构成倒排索引。不能做关键词搜索吗?但是转眼一想,这个需求应该是一个通用的需求,不仅仅是图书馆,还有很多互联网应用,比如网上商城。我可以设计一个类库给大家使用。张胖子赶紧画了一张结构图:你看,不管你是什么类型的文档,HTML、PDF、Word,甚至是数据库数据,只要你能从中提取文本,就可以作为我的数据源。文本经过分析后,可以存储在索引库中。用户可以发出各种查询,不仅可以是单个关键字,还可以是关键字的组合:keyword1ANDkeyword2等。在索引库中搜索后,将结果返回给用户。“中间虚线框出来的部分就是我要实现的类库!”张胖子对这个架构很满意。下一步的抽象就是考虑这个类库提供的API,很烦人。张胖子不禁想起好友比尔的殷切教导:“软件设计是一个不断抽象的过程。”关键是要抽象!但是这个系统似乎有点复杂。张大发绞尽脑汁两天了,一点头绪也没有。对于一个刚学web开发的同学来说,马上设计一个类库确实有点难度。没办法,张胖子只好打电话给比尔帮忙。Bill对张胖子的痛苦表示亲切的慰问,并对架构图表示适度的赞赏。他说:“既然有HTML、PDF、Word文档,自然可以做一个Document的抽象!”它可以映射到一个文档。当然,这种转换必须由程序员来完成。程序员决定什么是Document。”Bill说。“Document里有什么?例如,一个HTML文档可能有path、title、content等多个Field,其中path可以唯一标识该文档,而title和content需要分词形成倒排索引供用户查询搜索。”Bill回答道。(ADocumentcontainingmultipleFields)“用户创建Document和Field后,可以分析原始内容,分词,”张大胖开始明白,“这样,我可以定义一个Analyzer的抽象类,允许其他程序扩展它。”“是的,可以将分析结果添加到索引库中,而这个操作可以由一个单独的类来完成,比如IndexWriter类。”Bill说."但是IndexWriter怎么知道索引应该存在哪里呢?记忆?文件系统?“漂亮!”张胖子说。“好的设计通常更漂亮。”比尔想出了一个明智的报价。“对于用户搜索,肯定有一个叫做Query的东西,用来表达用户的搜索需求,当然这个Query也要允许扩展。”张大胖试着抽象。”但是这些类使用起来还是比较麻烦,最好是支持用户输入一个字符串来表达搜索意图:(电脑或者手机)和价格“Bill还是有经验的,”必须要有解析器来完成转换从字符串到Query的转换,然后我们让IndexSearcher接收Query,就可以实现搜索功能了。”张大发很激动,一个复杂的系统就这样解决了,虽然很多细节没有涉及到,但是大方向已经OK了,具体的细节会在具体的开发中处理。他摩拳擦掌,准备动手了一个大工程,实现了这个设计。但是Bill在网上搜了一会儿,泼了一盆冷水:“大胖子,好像有一个开源系统叫Lucene,和我们的设计很像,多了“强大的功能,要不你就用它来实现吧。”张胖子赶紧跑到电脑前看了看,果然,这个叫Lucene的家伙实现的很好,还有很多高级功能,比如“相似度”功能,需要深入研究搜索,遥不可及。他叹了口气说:“好吧,我去图书馆找王老师,就用这个Lucene吧!”熟练掌握。互联网应用增长,搜索成为普遍需求,他甚至提供Lucene咨询业余时间做服务,赚了很多外快。但是做多了,张胖子也觉得很烦。这个Lucene用起来太“低级”了,很多人向他抱怨:我只想搜索我的产品描述,现在还得懂什么是“Directory”、“Analyzer”、“Query”,实在是太复杂的!还有,我们的数据越来越多,索引占用的空间也越来越大。如何实现分布式存储?听到很多这样的抱怨,张大胖心想:是时候给Lucene做一层封装,提供一个简单的API了……后记:接下来可以说说ElasticSearch了。不知道你有没有兴趣。兴趣,而且这篇文章已经很长了,所以我就不写了。如果大家有兴趣,请留言告诉我,我会继续写下去。【本文为专栏作家“刘欣”原创稿件,转载请通过作者微信获取授权公众号coderising】点此查看该作者更多好文