- 浏览: 412899 次
- 性别:
- 来自: 北京
最新评论
-
springdata_spring:
apache lucene开源框架demo使用实例教程源代码下 ...
有关Lucene的问题(6):Lucene的事务性 -
jaychang:
必须要感谢作者的分享,对理解Lucene的工作原理帮助很大
Lucene学习总结之一:全文检索的基本原理 -
yin_kaihua:
...
Lucene学习总结之三:Lucene的索引文件格式 (1) -
djh122:
...
Lucene 原理与代码分析完整版 -
wayne0830:
多谢楼主分享!
Lucene 原理与代码分析完整版
Zoie是linkedin公司基于Lucene实现的实时搜索引擎系统,按照其官方wiki的描述为: http://snaprojects.jira.com/wiki/display/ZOIE/Overview Zoie is a realtime indexing and search system, and as such needs to have relatively close coupling between the logically distinct Indexing and Searching subsystems: as soon as a document made available to be indexed, it must be immediately searchable. The ZoieSystem is the primary component of Zoie, that incorporates both Indexing (via implementing DataConsumer<V>) and Search (via implementingIndexReaderFactory<ZoieIndexReader<R extends IndexReader>>). Zoie是一个实时的搜索引擎系统,其需要逻辑上独立的索引和搜索子系统相对紧密的结合在一起,从而使得一篇文档一经索引,就能够立刻被搜索的到。 ZoieSystem是Zoie的重要组成部分,其一方面通过实现DataConsumer接口而完成了索引功能,一方面通过实现IndexReaderFactory<ZoieIndexReader<R extends IndexReader>>而完成了搜索功能,并将二者紧密的结合在一起。 下面就是ZoieSystem的总体架构图: 二、配置一个ZoieSystem ZoieSystem是可以使用spring进行配置的,一个典型的配置如下: <!--An instance of a DataProvider: FileDataProvider recurses through a given directory and provides the DataConsumer indexing requests built from the gathered files. In the example, this provider needs to be started manually, and it is done via jmx. 一个DataProvider的实例: FileDataProvider递归的访问一个指定的路径,将得到的文件构造成索引请求提供给DataConsumer。 在本例中,此生产者需要通过jmx进行手动启动。 --> <bean id="dataprovider" class="proj.zoie.impl.indexing.FileDataProvider"> <constructor-arg value="file:${source.directory}"/> <property name="dataConsumer" ref="indexingSystem" /> </bean> <!-- an instance of an IndexableInterpreter: FileIndexableInterpreter converts a text file into a lucene document, for example purposes only 一个IndexableInterpreter的实例: 在本例中,FileIndexableInterpreter将一个文本文件转换成为一个Lucene的Document对象。 从上面的介绍中我们知道,DataProvider作为一个生产者生产了DataEvent对象供消费者DataConsumer进行消费,然而由于Zoie最终是基于Lucene的,Lucene是不能够索引DataEvent对象的,这就需要有人负责将DataEvent转换成为Lucene的Document对象,根据应用的需要控制添加那些Field,添加什么样的Field等,此工作由翻译器Interpreter完成。 --> <bean id="fileInterpreter" class="proj.zoie.impl.indexing.FileIndexableInterpreter" /> <!-- A decorator for an IndexReader instance: The default decorator is just a pass through, the input IndexReader is returned. 一个IndexReader的装饰者: 默认的装饰者什么都不做,将原IndexReader返回。 注意这里使用的是一个重要的设计模式,装饰者模式。被包装的IndexReader是直接打开Lucene索引的IndexReader,IndexReaderFactory在得到这些IndexReader后,都会经过此类封装一下,再返回给用户。基本的Lucene的IndexReader打开,会加载和初始化一些基本的东西,然而有时候,用户需要在IndexReader打开的时候,同时加载一些自己的东西,此类给了用户这样一个机会,用户只要实现自己的装饰者就可以了。在和Zoie同一个项目Bobo(实现Facet搜索,使用过Solr的同学可能会比较熟悉)中,实现了BoboIndexReaderDecorator,其作用就是在IndexReader打开的时候,将Facet信息加载到内存中形成某种数据结构,从而在收集Facet的时候快速的使用。 --> <bean id="idxDecorator" class="proj.zoie.impl.indexing.DefaultIndexReaderDecorator" /> <!-- A zoie system declaration, passed as a DataConsumer to the DataProvider declared above 一个ZoieSystem的声明,在上面的DataProvider的声明中,其是作为一个DataConsumer传入的。 --> <bean id="indexingSystem" class="proj.zoie.impl.indexing.ZoieSystem" init-method="start" destroy-method="shutdown"> <!-- disk index directory 索引文件夹--> <constructor-arg index="0" value="file:${index.directory}"/> <!-- sets the interpreter 设置翻译器--> <constructor-arg index="1" ref="fileInterpreter" /> <!-- sets the decorator 设置装饰器--> <constructor-arg index="2"> <ref bean="idxDecorator"/> </constructor-arg> <!-- set the Analyzer, if null is passed, Lucene's StandardAnalyzer is used 设置分词器,如果为null,则使用默认的Lucene的StandardAnalyzer --> <constructor-arg index="3"> <null/> </constructor-arg> <!-- sets the Similarity, if null is passed, Lucene's DefaultSimilarity is used 设置相似性评分器,如果为null,则使用Lucene默认的DefaultSimilarity --> <constructor-arg index="4"> <null/> </constructor-arg> <!-- the following parameters indicate how often to triggered batched indexing, whichever the first of the following two event happens will triggered indexing 下面的两个参数表示触发批量索引的频率,任意一个满足条件则触发索引。 --> <!-- Batch size: how many items to put on the queue before indexing is triggered 批量大小:即队列中放入多少项方才触发索引 --> <constructor-arg index="5" value="1000" /> <!-- Batch delay, how long to wait before indxing is triggered 批量延时:即等待多长时间方才触发索引 --> <constructor-arg index="6" value="300000" /> <!-- flag turning on/off real time indexing 是否开启实时索引的标志位 --> <constructor-arg index="7" value="true" /> </bean> <!-- a search service 一个搜索服务 --> <bean id="mySearchService" class="com.mycompany.search.SearchService"> <!-- IndexReader factory that produces index readers to build Searchers from ZoieSystem作为IndexReaderFactory向搜索服务提供IndexReader列表,使其可以构造Searcher。 --> <constructor-arg ref="indexingSystem" /> </bean> 看完了ZoieSystem的配置以后,我们首先来看看ZoieSystem的构造函数是如何使用这些参数进行初始化的: (1) 其根据制定的索引文件夹${index.directory}生成一个DefaultDirectoryManager _dirMgr,用于管理索引文件夹及索引的版本号IndexSignature。 (2) 生成一个SearchIndexManager _searchIdxMgr,它是实现实时搜索的关键类,包含如下的成员变量: (3) 将参数赋值成员变量ZoieIndexableInterpreter _interpreter,Analyzer _analyzer,Similarity _similarity (4) 创建DiskLuceneIndexDataLoader _diskLoader对象,用于索引到硬盘索引 (5) 如果实时索引_realtimeIndexing设置为true,则创建RealtimeIndexDataLoader _rtdc,第四步中的_diskLoader作为其成员变量。将其设置为ZoieSystem的父类AsyncDataConsumer的成员变量setDataConsumer(_rtdc) (1) 当系统启动的时候,索引处在Sleeping状态,这时Mem结构中,只有索引A,索引B为null,索引A为_currentWritable,_currentReadOnly为null,_diskIndexReader为硬盘索引的IndexReader。由于内存中索引的IndexReader是每添加完文档后立刻更新的,而且速度很快,而硬盘上的索引一旦打开,在下次合并之前,一直使用,可以保证新添加的文档能够马上被搜索到。 (2) 当A中的文档数量达到一定的数量的时候,需要同硬盘上的索引进行合并,因此要进入Working状态。合并是一个相对比较长的过程,这时候会创建内存索引B,在合并过程中新添加的文档全部索引到B中。此时的Mem结构中,有内存索引A,内存索引B,索引A为currentReadOnly,索引B为currentWritable,diskIndexReader为硬盘索引的IndexReader。此时要获得ZoieSystem的IndexReader,则三个IndexReader全都返回,由于索引B的IndexReader是添加文档后立刻更新的,因而能够保证新添加的文档能够马上被搜索到,这个时候虽然索引A已经在同硬盘索引进行合并,然而由于硬盘索引的IndexReader还没有重新打开,因而索引A中的数据不会被重复搜到。 (3) 当索引A中的数据已经完全合并到硬盘上之后,则要重新打开硬盘索引的IndexReader,打开完毕后,创建一个新的Mem结构,原来的索引B作为索引A,为currentWritable,原来的索引A被抛弃,设为null,currentReadOnly也设为null,diskIndexReader为新打开的硬盘索引的IndexReader。然后通过无缝切换用新的Mem结构替代旧的Mem结构,然后索引进入Sleeping状态。 上面一节中,我们可以看到,对于新添加的文档的实时搜索问题相对简单,然而当遇到文档更新的时候,就相对复杂了。 如何实时的删除已经索引在硬盘上的文档是一个很大的问题,为此Zoie实现了ZoieSegmentReader: 有了ZoieSegmentReader,下面我们来看文档更新情况下的实时搜索机制。 (1) 最初系统启动的时候,是在Sleeping状态下的,这个时候,内存索引为空,硬盘索引上有文档A,B,C。 (2) 在Sleeping状态下,更新文档B,则新的文档B进入内存索引,而硬盘索引中B被标记删除。 (3) 当内存中索引足够大的时候,索引会进入Working状态,进入合并过程。合并过程会首先将硬盘索引中被标记删除的文档先真实的删除,然后再将内存索引向硬盘索引进行合并。此时如果有新的更新进入,比如更新文档A,则将在另外一个内存索引和硬盘索引中都标记删除,然后将新文档添加到内存索引中。 (4) 当合并完毕后,硬盘索引会标记删除原来在内存索引中标记删除的文档,被合并的索引以及其标记删除的文档全部丢弃,索引进入Working状态。 (1) Zoie的索引过程由DataProvider中调用ZoieSystem的consume函数开始,其实是调用AsyncDataConsumer的consume(Collection<DataEvent<V>> data)函数,其仅仅将DataEvent放在LinkedList<DataEvent<V>> _batch中。 (2) AsyncDataConsumer有一个背后的线程ConsumerThread _consumerThread,其会调用_consumer.consume(currentBatch),由ZoieSystem的构造函数中第(5)步我们知道,此处的_consumer为RealtimeIndexDataLoader _rtdc。 (3) RealtimeIndexDataLoader.consume函数分一下几个步骤: (4) RAMLuceneIndexDataLoader的consume函数会调用LuceneIndexDataLoader的consume函数,其包含以下步骤: RealtimeIndexDataLoader的父类是BatchedIndexDataLoader,其有一个背后的线程LoaderThread,其会调用processBatch函数。 RealtimeIndexDataLoader的processBatch函数过程如下: (1) 当内存索引中的文档数量超过配置的batch size或者时间超过设置的_delay的时候,就进行内存索引到硬盘索引的合并。 (2) 设置索引的状态从Sleeping到Working,_idxMgr.setDiskIndexerStatus(SearchIndexManager.Status.Working) (3) 得到需要合并的内存索引readOnlyMemIndex = _idxMgr.getCurrentReadOnlyMemoryIndex() (4) 将内存索引合并到硬盘索引:_luceneDataLoader.loadFromIndex(readOnlyMemIndex),DiskLuceneIndexDataLoader的loadFromIndex函数做以下事情 (5) 设置索引的状态从Working到Sleeping,_idxMgr.setDiskIndexerStatus(Status.Sleep) 在使用Zoie进行搜索的时候,要调用ZoieSystem的getIndexReaders()函数,其调用了_searchIdxMgr.getIndexReaders()。 SearchIndexManager的getIndexReaders函数,分别得到RAMSearchIndex<R> memIndexA的IndexReader,RAMSearchIndex<R> memIndexB的IndexReader,以及硬盘索引的IndexReader。在Sleeping状态下得到两个IndexReader,在Working状态下得到三个IndexReader。一、总体架构
三、Zoie实现实时搜索的原理
3.1、利用两个内存索引一个硬盘索引实现实时搜索的原理
3.2、有关文档的更新问题
四、Zoie的索引过程
4.1、将文档添加到内存索引
4.2、将内存索引合并到硬盘索引
五、Zoie的搜索过程
评论
我在Zoie的官网上看到
Donated by LinkedIn.com on July 19, 2008, and has been deployed in a real-time large-scale consumer website: LinkedIn.com handling millions of searches as well as hundreds of thousands of updates daily.
我想这种数据量 应该是分布式搜索 博主知道Zoie分布式方面是如何做的么?
发表评论
-
Lucene应用开发揭秘
2011-09-25 22:13 5356Lucene应用开发揭秘 ... -
Lucene应用开发揭秘上线了
2011-09-09 23:54 114Lucene应用开发揭秘 华章培训网地址:http:/ ... -
Lucene 原理与代码分析完整版
2010-06-13 01:30 34962Lucene 原理与代码分析系列文章已经基本告一段落, ... -
Lucene学习总结之十:Lucene的分词器Analyzer
2010-06-06 22:13 71461、抽象类Analyzer 其主要包含两个接口,用于生 ... -
Lucene学习总结之九:Lucene的查询对象
2010-05-19 02:39 2801Lucene学习总结之九:Lucene的查询对象(1) ... -
Lucene学习总结之九:Lucene的查询对象(3)
2010-05-19 02:37 29666、FilteredQuery FilteredQu ... -
Lucene学习总结之九:Lucene的查询对象(2)
2010-05-19 02:36 26055、SpanQuery 所谓SpanQ ... -
Lucene学习总结之九:Lucene的查询对象(1)
2010-05-19 02:34 6328Lucene除了支持查询语法以外,还可以自己构造查询对象 ... -
Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser
2010-05-08 13:41 2390Lucene学习总结之八:Lucene的查询语法,Java ... -
Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser(2)
2010-05-08 00:25 5543三、解析QueryParser.jj 3.1、声明Qu ... -
Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser(1)
2010-05-08 00:20 8384一、Lucene的查询语法 Lucene所支持的查询语 ... -
Lucene学习总结之七:Lucene搜索过程解析
2010-04-05 14:52 2954本系列文章将详细描述几乎最新版本的Lucene的基本原理 ... -
Lucene学习总结之七:Lucene搜索过程解析
2010-04-04 22:54 2644本系列文章将详细描述几乎最新版本的Lucene的基本原理 ... -
Lucene学习总结之七:Lucene搜索过程解析(8)
2010-04-04 22:43 76582.4、搜索查询对象 2.4.4、收集文档结果集 ... -
Lucene学习总结之七:Lucene搜索过程解析(7)
2010-04-04 22:39 43622.4、搜索查询对象 2.4.3.2、并集Di ... -
Lucene学习总结之七:Lucene搜索过程解析(6)
2010-04-04 22:20 36192.4、搜索查询对象 2.4.3、进行倒排表合并 在 ... -
Lucene学习总结之七:Lucene搜索过程解析(5)
2010-04-04 21:26 43292.4、搜索查询对象 2.4.2、创建Score ... -
Lucene学习总结之七:Lucene搜索过程解析(4)
2010-04-04 20:46 44502.4、搜索查询对象 2.4.1.2、创建Weight ... -
Lucene学习总结之七:Lucene搜索过程解析(3)
2010-04-04 20:19 43022.3、QueryParser解析查询语句生成查询对象 代码 ... -
Lucene学习总结之七:Lucene搜索过程解析(2)
2010-04-04 20:10 4865二、Lucene搜索详细过程 为了解析Lucene对索引文件 ...
相关推荐
Zoie是linkedin支持的开源实时搜索引擎项目。 http://code.google.com/p/zoie/ 相比普通搜索引擎,zoie有很多特性: 加入索引的文档必须能被立刻检索到。 索引过程不影响检索的性能。 文档的删除或者更新不能...
zoie, 实时搜索/索引系统 什么是 ZoieZoie是用Java编写的实时搜索/索引系统。维基维基在以下位置可用:http://linkedin.jira.com/wiki/display/ZOIE/Home问题问题在以下位置跟踪:http://link
作为LinkedIn公司产品与客户体验部门的副主管,尼沙尔负责梳理追溯到几十年前的工作记录,同时关注站内用户每分钟内形成的2,500种新关系。他需要审视美国的经济史(从1970到2000年,跳槽率增加了将近一倍,平均每...
CrossLinked是一种LinkedIn枚举工具,它使用搜索引擎抓取功能从目标组织收集有效的员工姓名。 此技术无需使用API密钥,凭据或什至直接访问站点即可提供准确的结果。 然后可以在命令行参数中应用格式,以将这些...
LinkedinSpider, Linkedin爬虫,根据公司名字抓取员工的linkedin信息
LinkedIn系统的架构设计和架构描述,详细分析了LinkedIn的大数据处理流程和模式。给大数据架构设计和开发工程师一个很好的参考。
Linkedin开发客户方法总结,值得多看看。
LinkedIn基于Kafka和ElasticSearch的实时日志分析系统
Linkedin接口 API 调用 实例 里面含有一个实例,非常具有参考价值。
Linkedin入门教程.pdf
linkedin 是国外的一个职业社交网站,在哪里可以查看注册用户的个人简历信息,但是如果想要实现开发任务,则需要模拟浏览器进行操作
十大领英开发客户方法,...5. 搜索框搜索People --- 如何突破三度人脉限制? 6. 利用Linkedin Companies 7. 利用Linkedin Groups 8. 利用 Linkedin Post 和 Article 9. 利用Google Search 10. 利用Linkedin SEO
linkedin api for php 有相关的文档 网址参考,不过普片上只要你流程没错,代码只要把key secret放进去 程序就哦了 就收个1积分吧 这不自己也没积分了
Linkedin社交媒体网站模板是一款企业风格的社交媒体工作招聘交流网站模板下载。提示:本模板调用到谷歌字体库,可能会出现页面打开比较缓慢。
Linkedin是一家商业客户导向的社交网络服务网站,成立于2002年12月并于2003年启动。2011年1月,LinkedIn有超过9000万的注册用户。到2012年1月,LinkedIn已经超过1.5亿的注册用户。 这是Linkedin分享的他们使用Play...
Linkedin Login - 在Android应用中实现LinkedIn社交登录的简单方法
来自 linkedin 的快速视图布局库.zip,layoutkit是ios、macos和tvos的快速视图布局库。
这个包允许在上获取有关个人或公司的数据。 安装 npm i linkedin-client 用法 您需要名为“ li_at ”的Linkedin cookie。 这样,请求将代表您发送。 您可以按照检索您的 Linkedin 会话 cookie。 const ...
资源来自pypi官网。 资源全名:linkedin_scraper-2.7.5.tar.gz
分布式OLAP引擎Pinot的聚合索引—LinkedIn