注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Lucene源代码分析[1]  

2009-07-02 16:12:23|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

首先讲一下Lucene的发音是Loo-seen,这是Lucene in Action中提到过的。另外强调的一点是我用的版本是1.9版,大家看到这里不要惊讶,我用这么早的版本,是为了能更好的了解Lucene的核心。如果有人看过最新的版本就应该了解,对于一个初学者,Lucene最高版本并不那么简单,它涉及了多线程,设计模式,对我反正是很挑战了。我先看老版本这也是受《LINUX内核完全注释》作者赵炯的启发,他分析的不是最新的Linux内核,而是1.11的版本。

我开始还是用调试的方式来解释,我想大家和我一样,如果看了半天analyzer也会有点不耐烦,我先写一个什么意义都没有例子(有那么一点意义的例子,网上很多)

package forfun;

 

import org.apache.lucene.analysis.SimpleAnalyzer;

import org.apache.lucene.index.IndexWriter;

 

public class Test

{

    public static void main( String[] args ) throws Exception

    {

       IndexWriter writer = new IndexWriter( "E:\\a\\", new

           SimpleAnalyzer(), true);

    }

}

    IndexWriter是最核心的一个类,一般的Blogger把其它所有的包都分析完了,就剩这最核心的一个包的时候,就分析不动了。

    我们先看一下它的参数,第一个就是索引存放的路径,第二个参数是一个Analyzer对象,它对输入数据进行过滤,分词等,第三个参数如果为true,那么它删除原目录内的所有内容重建索引,如果为false,就在已经存在的索引上追加新的内容。

    你可以先运行一下,就会发现指定的目录下有一个segments文件。

    调试的时候,暂时不去管SimpleAnalyzer类。

    我们看一下IndexWriter类的构造函数:

public IndexWriter(String path, Analyzer a, boolean create)

       throws IOException {

    this(FSDirectory.getDirectory(path, create), a, create, true);

}

    这里我们看到一个新的类FSDirectory:

public static FSDirectory getDirectory(String path, boolean create)

      throws IOException {

    return getDirectory(new File(path), create);

}

    再看getDirectory函数:

public static FSDirectory getDirectory(File file, boolean create)

       throws IOException {

    file = new File(file.getCanonicalPath());

    FSDirectory dir;

    synchronized (DIRECTORIES) {

       dir = (FSDirectory) DIRECTORIES.get(file);

       if (dir == null) {

           try {

              dir = (FSDirectory) IMPL.newInstance();

           } catch (Exception e) {

              throw new RuntimeException(

                     "cannot load FSDirectory class: " + e.toString());

           }

           dir.init(file, create);

           DIRECTORIES.put(file, dir);

       } else if (create) {

           dir.create();

       }

    }

    synchronized (dir) {

       dir.refCount++;

    }

    return dir;

}

    DIRECTORIES是一个Hashtable对象,DIRECTORIES注释上讲,目录的缓存,保证唯一的路径和Directory对应,所以在Directory上同步可以对读写进行同步访问。

(This cache of directories ensures that there is a unique Directory instance per path, so that synchronization on the Directory can be used to synchronize access between readers and writers.)

         也懒得解释了,就是创建一下目录,最后将refCount++

         我们回过头来看IndexWriter的构造函数:

private IndexWriter(Directory d, Analyzer a, final boolean create,

       boolean closeDir) throws IOException {

    this.closeDir = closeDir;

    directory = d;

    analyzer = a;

 

    Lock writeLock = directory.makeLock(IndexWriter.WRITE_LOCK_NAME);

    if (!writeLock.obtain(WRITE_LOCK_TIMEOUT)) // obtain write lock

       throw new IOException("Index locked for write: " + writeLock);

    this.writeLock = writeLock; // save it

 

    synchronized (directory) { // in- & inter-process sync

       new Lock.With(directory.makeLock(

IndexWriter.COMMIT_LOCK_NAME),

              COMMIT_LOCK_TIMEOUT) {

           public Object doBody() throws IOException {

              if (create)

                  segmentInfos.write(directory);

              else

                  segmentInfos.read(directory);

              return null;

           }

       }.run();

    }

}

         这里让我感兴趣的是doBody中的segmentInfos.writer,我们进入看一下这个函数:

public final void write(Directory directory) throws IOException {

    IndexOutput output = directory.createOutput("segments.new");

    try {

       output.writeInt(FORMAT); // write FORMAT

       output.writeLong(++version); // every write changes the index

       output.writeInt(counter); // write counter

       output.writeInt(size()); // write infos

       for (int i = 0; i < size(); i++) {

           SegmentInfo si = info(i);

           output.writeString(si.name);

           output.writeInt(si.docCount);

       }

    } finally {

       output.close();

    }

 

    // install new segment info

    directory.renameFile("segments.new", IndexFileNames.SEGMENTS);

}

         先看一下第一个函数,它建立了一个segments.new的文件,你如果在调试,就可以看到这个文件产生了,它返回一个IndexOutput对象,用它来写文件。我们就不去理睬这些有什么用了,第一个FORMAT-1,第二个version是用System.currentTimeMillis()产生的,目的是产生唯一的一个版本号。下面counter0SegmentInfos继承自Vector,下面的size()就是它有多少个元素,但是我们没有对任何文档建索引,所以它是空的。最后一句话是把segments.new文件名重命名为segment

         你可以用UltraEdit或是WinHex打开segments看一下里面的内容。我这里把它列出来:

FF FF FF FF 00 00 01 22 15 02 07 2A 00 00 00 00 00 00 00 00

writeInt是写入四个字节,writeLong是八个字节,现在可以看到所写入的四个内容分别是什么了。

 

  评论这张
 
阅读(1500)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017