王鹏云:大家下午好,感谢主办方把我安排在第一个演讲,有一个好处,听众还醒着。不过今天的演讲应该是很有吸引力,后面两位都会很精彩,应该大家不会这么轻易的睡着了。我们在交流的时候,刘主编在很早的时候给我们发了一个邮件说这次报名非常踊跃很快达到250了。跟大家开一个玩笑,我们下面开始我今天的主题演讲。
我讲的是实时搜索架构分析,今天大概内容主要是先简单了解一下实时搜索是什么东西,其实实时搜索和传统搜索技术体系基本是一样的,没有太大的变化,简单介绍一下搜索系统基础知识,再把它跟传统搜索区别关键点给大家介绍介绍.
其实实时搜索也不是什么新鲜的事物,很早以前就有了。原来新闻搜索,社区搜索,包括我做贴吧的时候,其实都需要用户发帖子内容可以很快的展现出来。这个东西不是什么新鲜事物,刚好赶上这个潮流,微博来了,把这个东西一推动,变成了一个热点,没有什么神秘的东西。我觉得实时搜索,一些商业价值到现在为止没有什么特别明显。大家目前还没有靠这个挣钱,但是我觉得它的商业价值体现在这些地方。他是一种新信息的聚合和放大。实时搜索在社交网络,是对信息传播方式很好的补充。你跟踪一个热点会看到你跟踪的人有了一些新的信息,你要获得这个全面信息你要进行搜索。能够通过搜索的情况,不管是结果还是搜索量,对当前一些热门和热点趋势进行一些分析。我觉得这以后很可能成为一种商业模式的一部分。所有搜索非常关键的一点就是能够直接表达用户的意图,通过这种意图投放广告是非常直接的方式。我觉得未来在搜索广告方面应该会有大的作为,这是我觉得实时搜索所具有商业价值的一些关键地方。
目前号称提供实时搜索搜索引擎的非常多,谷歌不用说了,还有Twitter,还有一些第三方的独立搜索引擎。我找了一下,结果发现太多,基本上各家都是大同小异。简单介绍一下搜索引擎基础知识,有几个大模块。不知道大家以前对搜索系统了解不了解,我就介绍快一些。首先要获得你要希望搜索的一些内容,就是通过抓取,超链分析,或者信息索引,就是要对你获得这些网页进行索引内容提取,对这些内容进行综合分析。然后是用户提交检索过程,对用户查询词进行分析,还有一些查询分析,做索引查询包括索引一些合并,一些过滤,一些全值计算。
传统搜索引擎和实时搜索区别主要在,第一个就是直观,就是一般我们实时搜索会做成一种比较酷的,信息会随着时间自动推移滚动的方式。这个不是一个很显著的区别,区别在于呈现方式。传统搜索会用静态的方式处理、显示这些内容,在搜索效果上传统引擎会更关注与搜索相关性,实时搜索更注重时效性,实时搜索有很强新闻媒体价值在里面,如果很旧信息做搜索没有什么太大的价值。传统搜索引擎对信息重要性排序一个关键因素就是PAGERANK,谷歌、百度都有这个指标。搜索PAGERANK值会变成一些数字化特征的东西,包括有多少人回复了,有多少人引用,有多少人推动其他方式来对你发布的这个信息进行一种放大。我们提供一个API让信息员直接推送信息,这里面有几个考虑我们后面会简单介绍一下。基本数据分布,在分布上对数据进行切分也会有一些区别,传统搜索我们是通过URL切分,我们数据在几十亿量级,一个索引库不可能把所有数据都处理下来,必须分布到很多物理机器上。这种切分我们更多会采用URL方式。在实时搜索更多我们通过时间这个纬度切分库,这个也是比较明显的区域。
对于信息提取有两种方式。一种我们通过PUSH方式提供信息。为什么喜欢PUSH的方式?其他方式会有很多麻烦,比如说我要搜索Twitter数据,这个抓取是通过超链分析的,这个是很困难的,通过抓取方式很难得到一个完整数据。另外通过抓取方式很难处理重复信息,一个信息会有多个URL反映,通过抓取方式你必须能够处理这些情况。还有另外很多原因。包括信息抽取,通常时候用抓取方式提取这个页面最关键的信息,这个通常比较准确,利用模板方式做,这样是比较准。通过一些启发式通用算法很难提取准确信息。通过模板做如果对方模板发生变化你所有这些模板必须跟着改,这是很大一个缺陷。我们更喜欢通过PUSH方式完成,为什么两者都要提供?因为不是所有人都会配合你做PUSH。对于你想搜索别人不配合你的时候,你只能用其他方式。在进入系统之前,我们会过滤一些垃圾信息,因为现在大家在新浪微博会看到很多信息是没有价值的,这些信息不过滤会导致搜索结果非常糟糕。这个在传统搜索引擎里面也有,整个搜索引擎核心是在索引这个部分。主体有两块,一个是放在内存里面,就是上面的蓝色的部分,然后下面是一个磁盘索引。内存索引里面我们有两个库,后面会讲到,这样做的意思是能够使它支持很多特性,包括整个索引过程中不会堵塞整个查询。怎么提高数据安全性?他们会通过定期的跟硬盘方式合并,硬盘索引会分成很多库,有一个查询器会对所有库进行数据查询,做出一个合并,提交给一些UI模块,生成最终页面,后面我对架构关键部分进行一些介绍。
这个架构设计要点我总结了一下,大概是信息获取这个层面。如果要使用抓取,一般会采用定向加制导式抓取,通常我们都知道哪些站点对我提供实时信息是有价值的,我们会选择一些站点、一些新闻、微博站点等等。我们已经知道每个连接的一些模式,我知道这个连接是一个索引页,是一个具体的内容页,我能够通过这些规则让我整个抓取过程变得非常快捷。在信息提取会用模板方式,模板是提取信息最准的。我也会加一些启发式的规则,是让你有一定的容错性,别人对模板进行修改你不用天天跟着改这些信息。有一个很重要的模块就是队列,我们通常会把这个队列设计成一个订阅式方式,不是有一个消费者取了以后就没有了。那种模式队列是有很多局限性的。我们采取TOPIC信息进入队列以后我可以订阅,以后可以由很多接受者获取这些信息,获取以后不会马上消亡,可以给后来比如说信息重放提供一个很好的支持。信息重放有一个很好的价值,后端模块可以对数据安全性提供一些非常大的帮助,主要是指数据不会丢失,坏了可以恢复。这个信息通常我们实现这个队列带一个队列数据加一个标的位的方式,这个队列普遍用在包括百度,还有139的系统,对于我们维护数据方面提供很大的帮助。
独立antispam这个模块有很多工作要做,基本上就是一个警察与小偷的游戏了,所以这个模块通常做成一个独立外挂,比较有利于性能的扩展。这是个CPU密集的模块,外挂可以进行快速演进,你必须很快否则搜索结果会变得非常糟糕。信息删除、修改,索引数据是连续的,中间是很难进行动态信息直接删除,通常我们做删除会采用标记方式进行,这种标记太多以后会给整个索引性能带来很大的影响,通常在合并或者索引重建会进行实际的删除。修改就是一个删除加添加的过程,动态实时搜索里面,信息的修改是什么类型,论坛里面修改删除很多,微博是没有修改,但是会有删除。我们有一个很重要的模块叫内存索引,传统搜索引擎没有必要存在,传统搜索引擎索引信息是相对比较静态化的,都放在硬盘上就可以了。但对于实时搜索引擎未来加快索引速度和索引被查询速度必须采取内存索引,必须支持边写边读。所以在构建索引数据结构时要仔细考虑,信息放在内存里面,我们必须有方式控制内存大小。通常就是在硬盘上写的过程我们称之为snapshot,通常我们会采用一个双索引结构,就是内存里面两块索引结构之间会互相切换,对其中某一个内存做的snapshot我会写到另外一个内存里面,相对竞争的内存我们必须安全写到硬盘上。这些数据是在内存里面,如果出现数据丢失会出现内存数据丢失,通常会采用两种办法,一种类似于数据库,把这些信息预先写到硬盘上,如果内存丢失我们可以通过它恢复。另外一种方式,我们如果在队列里做了好的机制就不用做这个,会在队列记录中记录你当前放在内存里面的位置,如果你崩溃了,就可以从以前的地方把这个数据拿回来。很多模块都会采取内存结构。
这里面有一个库合并的过程。目的是要减少库的数量。因为每一个索引库是一个独立可单独使用的索引,光检索也可以得到结果就是不全,整个查询过程中如果库特别多我们是需要并发的,把所有查询结果都出来再合并,如果你量特别大,这个就没有办法工作了。要通过库合并减少库的数量。一般做内存库的时候,很多时候我们会为了快捷而合并,如果合并内存要跟库合并,硬盘每次都要重写。当一个库大到一定程度,性能会直线下降,我们必须根据我们的不同业务了解这个库在什么情况之下是可控的范围内。库达到一定规模会进行一些库的拆分,拆分历史库,像RAMINDEXAB这个是准静态相对我们不会动它,有很大好处,我们做性能优化的时候会非常方便,一个库可以容纳非常大的数据量。
历史库之间还是基于减少库,也会进行一些合并。因为在实时搜索里面,搜索内容绝大部分来自于最近的数据,历史数据被访问的概率越来越低,所以我们会进行一些合并,会考虑一些频率的问题。老合并要进行数据库的重写,通过考虑一些综合因素决定是否要合并一些库。查询合并,刚才说到我们的查询必须发到两个内存数据库和所有的硬盘数据库,会有一些优化在里面,你可以先从内存数据库检索,如果得不到足够的数据再查一些老库这样可以减少有效库查询量。
实时搜索最大难点来自实时数据快以及数据动态。我相信大家有很多感受,因为这两个东西加起来会让你在各种架构里面设计算法、运维升级时带来非常复杂的东西。里面没有什么高深的东西,很多公司的产品其实是设计概念,没有什么特别复杂的地方,但是这些公司做数据开源不会告诉你运维细节,这些公司真正有价值的东西,是怎么做工程化的东西,我们这时候就不用这些产品,这些系统,因为我们不了解这个产品工程化的细节。一般实时搜索ranking算法跟传统不一样,有一个很大因素是时间因素,必须通过一种方式做衰减,老的信息让它的全值变得越来越低。最简单实时搜索就是时间排序,其实实时搜索也会按照相关性排序,这个时候需要进行一些处理。刚才说到社会化信息调权,这个信息是不是发自我的人,我的朋友,包括这个信息是不是被更多人分享过,这些是非常细节的问题,没有非常困难的东西,大家做搜索引擎不断调整参数、算法,最终获得一个比较满意的结果。
信息的anti—spam也会很复杂,让你信息很快检索出来,不能像搜索引擎,在一个离线数据进行一个很大的集群运算,包括可以算算这个网站有多少对外很差的链接,或者是在一个数据集群上的特定时候是很难做这些信息的,基本只能根据文本特点,一些敏感词通过社会化特点,必须结合这个也要理解一部分搜索站点上一些云信息,包括发这些信息的人是不是可信赖的。其实做一个独立的搜索引擎是很难的,还有一些其他的像动态行为,这个人在发得非常快,或者这样一些特点,一秒钟可以发很多,很明显这些特征不是一些正常数据,通过这些数据可以对anti—spam进行一些过滤。
下面是海量规模下的数据切分。实时搜索会有一个很明显的HOTSPAT的现象。大家搜索是当前热点,解决这个热点,设置会有一些小技巧。你在哪一个层级上做,可能在最终结果上做CACHE。所以通常我们CACHE分块做,做信息过滤之前做CACHE。各位做过微博系统应该很明确的,有很强的政治需求,你需要删除的信息必须马上让它消失。索引数据更新也是一些不太好处理的东西。很多情况之下我们要对索引数据进行更新,比如说我们词库有非常大的变化,老索引库会变得很低效,因为我们识别很多新词。原来是通过单个汉字进行倒排索引,现在我们识别出来很多新词,让我们索引库变得更小。一些信息删除修改如果非常多会在索引库造成非常多的逻辑。可能随着历史时间推移,有一些历史库访问量会越来越小,会进行一些库存的合并或者迁移的操作。通常我们把每个库变成一个独立单元,一个独立可检索单元我们可以很容易对每一库进行更新,不用同时进行更新,这样搜索引擎基本就不能用,我们进行错峰的更新,更新会导致你的索引结果出现一些变化,这个时候你的CACHE要重新清除。
大体架构就是这样的。任何一个搜索系统,把你最新的东西放内存里面,想办法让内存数据变大放大,硬盘上的数据不会丢失,做来做去就是这些东西。最后介绍几个,对搜索比较熟的人对这两个东西应该比较熟悉。一个就是ZOIE,现在开源了,官方说里面所有特性和代码都是他们自己做小白鼠,在他们产品线已经实验通过后才会发布到开源版本里面,是基于LUCENE的项目,也提供了一个SOLRPLUGIN,SOLR对这个进行非常好的封装。这个只是一个搜索库不是一个系统,SOLR是一个完整的系统,把这个工具集成到SOLR可以满足中小规模的搜索需求。其实对于大型垂直搜索,像百度、谷歌不适合,但你做一个垂直搜索是够的,另外就是sphinx在单机版会好一些,在1.10版本开始提供实时搜索,真的是一个非常时髦的概念。现在比较大的使用者像nntlog,比较大的站点已经部署千万级查询都不会有问题,我觉得再大也不会有问题,这个东西取决于你的扩展性。只要你加更多机器,做一些细节上的调整,执行一些更大量查询的时候不会出现什么问题,我今天的内容就是这些,谢谢各位。
提问:一开始看到最前面体系架构,如果有一个PUSHAPI,大致说明一下PUSH的比例。
王鹏云:这个不同形式是不一样的,比如说你是做Twitter搜索所有都是PUSH。
提问:现在PUSH比例还是比较小的。
王鹏云:因为PUSH必须合作。
提问:我们这里面的启发式模板是什么意思。
王鹏云:是信息提取技术,直接讲比如说你提取信息的时候,会有一些规则,这个东西更像一个真的信息,比如说我要提取一个内容,希望是一个地址,可能你启发式规则里面有一个什么街道或者这样的词,这个是地址可能性更大。但是称它为启发式,不一定是地址,这个要在不断实践总结中得出来了,其实就是一个比较模糊的匹配。
提问:刚才讲,目前我看到Twitter的数据,让他信息下降了十倍,但是具体怎么做没有透露任何细节。现在这个问题很严重,我们在实际工作中也有明显的需求,如果自己想建一个系统你有什么建议。
王鹏云:我之前看关于Twitter处理的一些信息,目前采取策略差不多就是这几个。里面有一些细的处理,也是包括会对一些发布者当时的情况,一些行为,会看这个人的一些历史,比如说你是良民还是什么,或者是来搞破坏,天天发垃圾信息,这样很自然对你这个信息进行一些降权,对短文本识别出来没有意义的词,字母包括一些反复拿一个词汇堆叠之类的,其实也是综合这些不断调整的过程。
提问:这块有没有一些开源的工具可以用?我调研好像邮件的东西特别多,像通用的一些实时性相关,邮件我了解过一些他们对实时性支持特别差,如果在一个实时性系统里面必须自己搭起一个系统来。
王鹏云:对,你说得没错,做得好的就是一些邮件系统。但是基本规则是可以直接借用过来的,其实也是发现很多模式,实现出来的。
提问:你能推荐一个吗?
王鹏云:名字不记得了,查一查反垃圾邮件的东西就可以查到那些东西。
提问:实时搜索跟谷歌、百度搜索有什么区别?
王鹏云:就是之前讲实时搜索和传统搜索主要的区别。
提问:内存数据库一般是怎么构架的?
王鹏云:一般硬盘索引就是一个倒排索引,有一个字典,每个字典进入一个信息,你在硬盘上出现索引,倒排索引是连续的,实际上通过链表的结果,比如说出现一个中国有相关信息会在这链表,你顺着读,你写到硬盘上能把这个链表变成一个连续的东西写在硬盘上。
提问:关于内存库两个问题,第一就是内存库本身有限制,具体是怎么实现的。如果实时搜索有限制,应该是会出现一个命中率的问题,是不是?你搜索的话,如果想在最短时间搜索出来结果,内存搜索区别用磁盘搜索的方式吗?不经过磁盘短时间直接从硬盘里面读出内容是有概率的问题吗?
王鹏云:你用CACHE一定会有命中率的问题。搜索有一个好处,可以防止局部性很好,大家近期搜索这个词会有长尾效应,头部100搜索就占了搜索量非常大的问题。热词通常可以做CACHE。内存库就是一个内存倒排索引。
提问:没有加其他的东西?
王鹏云:对。
提问:内存崩溃重建你们工作是选择日志恢复还是做队列重放?
王鹏云:我推荐队列重放。我这两种方式都做过。早期我们用日志方式,每个系统要自己带一个日志的功能,用重放就没有必要。
提问:第一种方式内存库日志是怎么存储?
王鹏云:磁盘上写一个连续追加的文件,一个信息先追加到一个文件列表,若内存崩溃,重起后文件顺着读一次。
提问:如果说做分布库比较多,有新的东西来,要记录,在每个数据库有一个标志修改了,是不是建库要建立这个标志是传送在哪台查询机上?还是要查询多台?如果数据量比较大,要标志已经修改过每个库中的文件,将来这个库传送到哪个机器里面?
王鹏云:我们只有删除。你是可以知道哪个库,那个信息是在哪一个库上,可以把删除信息只提交给那个库。实际上有一些细节,如果你本身没有删除信息这个概念,还是做不到,删除信息以后CACHE还有,删除信息会在很多地方存在,删除信息本身意义并不大。
提问:因为我做一个搜索更新,重新建一个库,每个文章有一个唯一的标志,就是说我取这个新的,把旧的屏蔽掉。
王鹏云:也是可以这样做,你CACHE出来东西,最终呈现之前必须要做过滤。
提问:建一个新库,优先级比较高,如果命中就不选旧库的结果。
王鹏云:看你对删除信息时效性要求。库5分钟重建一次,你删了5分钟不建,要求这样也可以这样做,一般删除时效性要求立马生效,不能靠你索引库重建实现删除,要有标记。
提问:我的问题是这样,搭建完实时搜索以后,这个系统最慢的速度是什么样的情况?
比如说我在内存两个里面没有找到数据在磁盘上,磁盘最大容量的一个情况。
王鹏云:只是说一个实例,当时做贴吧搜索一个索引库会放5千万左右的文档,看你这个文档长短,因为贴吧一个帖子肯定比微博长。
提问:我们做了这样一个系统,大概每天有40亿数据,有可能在内存或者是CACHE当中不能应用,这样的话系统非常慢有什么办法可以解决?
王鹏云:索引库是一个准静态,要做CACHE是很容易的。
提问:这样内存要求非常大,每天我有40亿数据。
王鹏云:很多是跟实际情况相关,比如说我不知道你是什么应用,你应用如果是一个查询,是分布非常广,没有很好局部性,你的命中率不是非常高,只能想办法从索引读取上面做一些改进,把硬盘提高速度,怎么样改进查询的时候索引合并这样一些性能。
提问:最后用的效果是这样,大概是二八原则,有80%比较快,但是有20%比较慢。
王鹏云:你要看慢是什么慢法。因为搜索引擎里面有一些投机取巧的办法。我查询的时候,头几页,查差不多给你这个数据,后面估算个数据告诉你就完了。否则你要得到一个查询总数,在缺少情况下会把所有数据查完,把第一页结果告诉你,你虽然只要第一页你查了所有的数据。我不知道里面有没有优化的可能,现在所有的大搜索引擎都不这么做,只查一部分数据就结束了。