几个搜索相关的pdf(lucene, 分词等)

写文档时, 偶然发现很久以前的东西,给大家分享一下. 现在lucene已经过了这个版本, 已经有OpenBitSet这种好东西了.~

 

1. lucene2.3.2的变更

2. 疱丁解牛分词器分析

3. 几种分词器精度和速度的比较

 

<!----><!----> <!---->

Lucene2.3.2的变更

Author: Jeremy Chow([email protected])

Last Modified: Aug 1st, 2008

一、运行时

<!---->1. <!---->IndexWriter最大化地提高了现有的索引速度。第一,IndexWriter现在由内存的使用情况来决定刷新索引至磁盘,而不是之前用IndexWriter.setMaxBufferedDocs规定缓存的Docuement数量来决定刷新行为。第二,ConcurrentMergeScheduler使用后方(backgroud)线程(调用IndexWriter.setMergeScheduler (new SerialMergeScheduler())保持向下兼容) 来进行合并操作,由此得到的好处是合并行为不会阻塞IndexWriter.addDocument操作。第三,现在对segment的合并操作是依据每个segment大小,而不再是依据它们所包含Document的数量。

<!---->2. <!---->SortField.AUTO对long型起作用。在之前的lucene版本中,为排序自动检测Field类型时,数字首先被解释成int,如果解释失败,则认为是float。现在则先检测是否int,然后是否long,最后是float。

二、API 的变更

<!---->1. <!---->新加了IndexWriter.setRAMBufferSizeMB(...),IndexWriter当缓存的Documents容量大于指定内存大小时进行刷新。同时,Token也添加了新的API,使用户使用char[]结合偏移量与长度来表示token (避免为每个Token调用一次new String ())。

 

三、新特性

<!---->1. <!---->新加了IndexReader.reopen() 方法用来重新打开已经存在的IndexReader。

<!---->2. <!---->新加了IndexWriter.optimize(int maxNumSegments) 用来局部优化值小于maxNumSegments 的片段

<!---->3. <!---->新加了IndexWriter.optimize(int maxNumSegments) 局部优化索引

<!---->4. <!---->新加了IndexCommit.isOptimized()。

<!---->5. <!---->新加了TokenFilter.reset()。

四、优化

1. CachingTokenFilter 现在使用一个迭代器来访问缓存在LinkedList内的Tokens。显著地提升了性能,特别是在Tokens数目比较大的情况。

2. 从实质上优化了IndexWriter怎么使用RAM来缓存Documents,使索引速度加快到之前的2~8倍。现在使用了一个简单的共享散列表记录在内存中的Postings。一个Term对应一个posting。这个表直接写入到一个segment中。

3. 消除了偶尔会发生在复合文件(compound files)上的缓存到缓存拷贝(buffer to buffer copy)。

4. 去掉了Document中的同步机制,实际就是把存储Fields的Vector改成了ArrayList。

5. StandardTokenizer (StandardAnalyzer)使用JFlex代替JavaCC生成Tokenizer,使其速度是以前的6倍。

6. 使用bulk-coping技术拷贝原始字节,加速邻接的未删除文档的合并。

7.加速了 ISOLatin1AccentFilter

五、重新打开索引文件

IndexReader .reopen()

如果IndexReader实例调用此方法时,索引有变化,则生成一个新的IndexReader实例。

打开索引是非常昂贵的操作。此方法可以用来刷新已经存在的IndexReader,减少代价。此方法尝试只加载已经变化或新建立的片段(segement)。

如果索引自从打开后没有变化,则返回原来的IndexReader对象,否则会返回一个新的IndexReader对象。此时旧的IndexReader对象没有 关闭,只是不可用。

注意: 新打开的IndexReader对象可能会与旧的对象共享资源,据此,千万不要调用这些对象对索引的任何修改操作(例如:deleteDocument(int) , setNorm(int, String, byte) ),除非旧IndexReader对象已经关闭。否则,其行为将是不可确定的。

你可以通过比较返回的IndexReader与原来的IndexReader来判断其是否真的重新打开了:

  IndexReader reader = ... 

  ...

  IndexReader new = r.reopen();

  if (new != reader) {

   ...     // reader was reopened

   reader.close(); 

  }

  reader = new;

  ...

六、建立索引优化原理

以DocumentsWriter代替了之前的DocumentWriter。前者接受多个文档(Documents)的添加,并且直接把它们写入到一个单一的片段(segment)中。它比lucene2.2.0中用DocumentWriter为每个文档建立一个片段,然后将这些片段合并的方法更高效。

当加一篇文档时,它所存储的属性(Field)和词条向量(Term Vector)立即被写入到磁盘目录(假设不用RAM)。词频freq/prox 等词条信息(Posting),以词条为键值加入到Posting散列中。Posting散列表的每项维护着一个词频和prox组成的独立字节流。它包含多个文档的Posting数据。如果启用了向量,则为每个文档的每条词条都分配一个Posting向量(Posting Vector)。向量的每个元素记录词条的偏移量、位置等信息。

当Posting散列已满(假设使用RAM)或者加入到RAM的文档数目足够大(在此,我们用文档数目,而不是RAM使用量来刷新索引)时,我们会建立一个真实的片段,把它刷新到磁盘,然后重置Posting散列。

加入文档时,我们首先由属性(Field)名来组织文档所有的属性,并为每个属性记录其Posting散列。处理完每个属性后,我们刷新它的词条向量。当到整个片段的时候,我们首先通过名称将属性(fields)排序,然后依次排序每个属性的Postings。

线程:

多条线程可以同时调用addDocument方法。DocumentsWriter内部有一个getThreadState的同步调用,它为当前线程式分配一个ThreadState对象。无论何时,同一线程将会得到同一ThreadState。因此,如果各线程为各自不同的内容建立索引,则可以更有效地使用RAM。之后,processDocument会在那个ThreadState之上被调用,它不用作同步(很多消耗在这一步)。这是lucene2.3.0最重要的改进。 最后,同步调用finishDocument刷新变化至磁盘目录。

每个ThreadState实例都有属于其自身的Postng散列。当我们使用过多RAM时,会通过合并多个线程状态(ThreadSate)中相同词条的Posting表中的文档ID(docIDs),刷新所有线程的Posting散列至一个片段中。

当IndexWriter调用刷新操作(flush),且autoCommit=false时,会执行刷新。此时,我们强制所有线程空闲,且确定它们都空闲后才刷新。这意味着,你可以由一个给定的线程调用刷新操作。

七、建索引速度测试

CPU:           Intel Dual CPU 2.00GHz,

内存:          1G  DDR400

文本材料大小 :   43.9 MB

文件数目       19997

分析器             lucene 标准 StandardAnalyzer

 

Lucene 版本:               2.2.0

生成索引大小 :    16,901,638 字节

耗时:

158094 微秒

110437 微秒

106328 微秒

 

 

Lucene 版本:               2.3.2

生成索引大小 :      16,177,772 字节

默认 16M 缓存耗时 :

15407 微秒

15500 微秒

设置 64M 缓存耗时 :

13578 微秒

13984 微秒

13359 微秒

15500 微秒

可以看出 2.3 2.2 建索引的速度要快 5~10 倍。 (不过现在看来是因为StandardAnalyzer变快了. )

 

 

 

你可能感兴趣的:(Lucene,Gmail)