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

anqiang专栏

不要问细节是怎么搞的,源码说明一切

 
 
 

日志

 
 

TermVecotrWriter源码解读  

2009-12-05 13:23:00|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

TermVectorWriter主要是打开tvx tvd tvf文件,这些文件中保存了每个文档document对象中每个field的信息,其中tvxtvd tvf的索引文件,tvdtvf的索引文件。Tvf中保存了每个包含stored term Vectorfield信息,它们按照文档来进行区分。

源码解析:

/**

   * 构造一个termVecotrswriter对象

   * 我们可以注意到很多读取index的构造函数都含有segment这个参数

   * 这表明当前这个读取index的类是相对于segment来说的

   * 同时经常会传入fieldInfos这个变量,这个是为了便于查找fieldNum方便

   * @param directory

   * @param segment

   * @param fieldInfos

   * @throws IOException

   */

  public TermVectorsWriter(Directory directory, String segment,

                           FieldInfos fieldInfos)

    throws IOException {

    // Open files for TermVector storage

    tvx = directory.createOutput(segment + "." + IndexFileNames.VECTORS_INDEX_EXTENSION);

    tvx.writeInt(TermVectorsReader.FORMAT_CURRENT);

    tvd = directory.createOutput(segment + "." + IndexFileNames.VECTORS_DOCUMENTS_EXTENSION);

    tvd.writeInt(TermVectorsReader.FORMAT_CURRENT);

    tvf = directory.createOutput(segment + "." + IndexFileNames.VECTORS_FIELDS_EXTENSION);

    tvf.writeInt(TermVectorsReader.FORMAT_CURRENT);

    this.fieldInfos = fieldInfos;

  }

这个函数构造一个TermVectorWriter对象

/**

   * Add a complete document specified by all its term vectors. If document has no

   * term vectors, add value for tvx.

   * 添加一个文档的TermFreqVector到索引中来。

   * vectors.length表示当前文档中field的数量

   * 写入的流程如下:

   * 1.现在tvx中写入当前文档流tvd当前的文件指针地址和当前field流tvf当前的文件指针地址

   * 2.判断vectors长度是否大于1,如果否,表明当前文档包含0个具有stored term vector的field,

   * 在当前tvd流中写入0,表明当前文档中没有含有stored term vector的field

   * 3.如果是,则在当前tvd流中写入fields的数量,向tvd中写入所有field的FieldNums,向tvf中写入vector里的信息

   * 最后再向tvd中写入每个field的指针信息(它们被保存在一个数组中)

   * @param vectors

   * @throws IOException

   */

  public final void addAllDocVectors(TermFreqVector[] vectors)

      throws IOException {

    tvx.writeLong(tvd.getFilePointer());

    tvx.writeLong(tvf.getFilePointer());

    if (vectors != null) {

      final int numFields = vectors.length;

      tvd.writeVInt(numFields);

      long[] fieldPointers = new long[numFields];

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

        fieldPointers[i] = tvf.getFilePointer();

        final int fieldNumber = fieldInfos.fieldNumber(vectors[i].getField());

        // 1st pass: write field numbers to tvd

        //第一轮是写入field的number信息

        tvd.writeVInt(fieldNumber);

        final int numTerms = vectors[i].size();

        //写入当前field的term数量

        tvf.writeVInt(numTerms);

        final TermPositionVector tpVector;

        final byte bits;

        final boolean storePositions;

        final boolean storeOffsets;

        if (vectors[i] instanceof TermPositionVector) {

          // May have positions & offsets

          tpVector = (TermPositionVector) vectors[i];

          storePositions = tpVector.size() > 0 && tpVector.getTermPositions(0) != null;

          storeOffsets = tpVector.size() > 0 && tpVector.getOffsets(0) != null;

          bits = (byte) ((storePositions ? TermVectorsReader.STORE_POSITIONS_WITH_TERMVECTOR : 0) +

                         (storeOffsets ? TermVectorsReader.STORE_OFFSET_WITH_TERMVECTOR : 0));

        } else {

          tpVector = null;

          bits = 0;

          storePositions = false;

          storeOffsets = false;

        }

        //写入bits

        tvf.writeVInt(bits);

        //获得所有term的内容

        final String[] terms = vectors[i].getTerms();

        //获得与上述term数组相匹配的frequecy数组信息

        final int[] freqs = vectors[i].getTermFrequencies();

        //utf8Results[0] [1]在不断的颠倒使用

        int utf8Upto = 0;

        utf8Results[1].length = 0;

        for (int j=0; j<numTerms; j++) {

          UnicodeUtil.UTF16toUTF8(terms[j], 0, terms[j].length(), utf8Results[utf8Upto]);

          

          int start = StringHelper.bytesDifference(utf8Results[1-utf8Upto].result,

                                                   utf8Results[1-utf8Upto].length,

                                                   utf8Results[utf8Upto].result,

                                                   utf8Results[utf8Upto].length);

          int length = utf8Results[utf8Upto].length - start;

          tvf.writeVInt(start);       // write shared prefix length

          tvf.writeVInt(length);        // write delta length

          tvf.writeBytes(utf8Results[utf8Upto].result, start, length);  // write delta bytes

          utf8Upto = 1-utf8Upto;

          final int termFreq = freqs[j];

          tvf.writeVInt(termFreq);

          //如果有位置信息,在这里将每个term的位置信息也写入

          if (storePositions) {

            final int[] positions = tpVector.getTermPositions(j);

            if (positions == null)

              throw new IllegalStateException("Trying to write positions that are null!");

            assert positions.length == termFreq;

            // use delta encoding for positions

            int lastPosition = 0;

            for(int k=0;k<positions.length;k++) {

              final int position = positions[k];

              tvf.writeVInt(position-lastPosition);

              lastPosition = position;

            }

          }

          //不太明白offset的涵义是什么?

          if (storeOffsets) {

            final TermVectorOffsetInfo[] offsets = tpVector.getOffsets(j);

            if (offsets == null)

              throw new IllegalStateException("Trying to write offsets that are null!");

            assert offsets.length == termFreq;

            // use delta encoding for offsets

            int lastEndOffset = 0;

            for(int k=0;k<offsets.length;k++) {

              final int startOffset = offsets[k].getStartOffset();

              final int endOffset = offsets[k].getEndOffset();

              tvf.writeVInt(startOffset-lastEndOffset);

              tvf.writeVInt(endOffset-startOffset);

              lastEndOffset = endOffset;

            }

          }

        }

      }

      // 2nd pass: write field pointers to tvd

      //在第二轮时,我们写入每个field的地址

      if (numFields > 1) {

        long lastFieldPointer = fieldPointers[0];

        for (int i=1; i<numFields; i++) {

          final long fieldPointer = fieldPointers[i];

          tvd.writeVLong(fieldPointer-lastFieldPointer);

          lastFieldPointer = fieldPointer;

        }

      }

    } else

     //这一步写入了当前文档包含的具有Vector的field数量

      tvd.writeVInt(0);

  }

/**

   * Add a complete document specified by all its term vectors. If document has no

   * term vectors, add value for tvx.

   * 添加一个文档的TermFreqVector到索引中来。

   * vectors.length表示当前文档中field的数量

   * 写入的流程如下:

   * 1.现在tvx中写入当前文档流tvd当前的文件指针地址和当前field流tvf当前的文件指针地址

   * 2.判断vectors长度是否大于1,如果否,表明当前文档包含0个具有stored term vector的field,

   * 在当前tvd流中写入0,表明当前文档中没有含有stored term vector的field

   * 3.如果是,则在当前tvd流中写入fields的数量,向tvd中写入所有field的FieldNums,向tvf中写入vector里的信息

   * 最后再向tvd中写入每个field的指针信息(它们被保存在一个数组中)

   * @param vectors

   * @throws IOException

   */

  public final void addAllDocVectors(TermFreqVector[] vectors)

      throws IOException {

    tvx.writeLong(tvd.getFilePointer());

    tvx.writeLong(tvf.getFilePointer());

    if (vectors != null) {

      final int numFields = vectors.length;

      tvd.writeVInt(numFields);

      long[] fieldPointers = new long[numFields];

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

        fieldPointers[i] = tvf.getFilePointer();

        final int fieldNumber = fieldInfos.fieldNumber(vectors[i].getField());

        // 1st pass: write field numbers to tvd

        //第一轮是写入field的number信息

        tvd.writeVInt(fieldNumber);

        final int numTerms = vectors[i].size();

        //写入当前field的term数量

        tvf.writeVInt(numTerms);

        final TermPositionVector tpVector;

        final byte bits;

        final boolean storePositions;

        final boolean storeOffsets;

        if (vectors[i] instanceof TermPositionVector) {

          // May have positions & offsets

          tpVector = (TermPositionVector) vectors[i];

          storePositions = tpVector.size() > 0 && tpVector.getTermPositions(0) != null;

          storeOffsets = tpVector.size() > 0 && tpVector.getOffsets(0) != null;

          bits = (byte) ((storePositions ? TermVectorsReader.STORE_POSITIONS_WITH_TERMVECTOR : 0) +

                         (storeOffsets ? TermVectorsReader.STORE_OFFSET_WITH_TERMVECTOR : 0));

        } else {

          tpVector = null;

          bits = 0;

          storePositions = false;

          storeOffsets = false;

        }

        //写入bits

        tvf.writeVInt(bits);

        //获得所有term的内容

        final String[] terms = vectors[i].getTerms();

        //获得与上述term数组相匹配的frequecy数组信息

        final int[] freqs = vectors[i].getTermFrequencies();

        //utf8Results[0] [1]在不断的颠倒使用

        int utf8Upto = 0;

        utf8Results[1].length = 0;

        for (int j=0; j<numTerms; j++) {

          UnicodeUtil.UTF16toUTF8(terms[j], 0, terms[j].length(), utf8Results[utf8Upto]);

          

          int start = StringHelper.bytesDifference(utf8Results[1-utf8Upto].result,

                                                   utf8Results[1-utf8Upto].length,

                                                   utf8Results[utf8Upto].result,

                                                   utf8Results[utf8Upto].length);

          int length = utf8Results[utf8Upto].length - start;

          tvf.writeVInt(start);       // write shared prefix length

          tvf.writeVInt(length);        // write delta length

          tvf.writeBytes(utf8Results[utf8Upto].result, start, length);  // write delta bytes

          utf8Upto = 1-utf8Upto;

          final int termFreq = freqs[j];

          tvf.writeVInt(termFreq);

          //如果有位置信息,在这里将每个term的位置信息也写入

          if (storePositions) {

            final int[] positions = tpVector.getTermPositions(j);

            if (positions == null)

              throw new IllegalStateException("Trying to write positions that are null!");

            assert positions.length == termFreq;

            // use delta encoding for positions

            int lastPosition = 0;

            for(int k=0;k<positions.length;k++) {

              final int position = positions[k];

              tvf.writeVInt(position-lastPosition);

              lastPosition = position;

            }

          }

          //不太明白offset的涵义是什么?

          if (storeOffsets) {

            final TermVectorOffsetInfo[] offsets = tpVector.getOffsets(j);

            if (offsets == null)

              throw new IllegalStateException("Trying to write offsets that are null!");

            assert offsets.length == termFreq;

            // use delta encoding for offsets

            int lastEndOffset = 0;

            for(int k=0;k<offsets.length;k++) {

              final int startOffset = offsets[k].getStartOffset();

              final int endOffset = offsets[k].getEndOffset();

              tvf.writeVInt(startOffset-lastEndOffset);

              tvf.writeVInt(endOffset-startOffset);

              lastEndOffset = endOffset;

            }

          }

        }

      }

      // 2nd pass: write field pointers to tvd

      //在第二轮时,我们写入每个field的地址

      if (numFields > 1) {

        long lastFieldPointer = fieldPointers[0];

        for (int i=1; i<numFields; i++) {

          final long fieldPointer = fieldPointers[i];

          tvd.writeVLong(fieldPointer-lastFieldPointer);

          lastFieldPointer = fieldPointer;

        }

      }

    } else

     //这一步写入了当前文档包含的具有Vector的field数量

      tvd.writeVInt(0);

  }

在这个类中经常用到TermFreqVector,它是一个接口,提供了当前field中所有term的信息(包括position,termFrequency,offset,termText等信息)。其中position,offset是在TermVector的实现类中提供的。在index中有很多类似的接口类,它们提供了访问一些数据的接口,以后我们慢慢一个个的接触。

源码解析:

/** Provides access to stored term vector of 

 *  a document field.  The vector consists of the name of the field, 

 *  an array of the terms that occur in the field of the

 * {@link org.apache.lucene.document.Document} and a parallel array of frequencies.  

 * Thus, getTermFrequencies()[5] corresponds with the

 * frequency of getTerms()[5], assuming there are at least 5 terms in the Document.

 * getTermFrequencies[5] == frequency of getTerms()[5]

 * Andrew Wang

 * 提供对一个存储term Vector的document Field的访问

 * 这个Vector包含field的名称

 * 

 * 这个是针对一个文档的特定field来说的

 * 这个文档的field文本中的term的freq

 */

这些是对当前接口的注释

/**

   * The {@link org.apache.lucene.document.Fieldable} name. 

   * @return The name of the field this vector is associated with.

   * 获得当前vector所对应的field的名称

   */ 

  public String getField();

  

  /** 

   * @return The number of terms in the term vector.

   * 获得在vector中term的数量

   */

  public int size();

  /** 

   * @return An Array of term texts in ascending order.

   * 按照升序排列

   */

  public String[] getTerms();

  /** Array of term frequencies. Locations of the array correspond one to one

   *  to the terms in the array obtained from <code>getTerms</code>

   *  method. Each location in the array contains the number of times this

   *  term occurs in the document or the document field.

   *  返回一组frequecy数列

   *  它们对应的是一个document或者是一个document的field,表示当前term在这个部分发生的frequency

   *  我在想这个frequcecy到底是对于document而言还是field而言的?

   */

  public int[] getTermFrequencies();


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

历史上的今天

评论

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

页脚

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