前言
客观来说,一个标准的全网搜索引擎很复杂,要处理的数据量亿级、百亿甚至更高,当然这些数据需要足够的硬件支持,个人只需要懂得技术流程逻辑,并实现较大数据(千万及以上)的搜索即可。
首先介绍一下搜索引擎基本的组成部分:
爬虫
网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,它们被广泛用于互联网搜索引擎或其他类似网站,可以自动采集所有其能够访问到的页面内容,以获取或更新这些网站的内容和检索方式。从功能上来讲,爬虫一般分为数据采集,处理,储存三个部分。
爬虫策略
一般来讲,爬虫需要制定一个合适的策略,因为互联网的内容过于庞大。一般分为深度优先原则和广度优先原则。深度优先就是先爬取一个网站的首页,再继续爬取首页内的内页,以此类推.....再继续爬取第二个网站。这样的方式对网站的性能有很高的要求,若爬取的频率过高,对一般普通网站而言,会产生很大压力,甚至使得网站无法正常运行。广度优先原则就是,先对一个网站集合进行统一的首页爬取,再对产生的内链进行二次统一爬取,以此类推...这样的好处就是可以分散流量压力,对网站比较友好。
在大量网页爬取的过程中,如果使用多线程。效率会很低,所以要尽可能使用多线程爬取,因为爬取数据过程中,网络的时间开销是最大的。
robots.txt
在现在的网站根目录里面,已经约定俗成有一个robots.txt,里面有网站管理员根据自己需要写入的网络爬虫的爬取规则,即哪些页面可以爬,哪些页面不允许爬。
网页类型
网页分为静态网页和动态网页,静态网页的数据一次性随页面加载完成,抓取起来比较容易,但动态数据是网页加载完成后,通过js再一次请求服务器获取到数据,展示在页面上的。普通的抓取请求无法获取到这些动态数据,所以对于这些动态数据,需要另外的抓取插件。
数据去重
当网页爬取到一定数量后,网页数量快速增长,必然会产生很多重复链接和内容。此时必须要考虑去重问题。对于搜索引擎的海量数据去重,一般而言会考虑事实去重,这样会大大减少重复内容的抓取,比统一抓取后统一去重适合得多。事实去重,需要构建一个链接库,用于每次链接判断,判断存在,则跳过,不存在则继续爬取。一次爬取任务结束后,再进行一次去重,接着入库。
内容相似度算法
1,余弦相似度
余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1,而其他任何角度的余弦值都不大于1;并且其最小值是-1。从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。两个向量有相同的指向时,余弦相似度的值为1;两个向量夹角为90°时,余弦相似度的值为0;两个向量指向完全相反的方向时,余弦相似度的值为-1。这结果是与向量的长度无关的,仅仅与向量的指向方向相关。
N维度向量 (A1,A2,A3,A4,A5...), (B1,B2,B3,B4,B5...)
2,simhash算法
步骤:分词、hash、加权、合并、降维
simhash可以计算文本间的相似度,我们可以通过simhash算法计算出文档的simhash值,通过比较各个文本的simhash值之间的汉明距离的大小来判断其相似度,海明距离越小,则相似度越大。一般大文本去重,大小<=3的即可判断为重复。
1.1、分词:
选择适合自己的分词库进行分词即可。
如“欢迎来到中国”->(分词后)“欢迎”、“来到”、“中国”
1.2、hash:
对每个词计算其hash值,hash值为二进制数01组成的n-bit签名。
设“欢迎“(100101)、“来到”(101011)、“中国”(101011)
1.3、加权:
对于给定的文本,权值即为分词后对应词出现的数量。给所有特征向量进行加权,即W = Hash * weight;这里我们假设三个词权值分别为4、5、9;
根据计算规则遇到1则hash值和权值正相乘,遇到0则hash值和权值负相乘
例如给“欢迎”的hash值“100101”加权得 到:W(欢迎) = 1001014 = 4 -4 -4 4 -4 4,给“来到”的hash值“101011”加权得到:W(来到)=1010115 = 5 -5 5 -5 5 5,剩下的按此规则计算
1.4、合并
将上述各个特征向量的加权结果累加,变成只有一个序列串。拿前两个特征向量举例,例如“欢迎”的“4 -4 -4 4 -4 4”和“来到”的“5 -5 5 -5 5 5”进行累加,得到“4+5 -4+-5 -4+5 4+-5 -4+5 4+5”,得到“9 -9 1 -1 1”。
1.5、降维
对于n-bit签名的累加结果,如果大于0则置1,否则置0,从而得到该语句的simhash值,最后我们便可以根据不同语句simhash的海明距离来判断它们的相似度。例如把上面计算出来的“9 -9 1 -1 1 9”降维(某位大于0记为1,小于0记为0),得到的01串为:“1 0 1 0 1 1”,从而形成它们的simhash签名。
海明距离:在信息编码中,两个合法代码对应位上编码不同的位数称为码距,又称海明距离。举例如下:10101和00110从第一位开始依次有第一位、第四、第五位不同,则海明距离为3。
3,其它方法:
*曼哈顿距离;
欧几里得距离;
杰卡德相似系数;
等...*
内容过滤处理
互联网内容有相当一部分是无用的,需要对抓取的内容进行去噪,例如网页里面的各种标签,违法内容,广告等等。处理完毕后,将结构化数据存储到数据库中。
中文分词
建立索引的前提是分词。对于英文来说,分词很容易,英文是由空格隔开的,但对于中文而言,没有分割符,这就需要专门的中文分词插件。
中文分词现阶段一般有:字典比对、HMM、crf、深度学习 等几种思想;
字典比对分词
一般有正向、逆向、双向 最大匹配法
全分词:
准备一个中文词典,里面包括大部分成词的词语、短句,对于搜索引擎而言,必须将一个句子里面所有可能的词语都提取出来,以提高召回率,比如:
句子 | 分词 |
---|---|
你今天真漂亮 | 你、今天、天真、漂亮 |
所以需要对句子进行遍历截取,将结果与中文词典进行比对,是一个词语则保存。
精确分词:
将一句话尽可能正确地分词,比如 我相信明天会更好 这句话,精确分词则会分为:
句子 | 分词 |
---|---|
我相信明天会更好 | 我、相信、明天、会、更好 |
现在互联网上有很多现成的各种语言(php、Java、Python等等)的分词插件,可以直接使用,若你对此有浓厚的兴趣,也可以自己摸索,重新开发一个属于你自己的分词插件。
HMM、crf、深度学习方式
这几种属于深度学习 模型类分词方式,有兴趣的朋友可以加深了解,深度学习是一个热门且宽广的领域。
HMM(隐马尔科夫模型),属于生成模型,生成概率有向图。是根据预先标注好的内容,训练生成模型,再根据模型进行分词,所以分词时,不依赖词库。但这时,训练语料的质量就尤为重要,其直接关系着分词效果。
crf(条件随机场),属于判别模型,生成概率无向图。但其计算的是整个标记序列的联合概率分布,所以训练代价比较大。用于命名实体识别,序列标准等任务。
其它字向量、词向量深度学习方法...
词库优化
分词的速度非常关键,其直接关系着索引与搜索的效率。对于依靠词典的方式而言,词库的维护就显得无比重要,词库的丰富度,直接关系着分词的准确度,也是一项大工程。
新词发现
对于我而言,目前维护词库的方式是:准备一个基础词库(可以从网上下载或从其他分词器里面提取),再利用我自写的新词发现程序(信息熵与内部凝聚度原理),每天爬取网页,生成优质候选新词,最后人工确认,再与基础词典合并...这样随着时间的发展,词典的丰富度会逐渐升高,分词的准确度会越来越好,分词的效果也不会与社会的语言发展脱节(随时爬取识别新词)。
词典结构
词典结构决定着每次分词时,是完全加载到内存,还是按需加载,(当然如果常驻内存,则不存在这个问题),结构不同,比对的效率也不同。
建立索引
倒排索引
索引,是为了加快信息查找过程,基于目标信息内容预先创建的一种储存结构。例如:一本书,没有目录,理论上也是可读的,只是当你合上当前在读的内容时,下次再翻开书本去查找,就比较耗费时间了。如果增加几页目录,我们可以快速地了解书本的大体内容分布以及每一个章节页面位置的分布情况,这样我们查询内容的效率自然就会提高。书的目录,就是书本内容一种简单索引。
倒排索引,是索引技术中的一种,它是基于信息主体的关键属性值进行构建的。
例如有两个文档:
id | 文档标题 | 分词 |
---|---|---|
1 | 搜索引擎爬虫爬取网站策略 | 搜索引擎、爬虫、爬取、网站、策略 |
2 | 搜索引擎爬虫的工作流程 | 搜索引擎、爬虫、的、工作、流程 |
(简单的)倒排索引结构为:
词 | 文档id |
---|---|
搜索引擎 | 1,2 |
爬虫 | 1,2 |
爬取 | 1 |
网站 | 1 |
策略 | 1 |
工作 | 2 |
的 | 2 |
流程 | 2 |
如果用户搜索“爬虫”,那么就可以直接返回包含“爬虫”的文档id集合 1,2
以上是最简单的倒排链表结构,复杂一些的在链表中可以携带一个词在文档中的频率、位置等更多其他信息。
索引存储
当数据非常庞大时,索引的存储结构将会非常关键,决定着搜索匹配的速度,在我自己的搜索尝试中,使用了bitmap存储,大大节约了存储空间。当然,前期bitmap并没有太多优势,但当数据量达到百万、千万时,优势就立刻显现出来了。
索引更新
索引的更新一般包括全量索引和增量索引。全量索引的含义为:每次将所有的内容全部更新一次索引,消耗的时间也比较长;增量索引为:每次将新增的内容更新索引,再将其和旧的索引合并,行程新的索引,增量索引的优点为消耗时间少。
搜索
随着搜索技术的逐渐走向成熟,搜索界面也有了一个比较固定的模式。除了基本的搜索,我们可能都会涉及到下面这些方面。
搜索自动补全
当用户在搜索框中输入查询过程中随时给予查询提示词。对于中文来说,当用户输入拼音的时候,也能提示。在搜索框输入的时候,需要实时反馈补全,所以对服务器和数据结构要求很高,延迟至少在0.2秒以内。
相关搜索提示词:当用户对当前的搜索结果不满意时,也许换一个搜索词,就能够得到更有用的信息。一般会根据用户当前搜索词给出多个相关的提示词。可以看成是协同过滤在搜索词上的一个具体应用。
搜索词预处理
有时候用户输入的搜索词或句子很完整,但有时候非常不完整甚至出现错误,这个时候旧需要纠错功能。同时还要分析用户的搜索意图,将未能表明的内容自动识别出来,这样能提供最优质的结果。此部分涉及到自然语言处理。
搜索排序(相当重要)
对于搜索引擎来说,最重要最关键的就属结果排序了,将最符合要求的内容放到最前面。对于排序的算法,需要各位摸索,一般而言,对一个文档进行多维度地打分,以及一个词对于一个文档的重要性进行打分,之后进行排序。当然这只是一个大概的逻辑,毕竟这属于一个搜索引擎公司的核心技术~
google的MapReduce在互联网上有很多详细的介绍,大家可以参考各类文献资料。
搜索高级功能
当然,有时候用户搜索会有一些特殊的需求,例如指定网站内容搜索、排除搜索,搜索特定时间的内容等等。
搜索结果缓存
一次搜索没有必要重复进行,可以将搜索结果利用各种缓存工具(redis,mg)等进行缓存,缓存的设计要避免出现缓存雪崩。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。