此次青训营的项目选择的是搜索引擎开发,因此在这对实现原理和涉及的数据结构和算法进行整理。
搜索引擎的整体系统架构大致可以分为搜集、索引、查询三步,流程图可以如下所示
以下将对每个阶段进行介绍
1.搜集
通过爬虫对网页进行爬取,可以通过一些比较有名的网页作为起始页,通过广度优先不断遍历子链接,加入到爬取队列不断爬取(之所以使用广度优先,是因为相比于深度优先,广度优先对于并行的支持性更好)。
网页判重|布隆过滤器
为了避免重复爬取,需要对url进行去重操作,为了尽可能减少内存的消耗,这里我们介绍布隆过滤器。
网页存储
一般把网页内容存储在一个文件中,文件中应包含对应的映射便于查找
预处理
在爬取一个网页存储之前我们需要考虑其内容的预处理,因为得到的是html代码,需要把代码中的起始标签及其中的内容全部去掉,获得纯内容。
2. 分词与倒排索引
分词主要就是将整段的纯文字转为一个个的词语作为关键词,在不同模式下汉字可能会有多种分词结果,中文分词可以使用Jieba分词库。之后就可以获得每个分词与网页的对应关系例如
不同的网页内容可能有同样的分词,所以把具有相同分词的网页归在一起
通过一个词,获取存在该词的网页,也就是倒排索引。
在倒排索引的排序中,对于一大组网页,我们可以使用PageRank算法对其排序,其核心原理就是被其他网页引用越多的网页越重。以网页之间的超链接个数和质量作为主要因素粗略地分析网页重要性。具体细节原理可以自行搜索。
除了PageRank,我们还需要了解一个算法IF-IDF,对于分词结果,必定包含“的”、“地”、“得”这类没什么意义或者不太重要的词,这是我们就需要算法去对词进行排名,只记录重要的关键词在索引中。
该算法通过计算词频和逆文档频率,如下所示。
(IDF中加1是为了防止分母为0,即词语没出现过)
TF-IDF与一个词在文档中出现的次数成正比,与在整个语言中出现的次数成反比(可以排除的、地、得这些常见词)。但是这种计算可能无法体现词在上下文的重要性,如果要体现词的上下结构,可能需要word2vec算法来支持。
3. 查询
得到网页id后,便可以去提取出网页的链接和内容,按权重从小到大排列
在搜索框输入搜索词时会存在搜索提示,该功能主要和Trie字典树有关,通过维护一个词库,由搜索次数大于某个阈值地字符串组成,将该词库构建成Trie树,当用户输入字母时,就可以根据这个前缀去树中查找并显示。
同时我们可以使用Trie树去寻找热门搜索字符串。总所周知,Trie树会在节点设计标志表示是否构成一个单词,可以通过把这个标志改成以节点为终止字符地搜索字符串个数。最后维护一个有10个节点地小顶堆。