Lucene入门之索引的建立和优化

来源:互联网 发布:js input disabled 编辑:程序博客网 时间:2024/06/03 10:02

索引的建立和优化

索引的建立

   对不同的文本使用不同的分析器

     普通情况下,建立索引器,并向索引器添加文档的语句如下:

     IndexWriter writer=new IndexWriter(indexPath,new StandardAnalyzer());

     Writer.addDocument(doc);

     这种情况下,所有的文档都会被同一种分析器所处理。我们要处理的文档中即包含中文,也包含法文,或者其他的语言的时候,如果只按一种分析器去处理,那么就会导致一种文档分析得好,另一种文档分析得差。

     为了解决这个问题,就可以使用下面的语句:

     Writer.addDocument(doc,分析器实例);

     通过这个方法,可以对不同的文本使用不同的分析器。

   Lucene内置的分析器

     Lucene使用JavaCC来生成分析器。

     Lucene内置了一些分析器。

分析器类型

分析器原理简述

WhitespaceAnalyzer

在空格处进行词语的切分

SimpleAnalyzer

在非字母字符处切分文本,并转化成小写形式

StopAnalyzer

在非字母字符处切分文本,然后小写化,再移除忽略词

StandardAnalyzer

基于某种语法规则将文本切分成词语快

     Lucene还内置了很多其他类型的分析器。还有很多有志之士贡献了自己开发的分析器。

   开发自己的分析器

     这里只说开发的具体思路,不谈分析器的具体思路,我也不太会。

1,  继承Analyzer,覆盖tokenStream的方法

package org.apache.lucene.analysis;

import java.io.Reader;

public class MyAnalyzer extends Analyzer

{

  public TokenStream tokenStream(String fieldName, Reader reader)

  {

      return new MyTokenizer(reader);

  }

}

 

2,  实现自己的Tokenizer

    

import org.apache.lucene.analysis.Token;

import org.apache.lucene.analysis.Tokenizer;

public class MyTokenizer extends Tokenizer

{

    public MyTokenizer(Reader reader)

    {

    }

    public Token next()

    {

    }

}

 

   根据不同的Field使用不同的分析器

      如果一篇中文的论文,里面有一段英文的摘要,我们要对摘要信息进行索引,应该怎么办呢?Lucene中的PerFieldAnalyzerWrapper可以解决这个问题。

      这个类继承自Analyzer,使用addAnalyzer(字段名称,分析器实例);

      例如:

PerFieldAnalyzerWrapper wr = new PerFieldAnalyzerWrapper(new StandardAnalyzer());

wr.addAnalyzer("title", new MMAnalyzer());

wr.addAnalyzer("author", new MMAnalyzer());

wr.addAnalyzer("abstract", new StandardAnalyzer());

wr.addAnalyzer("time", new StandardAnalyzer());

索引文件的生成

生成的过程

    IndexWriter调用DocumentWriter,DocumentWriter能获得Field的信息,建立倒排索引,与文件系统交互。

索引文件的格式

文件类型

存储含义

Segments

索引块

Fnm

Field的名称

Fdt

存储了所有设有Store.YESField的数据

Fdx

存储文档在fdt中的位置

Cfs

复合式索引格式的索引文件

索引的优化

优化的原则

1,  利用缓存,建设磁盘的读写频率。

2,  简述索引文件的大小和数量。

复合式索引格式

IndexWriter具有setUseCompoundFile方法,通过这个方法可以设置是否使用复合式索引。默认值是True

使用复合式索引可以减少索引文件的数量。

调整索引优化参数

第一个优化的参数mergeFactor

用来控制索引块的合并频率和大小,默认值是10。这个参数控制在内存中存储的Document对象的数量以及合并多个索引块的频率。在将它们作为单个块写入磁盘之前,Lucene在内存中默认存储10Document对象。当mergeFactor的值为10也意味着磁盘上的块数达到10的乘方的时候,Lucene会将这些块合并为一个段。

     也就是说,每当向索引增加10Document的时候,就会有一个索引块被建立起来。当磁盘上有10个索引块的时候,将被合并成一个大块。这个大块含有100Document.然后,继续积累,当到10个大块的时候,将被合并成一个更大的索引块。这个索引块中有1000个索引。

但是这个参数,受到maxMergeDocs的制约。由此导致每个索引块中含有的Document数量都不可以大于maxMergeDocs的值。

使用较大参数的mergeFactor会让Lucene使用更多的内存,同时使得磁盘写入数据的频率降低,因此加速了索引的过程。但是,大的mergeFactor意味着低频率的合并,回导致索引中的索引文件数增多。这样会降低搜索速度。

使用较小参数的mergeFactor会减少内存的消耗,并使索引更新的频率升高。这样做使得数据的实时性更强,但是也降低了索引过程的速度。

IndexWriter类的setMergeFactor(int mergeFactor)方法来设置mergeFactor的大小。

第二个优化的参数maxMergeDocs

用来限制每个索引块的文档数量,默认值是Integer.MAX_VALUE;

较大的maxMergeDocs可以加快索引的速度,但是更耗内存。

较大的maxMergeDocs参数适用于批量索引的情况,较小的maxMergeDocs参数适用于交互性较强的索引。

IndexWriter.setMaxMergeDocs(int maxMergeDocs)方法来设置maxMergeDocs的大小。

第三个优化的参数maxBufferDocs

这个参数用于控制内存中文档的数量。默认值是10.

这个值越大,在内存中存储文档就越多,越消耗内存,同时磁盘的I/O越少。

这些参数都是针对Lucene2.1而言的,好像Lucene2.4有了变化。

内存缓冲器与索引合并

   为了将索引放在内存中缓冲起来,我们需要内存缓冲器。

   Public IndexWriter(Directory d,Analyzer a,Boolean create) throws IOException

   Directory分为两种,一种是RAMDirectory或者FSDirectory得实例。

   使用RAMDirectoy,就是在内存中建立索引。这种索引建立的方式特别快,但是不能永久保存。

   使用FSDirectory,就是在磁盘中建立索引。建立起来的索引能永久保存,但是索引速度慢。

   如果把RAMDirectory作为缓冲器,先将索引文件缓存在缓冲器中,再把数据写入基于FSDirectory的索引中,从而达到改善性能的目的。

   RAMDirectory的使用方法

  

//创建缓冲器对象

RAMDirectory rd = new RAMDirectory();

//创建索引器

IndexWriter writer = new IndexWriter(rd,new StandardAnalyzer());

//创建搜索器

IndexSearcher searcher = new IndexSearcher(rd);

 

   FSDirectory的使用方法

  

FSDirectory fd = FSDirectory.getDirectory("index");

IndexWriter writer = new IndexWriter(fd,new StandardAnalyzer());

IndexSearcher searcher = new IndexSearcher(fd);

 

   RAMDirectoryFSDirectory相结合使用

 

//创建基于RAMDirectory的索引

RAMDirectory rd = new RAMDirectory();

IndexWriter iw = new IndexWriter(rd,new StandardAnalyzer());

….

//向基于RAMDirectory的索引中添加文档

iw.addDocument(doc);

iw.close();

//建立基于FSDirectory的索引

FSDirectory fd = FSDirectory.getDirectory("mix");

IndexWriter writer = new IndexWriter(fd,new StandardAnalyzer());

//把缓存在RAMDirectory中的所有数据写入FSDirectory

writer.addIndexes(new Directory[] {rd});

writer.close();

     同样可以反过来用,将文件系统中的索引读入内存中,就需要使用如下的方法:

     RAMDirectory rd=new RAMDirectory();

限制每个Field的词条数量

     对于Document德某个Field,我们可以限定它可被拆分的最大的词条数量。

     使用IndexWriter如下方法即可:

     Public void setMaxFieldLength(int maxFieldLength);

     如果某个Field别拆分了大量的词条,那么将消耗大量的内存。很容易导致内存溢出,这个问题在大文档的情况下尤其容易发生,所以要限定。

     通常,maxFieldLength不应超过10000

索引本身的优化

     IndexWriter

     Public void optimize() throws IOException

     这个方法可以提高索引搜索操作的速度,但是不会影响建立的速度。

查看索引的过程

     IndexWritersetInfoStream可以用来查看索引的过程。

     例如:

PrintStream ps = new PrintStream("log.txt");

writer.setInfoStream(ps);

 

原创粉丝点击