首先抱歉,这是个标题党。我们经常使用谷歌和百度搜索引擎来找到我们想要的内容。也许你已经思考过这个问题,他们如何快速找到你需要的信息?本文将向您介绍一个简单的搜索引擎的实现,“哦,不是搜索引擎,而是全文搜索!”
在这样的背景下,公司需要在网站中搜索文章信息的功能。首先想到的是利用数据库的全文搜索功能。但是查了资料发现感觉不太好,然后去查了第三方全文搜索软件或者库,也有很多比较成熟的,比如Lucene,Sphinx等等。我觉得如果能集成第三方的产品就好了,就看了一下,发现Java写的是什么,但是我是Java小白。估计环境够我折腾了,其他产品也看看,觉得挺麻烦的,就冒了一次险,决定自己实现一个。
问题解析与实现用过搜索引擎的人都知道,我们在搜索栏中输入需要查找的关键词,点击“搜索”就会得到一个结果页面,里面包含了我们需要查找的关键词。
第一个问题,如何从一篇文章搜索到你需要的关键字这个问题我觉得有一定基础的人都能体会到,很多人讨论如何达到更高的效率。在这里,我们将讨论一个简单易懂的算法(复杂的我们没有研究过)。例如,有这样一段话:
我爱你!
我们需要从中找到爱这个词。我们本来想写一个简单的搜索算法,但是时间有限,就算了。请下定决心(很多编程语言都支持字符串搜索)!显然,我们可以很容易地编写一个算法来找到这个单词。而且我们会发现,一篇小文章搜索关键词的速度是完全可以接受的。看来我们可以沾沾自喜了!
其实现在高兴还为时过早。我们的网站不能只有一篇文章。以后可能会有几千篇。应该如何应对?
第二个问题,使用上面的方法进行搜索,文章多了会遇到什么状况让我们做一个简单的假设来计算:
服务器包含1000篇文章,阅读一篇文章的时间假设为50毫秒,每篇文章搜索时间为0.1毫秒。
经过不精确的计算,读取文件总共需要50,000毫秒(50秒)。其实消耗的时间可能没有这么多。虽然操作系统和数据库会做一些优化,但是时间还是会很可观的。搜索文件内容大约需要100毫秒(0.1秒,实际需要根据文章大小来确定)。简单算了一下就会很明显,这个搜索的速度是完全不能接受的,其他的像谷歌和百度。
所以上面的方法根本行不通,我们需要一个新的方法。
倒排索引上场我们还是用例子来说明问题吧,假设有五个句子,分别如下:
我非常爱她。
她是个美女,我很喜欢。
我是一个开源爱好者。
何谓爱情?我不知道。
我不知道这是怎么回事
我们可以清楚地看到,这五个句子中都有“我”这个词,也就是说,如果我们在这五个句子中搜索“我”,就会得到五条记录。经过前面的分析,理论上我们搜索每一句都是可以的,但实际情况是当数据量很大的时候,完全不能接受。
我们可以发现,如果我们搜索“我”,那么我们会得到所有的ID列表[1,2,3,4,5]。这是什么意思?显然,这意味着我们可以使用“我”这个词作为索引,然后记录列表中引用这个词的每个句子的ID。利用这个规则,我们可以对“我”、“是”和“她”进行索引,可以得到如下结果:
I : [1,2,3,4,5]
是: [2,3,4,5]
她: [1,2]
我们可以很容易的根据单词得到相关的列表,而不是每次都去查,这样不是很快吗?这就是倒排索引!
另外一个问题,如何把文章的词进行分开相关的词和文章ID可以存储在倒排索引中进行快速检索,这是毫无疑问的,但是还有一个问题,我们如何把文章的内容按词或词分开(这个技术术语叫分词)。)?
先看一个简单的英语句子:
你好世界,你好搜索引擎!
我们可以很容易地对英语单词进行分类,因为英语单词之间有空格或标点符号,这对大多数人来说没有挑战性。
让我们来看另一个中文句子:
你好世界,你好搜索引擎。
作为人,我们很容易分辨出里面的单词,比如“你好”,但是我们怎么让计算机知道“你好”是一个单词呢?中文不像英文,可以用简单空的大小写和标点符号来切割。
我们来想象一下,如果我们告诉程序“你好”是一个单词,那么程序就能分辨出来。如何做到这一点?首先,我们要有一个字典,里面储存了中文所有的短语(其实不可能,这个问题后面会讨论);我们扫描文章的内容,并将当前的扫描结果与字典中的单词进行比较。如果匹配,说明扫描的单词是短语。
但是我们会遇到这样的问题,比如:
中华人民共和国
其中,“中国”、“人民”、“中华民国”可以单独使用,但按照人们的习惯,“中华人民共和国”是一个词。在这种情况下,我们可以利用最大匹配原则,即尽可能多的匹配单词,从而得到最大程度上符合我们使用习惯的单词。
我们可能会遇到更极端的问题,比如:
乒乓球拍卖结束了。
这句话有歧义,可以有多种解释,给分词带来很大困难。
另外,分词系统可以根据词频对短语进行细分,可以解决词典中没有收录的分词问题。
分词是一门高级学科。以上分词方法可以解决大部分问题,但不全面。有兴趣的可以自己找相关资料。
分词后,将分离出的单词和ID合并存储在倒排索引中,建立索引块。接下来,需要完成搜索功能。
搜索我们已经讲过搜索的原理,根据关键词,然后查倒排索引得到被引用的文章列表。很简单。这都是自然的。
但一般来说,搜索不会只搜索一个词,而可能是一个句子。我们如何搜索一个句子?以下步骤:
这样可以搜索出所有相关的文章,但是这样搜索出的文章列表是有缺陷的,因为我们不知道每篇文章的匹配程度。有些文章可能只匹配前面的一个关键词,而有些文章全部匹配关键词却在列表的最后,这显然不符合人们对搜索的要求。
提高搜索结果的准确度这里我们提供一个简单的解决方案:我们统计匹配的词,引用的次数越多,匹配度越高,我们能想到的就越准确。
此外,我们在构建索引时可以存储更复杂的信息:比如一篇文章由标题和正文组成,标题在索引中的权重为10,正文的权重为1,我们根据关键词所在的组件累加权重和引用次数。读完索引后,根据权重和引用次数重新排序,将权重高、引用多的放在结果列表前面,这样可以得到更好的结果。
总结本文只介绍了全文搜索的简单实现和原理,如果你想做一个专业的搜索引擎,这些知识是完全不够的。你需要了解爬虫,自然语言分析处理,海量数据存储等等。
希望这篇文章对你有用!