怎样实现一个搜索引擎

首先说声抱歉,这是个标题党。我们经常使用Google和百度搜索引擎去查找我们想要的内容,也许你想过这么一个问题,他们如何做到迅速的查找你所需的信息。本文将为你介绍一个简单的搜索引擎的实现,“哦,不是搜索引擎,是全文检索!”

背景

交代下背景,公司做一个网站需要搜索站内文章的信息的功能,首先想到的是就是使用数据库的全文检索功能,但是查查资料发现,感觉不好,然后又去查查第三方的全文检索的软件或者库,有很多成熟的,比如Lucene,Sphinx等。我就想如果能集成第三方的也不错,于是看下,结果发现是Java什么写的,无奈自己是Java小白,估计一下弄环境都够自己折腾的,其他的也看了下,感觉都挺麻烦,于是铤而走险,决定自己实现一个。

问题解析与实现

用过搜索引擎的人都知道,我们在搜索栏中输入我们需要的查找的关键字,点击“搜索”就会得到一个结果页面,这个结果页面的内容就包含了我们要查找的关键字。

第一个问题,如何从一篇文章搜索到你需要的关键字

这个问题我认为有一定基础的人都可以实现出来,也有很多人讨论怎么实现效率更高,在这里就讨论一个通俗易懂的算法(复杂的自己没有研究^_^),比如有一段文字如下:

I Love You!

我们需要从中找到Love这个词,本来想写一个简单查找算法的,时间有限就算了,请各位自己脑补(很多编程语言都支持字符串查找)!很显然我们轻易的就可以写出一个算法来查找这个词。而且我们会发现,这个搜索在一篇不是很大的文章里查找关键词的速度完全可以接受。我们似乎可以沾沾自喜了!

其实,高兴的太早了,我们的网站不可能只有一篇文章,在以后可能有成千上万篇文章,该怎么应付呢?

第二个问题,使用上面的方法进行搜索,文章多了会遇到什么状况

我们做个简单的假设来进行计算:

服务器包含1000篇文章,读取一篇文章所消耗的时间假定为50毫秒,每篇文章搜索消耗0.1毫秒

经过不严谨的推算读取文件时间总共要消耗50000毫秒(50秒,实际上消耗的时间可能没有这么多,虽然操作系统和数据库会做一些优化,但是时间仍然会很可观),搜索文件内容大概需要100毫秒(0.1秒,实际上需要根据文章的大小来确定),经过简单的推算会明显发现,这个搜索的速度是完全不可能接受的,人家Google,百度可都是几百毫秒取出上亿的列表。

所以,上述的方法完全行不通,我们需要新的方法。

倒排索引上场

我们仍然举例说明问题,假设有5句话,内容如下:

  1. 我很爱她

  2. 她是一位美丽的女子,我很喜欢

  3. 我是开源爱好者

  4. 爱是什么?我不知道

  5. 我不知道这是怎么回事

我们可以清楚的看到,这五句话中都有“我”字,也就是说,如果我们在这5句话搜索“我”,那么我们会得到5条记录。经过前面的分析,我们每句话都进行搜索一遍理论上是没有问题,但是实际情况是在数据量大的时候,完全不能接受。

我们可以发现,如果我们搜索“我”,那么我们会得到全部的ID列表[1, 2, 3, 4, 5],这意味着什么呢?很显然,这意味着我们可以使用“我”这个字来做索引,然后把所有引用这个字的每句话的ID都记录到列表中。利用这种规则我们对“我”,“是”和“她”建立索引,可以得到如下的结果:

:[1, 2, 3, 4, 5]

:[2, 3, 4, 5]

: [1, 2]

我们可以很轻易的根据字得到相关的列表,而不用每次都全部查找一遍,是不是很快呢?这就是倒排索引!

另外一个问题,如何把文章的词进行分开

把相关的词和文章ID存放到倒排索引里可以进行快速检索,这已经没有任何疑问了,不过另外一个问题来了,我们如何把文章的内容按照词或字的方式给分开呢(这个专业术语叫做分词。)?

先看一句简单的英文:

Hello world, Hello search engine!

我们可以轻易的划分出英文单词,因为英文单词之间是有空格或者标点符号的,这对于多数人来说没有挑战性。

我们再看一句中文:

你好世界,你好搜索引擎

作为人,我们可以很容易的区分里面的词语,比如“你好”,但是怎么让计算机知道“你好”是一个词呢?中文不像英文那样可以通过简单的空格和标点符号来切割。

我们来试想一下,如果我们告诉程序“你好”是一个单词,那么程序就能分辨出来了,这个怎么做到呢?首先我们要有一个字典,这个字典里面存储了汉语里面所有的词组(实际上不可能,这个问题后面讨论);我们对文章的内容进行扫描,并对当前扫描的结果与字典的词语进行对比,如果匹配上,就说明扫描出来的是一个词组。

但是我们会遇到这么一个问题,比如:

中华人民共和国

其中“中华”,“人民”和“共和国”都可以单独使用,但是从人们的习惯上来说“中华人民共和国”就是一个词,对于这样的情况我们可以使用最大匹配的原则,就是尽可能的匹配更多的词,这样就在很大程度上得到符合我们使用习惯的词语。

我们可能还会遇到更极端的问题,比如:

乒乓球拍卖完了

这句话歧义很大,可以做多种解释,这给分词带来很大的困难。

另外,分词系统可以根据词语出现的频率在划分词组,这样就可以解决词典中没有包含的词语分词问题。

分词是门高深的学问,上述的分词方法可以解决大部分的问题,但是还不全面,有兴趣的可以自己查找相关资料。

经过分词,并把分开的词语与ID结合存入到倒排索引,索引这块就建立完了,接下来需要完成查找的功能。

搜索

前面已经讲过搜索的原理,根据关键字,然后查找倒排索引得到引用的文章列表。很简单,一切顺理成章。

但是搜索一般来说不会只搜索一个单词,可能是搜索一句话。我们如何搜索一句话?如下步骤:

  1. 首先,我们需要把要搜索的话进行分词,得到相关的搜索词语(关键字)列表
  2. 使用词组查找所有相关的文章列表
  3. 因为可能几个词语(关键字)指向同一篇文章,所以需要对查出来的文章列表进行归并
  4. 返回归并后的文章列表

这样就可以把所有相关的文章都查找出来,但是这样搜索出来的文章列表是有缺陷的,因为我们不知道每个文章匹配的程度如何,有的文章可能只匹配到一个关键字排在了前面,而有的文章关键字全部匹配了却在列表的尾部,很显然这不符合人们对搜索的要求。

提高搜索结果的准确度

这里我们提供一个简单的解决方案:我们对匹配的词语进行统计,引用次数越多,那么匹配度越高,可以认为越准确。

另外我们可以在建立索引的时候存入更复杂的信息:比如一篇文章由标题和正文组成,标题在索引中所占的权重为10,正文权重为1,我们根据关键字所在的组成部分来累加权重和引用次数。在完成索引读取后再次根据权重和引用次数进行排序,将权重高的和引用次数多的放在结果列表前面,从而得到较为理想的结果。

总结

本文介绍的只是简单的全文搜索实现及原理,如果要做专业级的搜索引擎,这些知识是完全不够的。你需要知道爬虫,自然语言分析处理,海量数据的存储等等知识。

希望这篇文章对你有用!

欢迎拍砖,欢迎转载(请保留本人的信息)

转载于:https://my.oschina.net/felingdev/blog/393170

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值