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

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Lucene源代码分析[4]  

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

  下载LOFTER 我的照片书  |

         写一个略有一点意义的例子,我们把”Hello World”加入索引:

package forfun;

 

import org.apache.lucene.analysis.SimpleAnalyzer;

import org.apache.lucene.document.Document;

import org.apache.lucene.document.Field;

import org.apache.lucene.index.IndexWriter;

 

public class FieldTest

{

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

    {

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

SimpleAnalyzer(), true);   

       writer.setUseCompoundFile( false );

 

       Document doc = new Document();

      

       Field name = new Field( "TheField", "hello world",

           Field.Store.YES, Field.Index.TOKENIZED );

      

       doc.add( name ); 

       writer.addDocument( doc );

       writer.close();

    }

}

    DocumentField不太想讲了,参数的含意也查的到,直接开始最重要的函数,IndexWriter中的addDocument函数:

public void addDocument(Document doc, Analyzer analyzer) throws

IOException {

    DocumentWriter dw = new DocumentWriter(ramDirectory, analyzer, this);

    dw.setInfoStream(infoStream);

    String segmentName = newSegmentName();

    dw.addDocument(segmentName, doc);

    synchronized (this) {

       segmentInfos.addElement(new SegmentInfo(segmentName, 1,

              ramDirectory));

       maybeMergeSegments();

    }

}

    我们看到它用DocumentWriter进行加入文档dw.addDocument,这里newSegment”_o”,我们看它的加入文档函数:

final void addDocument(String segment, Document doc) throws IOException {

    // write field names

    fieldInfos = new FieldInfos();

    fieldInfos.add(doc);

    fieldInfos.write(directory, segment + ".fnm");

 

    // write field values

    FieldsWriter fieldsWriter = new FieldsWriter(directory, segment,

           fieldInfos);

    try {

       fieldsWriter.addDocument(doc);

    } finally {

       fieldsWriter.close();

    }

 

    // invert doc into postingTable

    postingTable.clear(); // clear postingTable

    fieldLengths = new int[fieldInfos.size()]; // init fieldLengths

    fieldPositions = new int[fieldInfos.size()]; // init fieldPositions

    fieldOffsets = new int[fieldInfos.size()]; // init fieldOffsets

 

    fieldBoosts = new float[fieldInfos.size()]; // init fieldBoosts

    Arrays.fill(fieldBoosts, doc.getBoost());

 

    invertDocument(doc);

 

    // sort postingTable into an array

    Posting[] postings = sortPostingTable();

 

    // write postings

    writePostings(postings, segment);

 

    // write norms of indexed fields

    writeNorms(segment);

}

    有一个新的类,FieldInfos,看它的名字应该是保存Field信息的,看一下它的addDocument函数:

public void add(Document doc) {

    Enumeration fields = doc.fields();

    while (fields.hasMoreElements()) {

       Field field = (Field) fields.nextElement();

       add(field.name(), field.isIndexed(),

field.isTermVectorStored(),

              field.isStorePositionWithTermVector(),

field.isStoreOffsetWithTermVector(),

field.getOmitNorms());

    }

}

    果然是记录Field的信息的,dig deeper

public void add(String name, boolean isIndexed, boolean storeTermVector,

       boolean storePositionWithTermVector,

       boolean storeOffsetWithTermVector, boolean omitNorms) {

    FieldInfo fi = fieldInfo(name);

    if (fi == null) {

       addInternal(name, isIndexed, storeTermVector,

              storePositionWithTermVector, storeOffsetWithTermVector,

              omitNorms);

    } else {

       if (fi.isIndexed != isIndexed) {

           fi.isIndexed = true; // once indexed, always index

       }

       if (fi.storeTermVector != storeTermVector) {

           fi.storeTermVector = true; // once vector, always vector

       }

       if (fi.storePositionWithTermVector !=

           storePositionWithTermVector) {

           fi.storePositionWithTermVector = true;

       }

       if (fi.storeOffsetWithTermVector != storeOffsetWithTermVector) {

           fi.storeOffsetWithTermVector = true;

       }

       if (fi.omitNorms != omitNorms) {

           fi.omitNorms = false; // once norms are stored, always store

       }

    }

}

    再到addInternal中看一下:

private void addInternal(String name, boolean isIndexed,

       boolean storeTermVector, boolean storePositionWithTermVector,

       boolean storeOffsetWithTermVector, boolean omitNorms) {

    FieldInfo fi = new FieldInfo(name, isIndexed, byNumber.size(),

           storeTermVector, storePositionWithTermVector,

           storeOffsetWithTermVector, omitNorms);

    byNumber.add(fi);

    byName.put(name, fi);

}

    回到fieldInfos.add(doc)的下一句:

public void write(Directory d, String name) throws IOException {

    IndexOutput output = d.createOutput(name);

    try {

       write(output);

    } finally {

       output.close();

    }

}

    这个函数我们见过,但是因为DirectoryRAMDirectory,所以并没有以文件的形式产生。

public void write(IndexOutput output) throws IOException {

    output.writeVInt(size());

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

       FieldInfo fi = fieldInfo(i);

       byte bits = 0x0;

       if (fi.isIndexed)

           bits |= IS_INDEXED;

       if (fi.storeTermVector)

           bits |= STORE_TERMVECTOR;

       if (fi.storePositionWithTermVector)

           bits |= STORE_POSITIONS_WITH_TERMVECTOR;

       if (fi.storeOffsetWithTermVector)

           bits |= STORE_OFFSET_WITH_TERMVECTOR;

       if (fi.omitNorms)

           bits |= OMIT_NORMS;

       output.writeString(fi.name);

       output.writeByte(bits);

    }

}

    我们这里可以看到,”_0.fnm”中保存的是Field的名字以及设置。我们看一下,一共向_0.fnm中写入了多少内容,第一,写入了有多少个Field,第二,分别写入了Field的名字与设置。我把”_0.fnm”中的内容列出来看一下:

01 08 54 68 65 46 69 65 6C 64 01                                            

    可能会有点奇怪,写入的是size()是一个int,为什么就用了一个字节表示了呢?其实与我们上次看到的writeInt不同的是这里用的是writeVInt

public void writeInt(int i) throws IOException {

    writeByte((byte) (i >> 24));

    writeByte((byte) (i >> 16));

    writeByte((byte) (i >> 8));

    writeByte((byte) i);

}

 

/** Writes an int in a variable-length format.  Writes between one and

 * five bytes.  Smaller values take fewer bytes.  Negative numbers are not

 * supported.

*/

public void writeVInt(int i) throws IOException {

    while ((i & ~0x7F) != 0) {

       writeByte((byte) ((i & 0x7f) | 0x80));

       i >>>= 7;

    }

    writeByte((byte) i);

}

    可以看出writeInt很简单,分成4个字节写就可以了,而writeVInt看起来有点让人不解,大概讲一下,~0x7F是除低7位,其它位都为1(i & ~0x7F) != 0的意思就是高25位不为0(int是用32位表示,除去低7位就是25)。进到循环内i & 0x7f表示取低7位,(i & 0x7f) | 0x80表示取低7位,并将最高位置1,然后右移7位,写下7位。最后把余下的位写入。概括一点讲就是每次写七位,如果不是最后一个字节,那么最高位都有1这个标志位,如果是最后一个字节,最高位为0

    我们接下来看写入Field name的内容,开头是08我们可以猜出来,它应该是TheField(我们起的Field的名字)的长度,后面的8个字符应该就是”TheField”,我们还是看一下代码:

public void writeString(String s) throws IOException {

    int length = s.length();

    writeVInt(length);

    writeChars(s, 0, length);

}

 

/** Writes a sequence of UTF-8 encoded characters from a string.*/

public void writeChars(String s, int start, int length) throws IOException {

    final int end = start + length;

    for (int i = start; i < end; i++) {

       final int code = (int) s.charAt(i);

       if (code >= 0x01 && code <= 0x7F)

           writeByte((byte) code);

       else if (((code >= 0x80) && (code <= 0x7FF)) || code == 0) {

           writeByte((byte) (0xC0 | (code >> 6)));

           writeByte((byte) (0x80 | (code & 0x3F)));

       } else {

           writeByte((byte) (0xE0 | (code >>> 12)));

           writeByte((byte) (0x80 | ((code >> 6) & 0x3F)));

           writeByte((byte) (0x80 | (code & 0x3F)));

       }

    }

}

    可以看到,我们的估计没有错,的确是先写入它的长度,writeChars让人更加糊涂,不过看懂了也就没什么了。

    For循环中第一个if不讲了,1-111 1111之间的字符,else if是在100 0000111 1111 1111之间的字符,code >> 6右移6位,右移6位的原因是下面code & 0x3F是写低6位。0xC0 | (code >> 6)是在高3位加上110的标志,而(0x80 | code & 0x3F)是在高两位上加上01标志。最后else,右移12(你还是知道一共有16个字节的吧?)那么就4位剩下了,(0xE0 | (code >>> 12))加上1100标志位,下面两个不讲了,和上面的一样。

 

 

 

 

 

 

 

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

历史上的今天

评论

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

页脚

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