zoukankan      html  css  js  c++  java
  • [转帖]lucene2.9.0 索引过程(一) TermsHashPerField

    TermsHashPerField 类

    一、类功能概述:

    负责词项的索引过程,每个字段有相应的一个TermsHashPerField;当索引某字段词项时,使用对应TermsHashPerField的add()函数完成(一个)词项索引过程,并将索引内容(词项字符串/指针信息/位置信息等)存储于内存缓冲中

    二、类成员说明:

    2.1 final int streamCount;

    如果需要记录词频和位置,此值为2(用两个int记录偏移指针),否则为1

    // 代码如下

    streamCount = consumer.getStreamCount(); // FreqProxTermsWriterPerField //

    2.2 TermAttribute termAtt;

    分词后的词项存储于此,因此索引时从termAtt中将词项取出

    2.3  RawPostingList[]和RawPostingList

    代码如下

    private RawPostingList[] postingsHash = new RawPostingList[postingsHashSize];

    private RawPostingList p;

    每个p记录了该词项的偏移地址、文档编号、文档频率(df)、位置信息

    并存储在postingsHash中,下标是哈希值

    保存了偏移地址

    abstract class RawPostingList {

      int textStart;

      int intStart;

      int byteStart;

    }

    但实际上存储的是FreqProxTermsWriter.PostingList

    意思很浅显,代码如下:

    static final class PostingList extends RawPostingList {

        int docFreq;    // # times this term occurs in the current doc

        int lastDocID;  // Last docID where this term occurred

        int lastDocCode;  // Code for prior doc

        int lastPosition;    // Last position where this term occurred

      }

    因此postingsHash存储的其实是

    [0]= FreqProxTermsWriter$PostingList  (id=23)   

             byteStart= 0    

             docFreq= 1      

             intStart= 0       

             lastDocCode= 0       

             lastDocID= 0   

             lastPosition= 0         

             textStart= 0    

    postingsHash存储的是该字段所有词项的一些索引信息,根据词项字符的编码值作为初始值hash到postingsHash中

    代码如下:

    int hashPos = code & postingsHashMask;

    如果出现地址冲突,以固定步长递增编码值,查找空位置,填入p,此步长为

    final int inc = ((code>>8)+code)|1;

    代码如下

    do {

            code += inc;

            hashPos = code & postingsHashMask ;

            p = postingsHash[hashPos];

    } while (p != null && !postingEquals(tokenText, tokenTextLen));

    另外,如果postingsHash的使用率超过一半(使用率可调),将扩展之

    代码如下

          if (numPostings == postingsHashHalfSize)

            rehashPostings(2*postingsHashSize);

    2.2 字符串缓冲

    以下三个是存储索引内容的缓冲,最终还是从DocumentsWriter中获得,此缓冲中的索引结构并不是最终写入磁盘的索引内容结构

    intPool = perThread.intPool;

    charPool = perThread.charPool;

    bytePool = perThread.bytePool;

    2.2.1 final CharBlockPool charPool; -

    存储词项内容(字符串内容)

    连续存储,相邻词项间隔1个char,即存储textLen+1长度

    字符串指针记录了每个词项的开始位置(无记录长度和结束位置,仅通过相邻字符串起始位置得知长度)

    例如

    华  南 理 工 大 学  2 0 0 9 1 0 1 9 0 1 4 6

    |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|

    2.2.2 final IntBlockPool intPool;

    存储的是位置信息的偏移值

     for(int i=0;i<streamCount;i++)

     {

    // intUptos[intUptoStart+1]记录的是位置信息偏移值,

    // intUptos[intUptoStart+0]尚未明白

         final int upto = bytePool.newSlice(ByteBlockPool.FIRST_LEVEL_SIZE);

            intUptos[intUptoStart+i] = upto + bytePool.byteOffset;

     }

    隔2(streamCount)存储一个词项,即每个词项记录了两个指针

    2.2.3 final ByteBlockPool bytePool;

    写入词项位置信息

    隔10存储一个词项位置(编码后)

    |-|-|---|

    0-5-10-15

    间隔10 这个值由以下决定的

    1. ByteBlockPool.FIRST_LEVEL_SIZE =5

    2. 已经提及到的:当需要保存词项频率和词项位置时streamCount =2

    代码如下

    for(int i=0;i<streamCount;i++)

    {

    final int upto = bytePool.newSlice(ByteBlockPool.FIRST_LEVEL_SIZE);

       intUptos[intUptoStart+i] = upto + bytePool.byteOffset;

    }

    三、类成员函数说明

    3.1 构造函数

      public TermsHashPerField(DocInverterPerField docInverterPerField,

                               final TermsHashPerThread perThread,

                               final TermsHashPerThread nextPerThread,

                               final FieldInfo fieldInfo)

    一些索引全局变量在构造函数时传入

    final FieldInfo fieldInfo是字段信息

    传入缓冲内存池

        intPool = perThread.intPool;

        charPool = perThread.charPool;

    bytePool = perThread.bytePool;

    3.2 索引过程

    索引过程由add()函数完成

      void add() throws IOException {}

      void add() throws IOException {

        // 获得分词后的词项内容和长度

        final char[] tokenText = termAtt.termBuffer();

        final int tokenTextLen = termAtt.termLength();

       

        // 计算postingsHash位置,使用词项字符做编码值

        int downto = tokenTextLen;

        int code = 0;

       

        while (downto > 0) {

       

          // 高位起

       

          char ch = tokenText[--downto];

        

         //  中间省去Unicode情况

        

          code = (code*31) + ch;  // 字符编码

        } // while (downto > 0)

        // 词项最终编码

       

        int hashPos = code & postingsHashMask;

        // Locate RawPostingList in hash

        p = postingsHash[hashPos];

        // 如果该哈席位已经填充,遍历寻找下一个空位

        if (p != null && !postingEquals(tokenText, tokenTextLen)) {

          // Conflict: keep searching different locations in

          // the hash table.

          final int inc = ((code>>8)+code)|1;

          do {

            code += inc;

            hashPos = code & postingsHashMask;

            p = postingsHash[hashPos];

          } while (p != null && !postingEquals(tokenText, tokenTextLen));

        }

        // 找到一个可以填充的位置(postingsHash未曾索引过此词项)

        if (p == null) { // 第一次p为空,因为没有哈希冲突

          final int textLen1 = 1+tokenTextLen;

         

          // 存储词项字符的缓冲已满,扩展之

          if (textLen1 + charPool.charUpto > DocumentsWriter.CHAR_BLOCK_SIZE)  // 16384

          {

            if (textLen1 > DocumentsWriter.CHAR_BLOCK_SIZE) {

              if (docState.maxTermPrefix == null)

                docState.maxTermPrefix = new String(tokenText, 0, 30);

              consumer.skippingLongTerm();

              return;

            }

            charPool.nextBuffer();

          }

          // Pull next free RawPostingList from free list

          p = perThread.freePostings[--perThread.freePostingsCount];

        

          final char[] text = charPool.buffer;

          final int textUpto = charPool.charUpto;

          // 记录词项字符的偏移地址值

          p.textStart = textUpto + charPool.charOffset;

          charPool.charUpto += textLen1(原字符长度+1);

         // 将词项字符拷贝至缓冲中

          System.arraycopy(tokenText, 0, text, textUpto, tokenTextLen);

          text[textUpto+tokenTextLen] = 0xffff;

             

          assert postingsHash[hashPos] == null;

          postingsHash[hashPos] = p;

          numPostings++;

          // postingsHash如果使用率超过一半,扩展之

          if (numPostings == postingsHashHalfSize)

            rehashPostings(2*postingsHashSize);

          // Init stream slices

          if (numPostingInt + intPool.intUpto > DocumentsWriter.INT_BLOCK_SIZE)

            intPool.nextBuffer(); // 内存不足,申请

          if (DocumentsWriter.BYTE_BLOCK_SIZE - bytePool.byteUpto < numPostingInt*ByteBlockPool.FIRST_LEVEL_SIZE)

            bytePool.nextBuffer(); //内存不足,申请

          intUptos = intPool.buffer; // 记录偏移量

          intUptoStart = intPool.intUpto;

          intPool.intUpto += streamCount; // 每个词项使用streamCount偏移值

          p.intStart = intUptoStart + intPool.intOffset;

          for(int i=0;i<streamCount;i++)

          {

            final int upto = bytePool.newSlice(ByteBlockPool.FIRST_LEVEL_SIZE);

            intUptos[intUptoStart+i] = upto + bytePool.byteOffset;

          }

         

          p.byteStart = intUptos[intUptoStart];

          consumer.newTerm(p);

        } else {

        // 这说明已经索引过此词项(再次在原始文档中出现)

         

          intUptos = intPool.buffers[p.intStart >> DocumentsWriter.INT_BLOCK_SHIFT];

          intUptoStart = p.intStart & DocumentsWriter.INT_BLOCK_MASK;

          consumer.addTerm(p); // 添加posting list 且压缩编码

        }

      }

    四 实验

    以下的数据支撑以上的解析,索引文档,

    文档一的内容为”新浪新闻”,而文档二的内容为”联合早报”

    adding D:\file\2.txt

    intUptoStart= 16

    intPool.intUpto= 18

    p.intStart= 16

    intUptos[intUptoStart+i]= 80

    intUptos[intUptoStart+i]= 85

    p.byteStart= 80

    bytes[85]= 0

    RawPostingList P 的值如下:

    byteStart= 80

    docFreq= 1

    intStart= 16

    lastDocCode= 2

    lastDocID= 1

    lastPosition= 0

    textStart= 39

    termsHashPerField.writeVInt(1,0)

    intUptoStart= 18

    intPool.intUpto= 20

    p.intStart= 18

    intUptos[intUptoStart+i]= 90

    intUptos[intUptoStart+i]= 95

    p.byteStart= 90

    bytes[95]= 2

    RawPostingList P 的值如下:

    byteStart= 90

    docFreq= 1

    intStart= 18

    lastDocCode= 2

    lastDocID= 1

    lastPosition= 0

    textStart= 41

    termsHashPerField.writeVInt(1,1)

    新(注意:第二次出现此词项)

    intUptoStart= 16

    intPool.intUpto= 20

    p.intStart= 16

    bytes[86]= 4 // 连续存储词项位置信息

    RawPostingList P 的值如下:

    byteStart= 80

    docFreq= 2  // 文档df设置为2

    intStart= 16

    lastDocCode= 2

    lastDocID= 1

    lastPosition= 0

    textStart= 39

    termsHashPerField.writeVInt(1,2)

    intUptoStart= 20

    intPool.intUpto= 22

    p.intStart= 20

    intUptos[intUptoStart+i]= 100

    intUptos[intUptoStart+i]= 105

    p.byteStart= 100

    bytes[105]= 6

    RawPostingList P 的值如下:

    byteStart= 100

    docFreq= 1

    intStart= 20

    lastDocCode= 2

    lastDocID= 1

    lastPosition= 0

    textStart= 43

    termsHashPerField.writeVInt(1,3)

    200910190147

    intUptoStart= 22

    intPool.intUpto= 24

    p.intStart= 22

    intUptos[intUptoStart+i]= 110

    intUptos[intUptoStart+i]= 115

    p.byteStart= 110

    bytes[115]= 0

    byteStart= 110

    docFreq= 1

    intStart= 22

    lastDocCode= 2

    lastDocID= 1

    lastPosition= 0

    textStart= 45

    D:\file\2.txt

    intUptoStart= 24

    intPool.intUpto= 26

    p.intStart= 24

    intUptos[intUptoStart+i]= 120

    intUptos[intUptoStart+i]= 125

    p.byteStart= 120

    bytes[125]= 0

    byteStart= 120

    docFreq= 1

    intStart= 24

    lastDocCode= 2

    lastDocID= 1

    lastPosition= 0

    textStart= 58

    adding D:\file\3.txt

    intUptoStart= 26

    intPool.intUpto= 28

    p.intStart= 26

    intUptos[intUptoStart+i]= 130

    intUptos[intUptoStart+i]= 135

    p.byteStart= 130

    bytes[135]= 0

    RawPostingList P 的值如下:

    byteStart= 130

    docFreq= 1

    intStart= 26

    lastDocCode= 4

    lastDocID= 2

    lastPosition= 0

    textStart= 72

    intUptoStart= 28

    intPool.intUpto= 30

    p.intStart= 28

    intUptos[intUptoStart+i]= 140

    intUptos[intUptoStart+i]= 145

    p.byteStart= 140

    bytes[145]= 2

    RawPostingList P 的值如下:

    byteStart= 140

    docFreq= 1

    intStart= 28

    lastDocCode= 4

    lastDocID= 2

    lastPosition= 0

    textStart= 74

    intUptoStart= 30

    intPool.intUpto= 32

    p.intStart= 30

    intUptos[intUptoStart+i]= 150

    intUptos[intUptoStart+i]= 155

    p.byteStart= 150

    bytes[155]= 4

    RawPostingList P 的值如下:

    byteStart= 150

    docFreq= 1

    intStart= 30

    lastDocCode= 4

    lastDocID= 2

    lastPosition= 0

    textStart= 76

    intUptoStart= 32

    intPool.intUpto= 34

    p.intStart= 32

    intUptos[intUptoStart+i]= 160

    intUptos[intUptoStart+i]= 165

    p.byteStart= 160

    bytes[165]= 6

    RawPostingList P 的值如下:

    byteStart= 160

    docFreq= 1

    intStart= 32

    lastDocCode= 4

    lastDocID= 2

    lastPosition= 0

    textStart= 78

    200910190148

    intUptoStart= 34

    intPool.intUpto= 36

    p.intStart= 34

    intUptos[intUptoStart+i]= 170

    intUptos[intUptoStart+i]= 175

    p.byteStart= 170

    bytes[175]= 0

    D:\file\3.txt

    intUptoStart= 36

    intPool.intUpto= 38

    p.intStart= 36

    intUptos[intUptoStart+i]= 180

    intUptos[intUptoStart+i]= 185

    p.byteStart= 180


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/todaylxp/archive/2009/10/25/4726017.aspx

  • 相关阅读:
    PE文件捆绑实现二:(远程线程注入)
    C++中Vector清空
    ttrss更新到最新版本后发访问非80和443端口规避
    Git配置https_proxy访问github失败
    Haproxy配置拦截指定src的连接
    synology git管理程序添加
    ActiveMQ深入浅出系列 (一)
    sl4fj日志级别
    HTTP上传文件解析
    linux下jcmd无法获取jvmdump
  • 原文地址:https://www.cnblogs.com/LeftNotEasy/p/1655966.html
Copyright © 2011-2022 走看看