概念扫盲
页面最后修改于 05:37, 30 Dec 2011 修改人 鹰缘 | 历史版本
慎重说明:下面对概念的描述一定存在不正确、不规范的地方。如果和你之前其他地方看到的有出入,请忽略下面的描述或者对比下。基本上以通俗的描述给你一个印象。更准确的定义请参考相关学术论文。如果你看完了,我相信能帮助你初步的认识搜索的全貌。
1. 信息检索
就是我输入一个内容,你返回匹配这些“字符”的文档或者网页或者图片或者Id;也有,我输入一个内容,你返回的内容能回答我的提问,内容能帮助我解决问题;也有,我输入一个内容,你显示我的周边交通、餐饮、住房等信息,有图有字甚至音乐
2. 倒排索引
简单说就是key-value 索引。其中key 就是关键词, 也叫Token, 也叫tag,value呢,就是那些包含这个关键词的文档id集合。然后围绕key-value就引申出一序列的实现、优化。
3. 输入和分词
查询要输入内容吧,输入的内容千奇百怪,相同的输入串 “电脑”,是买电脑呢还是了解电脑基本原理呢?不得而知。我输入“餐饮和服装”,你说查 餐饮|服装, 还是 餐饮|和服|餐饮和服| 装呢?这就关系到了 分词、queryparse也有叫queryplan。深入优化queryparse的,基于统计的、基于规则的。我输入男女,你是说出来有男也可以,有 女也可以,男女都出来也可以,还是男女必须同时存在的文档才出来呢?这就是分词后的 AND 还是OR的问题。
4. 词典
几百万,甚至几个亿的记录,关键词数量(中文、英文、数字、混合)非常大,不可 能每次都是遍历去找token,然后找到这个token关联的value----doclist 也就postinglist吧。那token集合就需要重构并且压缩了。词典顺序就是一种,并且在词典顺序基础上再加跳跃索引(二级索引),同时执行前缀 或者其他压缩,这样词典就可以一次性导入内存。如果规模可控制,完全可以去词典,直接哈希了。kingso就是这么搞的。只是,这样就不支持模糊查询、区 间查询了。
5. postinglist |doclist|文件集合
从输入内容,匹配到词典中对应的token,由token关联的指针,找到对应 的postlinglist 文件集合。通常一个token关联几百万的docid,那么这么大的数据结构不可能整一个数组吧。同时,与这个token关联的文档id,与不一定是锦簇 的。可能docid是 0,1,2,10,34,65,1000000不等。
这就导致了所谓的索引压缩了,本质上就是整数压缩了。整数压缩基本就是分组执行 的。多个分组之上也会建索引,这样可以加速文档id的计算。因为分组后,除了第一个是明文,后面都是偏移值了。那么,究竟该选择什么样的压缩算法呢?测试 是王道。不过,需要明白,分组整数压缩算法的性能是与数据集相关的,不是A引擎用F算法,B引擎也用F算法就一定好,需要看数据分布情况。具体测试后才知 道。算法选择不是只看压缩、解压速度和压缩比例这个性能的。
5. AND OR
输入一个token,那就指一个doc list了,一个结果集了。通常是有多个token共同构成一次查询的。例如tokenA,tokenB,那就有了2个结果list。tokenA 和tokenB之间的逻辑要么是AND ,要么是OR。然后导致的结果就是tokenA---postinglistA AND|OR tokenB---postinglistB,问题转化为postingA 与postingB的求交、求并。本质就回到数据结构的数组求交、求并了。在具体应用中,如果一次请求的中间过程结果又很多OR操作,那性能会非常糟糕。 并且最好是小list OR到大list中,以缓解计算、存储压力。更高级的做法就是索引截断了。当AND 或者OR 到一定规模了,就不计算了,提前终止。坏处是牺牲一定的相关性。
6. 相关性计算和排序
所有进过输入、词典、postinglist、AND OR之后,就获得本次输入条件的对应文档集合。这只是一个docid结合。这些docid 通常是内部编号的。而且这些集合非常大,不可能全部输入到页面。不需选择几页最相关的内容返回给前端,这就是搜索中相关性问题了。保证TOPN 返回的内容最相关用户输入的字符串 或者 用户意图要的,那就完成了本次查询计算。相关性计算经典的有PageRank,简写PR,VSM向量空间模型,本质就是tf-itf;以及BM25等。
此时,带出了另外一个话题---域。postinglist只是id,而相关性是和“内容”相关的,那内容信息在哪里呢?一篇文档那么大,一次计算关联的计算范围如果是全文档,那计算非常耗时。此时就有另外一个概 念了 “域”field,可以理解为数据库中的字段。有了域的概念后,文档就划分了格子了。查询的token定位到某个格子中,相关性范围进一步缩小到域这个级 别运算了。进一步引申出,token的基本属性 token-field-docid,而文档淡化了,变成了一个逻辑概念。
这里面还有一个高级活儿,就是搜索结果混排。因为按照既定的相关性排序,也是可 能出现饥饿现象的。比如,展示的都是某一个类型、甚至某一个人或者某一商家的商品或者图片,那其他买家不就死翘翘了,明显资源或者流量不对等啊。很难实现 绝对的公平,但是是需要照顾的。谁的运气好,就是谁了。
7. 结果返回
相关性计算为每一个文档分配了分数,然后按照得分排个序。最高得分的将返回给前 端,同时将对应id的文档完整内容输出,个别信息还需要高亮。从docid 到doc完整的内容,就是数据存储了。象lucene 里面,支持直接将每个域的内容保存到索引,象kingso,已经将这块独立出来放到detail中。由docid 关联到另外一个存储,获取文档是推荐的。另外的存储可以是nosql存储,也可以是mysql等存储,也可以是文档并接,偏移索引的简单实现。
8. 数据源
从上面的流程下来,检索的宏观流程很清晰了。但是构建索引之前,需要数据源啊。 数据源简单可以分为:格式化数据、非格式化数据。然后可以退给引擎,也可以引擎去拉取数据。网页都是非格式化的,网页的获取第一步是爬虫抓取。抓取后提前 文本。而网页的dom千差万别,并且不规范,提取的准确性、性能是个问题。数据源的服务器性能同样影响数据获取速度,数据源数据的质量更是影响用户体验。 互联网层次的数据源处理非常复杂,垂直应用的数据源相对单一。只是业务场景多,文档的格式、内容不统一,需要每一个应用针对这个应用定制数据文档格式写入 引擎。kingso已经实现自解释数据结构,这样的话,完全可以屏蔽文档格式。一行文档一个doc,字段属性什么的都在这个字段里面。建索引的时候,自动 解析。
9. 全量、增量、实时
全量数据引申出了dump中心,增量引申出了实时。全量保证数据的一致性、索引 更紧凑、更优化,也面临大数据量全量耗时的问题。增量到实时,要求引擎提供实时写接口。也意味这只要业务方发出新数据,引擎就能实时了。是不是什么都实 时,就一定好呢。当然不是。看具体业务场景了。同时,实时的那些数据应该进索引也是需要考虑的,不是一有变动就的写引擎。另外,如果数据变更前后有时序关 系,应该确保上一次变更生效后,下一次变更才执行,避免发送和执行顺序不一致。这就是实时的 时序问题了。
10. 数据管道
有了上面的不同模块,有的可以融合一起,节省资源,便于排查错误。通常是分布式的,多个系统依赖、配合工作的。数据流动可以由模块间相互协议实现,也可以独立一个推送系统,这个可以理解为数据高速公路了。
11. 监控与流控
有了以上那么多的模块和工作,一个不错的引擎平台出现了。但是不可少监控和流控 了。监控可以及时发现系统问题,流控可以保证服务可用、资源共享等高级需求。小应用做好监控比流控更紧迫。监控主要分为基本监控和业务监控。基本监控就是 disk、io、cpu、load等参数,而业务监控就看具体应用了,通常有超时监控、请求量监控、结点服务状态监控等。
12. 持续优化
搜索是动态的过程,用一位前辈的话说就是,用的越多就越好。排序算法需要持续改进、响应时间需要持续关注、反作弊更是不容忽视。特别是垂直搜索中按照某个别条件的排序,尤其要注意单一条件的作弊。另外,引擎安全也是需要关注的!
13. 运维
搜索引擎的运维,不是简单的服务重启过程。运维的过程就是测试的过程、分析的过程,这个系统是索引、查询共同完成的。看索引或者看查询一个面,可能发现不了一些问题。所以,引擎运维绝对是专业的运维人士。