zoukankan      html  css  js  c++  java
  • lucene正向索引(续)——一个文档的所有filed+value都在fdt文件中!!!

    4.1.3. 域(Field)的数据信息(.fdt,.fdx)

    fdxfdt

    • 域数据文件(fdt):
      • 真正保存存储域(stored field)信息的是fdt文件
      • 在一个段(segment)中总共有segment size篇文档,所以fdt文件中共有segment size个项,每一项保存一篇文档的域的信息
      • 对于每一篇文档,一开始是一个fieldcount,也即此文档包含的域的数目,接下来是fieldcount个项,每一项保存一个域的信息。
      • 对于每一个域,fieldnum是域号,接着是一个8位的byte,最低一位表示此域是否分词(tokenized),倒数第二位表示此域是保存字符串数据还是二进制数据,倒数第三位表示此域是否被压缩,再接下来就是存储域的值,比如new Field("title", "lucene in action", Field.Store.Yes, …),则此处存放的就是"lucene in action"这个字符串。
    • 域索引文件(fdx)
      • 由域数据文件格式我们知道,每篇文档包含的域的个数,每个存储域的值都是不一样的,因而域数据文件中segment size篇文档,每篇文档占用的大小也是不一样的,那么如何在fdt中辨别每一篇文档的起始地址和终止地址呢,如何能够更快的找到第n篇文档的存储域的信息呢?就是要借助域索引文件。
      • 域索引文件也总共有segment size个项,每篇文档都有一个项,每一项都是一个long,大小固定,每一项都是对应的文档在fdt文件中的起始地址的偏移量,这样如果我们想找到第n篇文档的存储域的信息,只要在fdx中找到第n项,然后按照取出的long作为偏移量,就可以在fdt文件中找到对应的存储域的信息。
    • 读取域数据信息的代码如下:

    Document FieldsReader.doc(int n, FieldSelector fieldSelector)

    • long position = indexStream.readLong();//indexStream points to ".fdx"
    • fieldsStream.seek(position);//fieldsStream points to "fdt"
    • int numFields = fieldsStream.readVInt();
    • for (int i = 0; i < numFields; i++)
      • int fieldNumber = fieldsStream.readVInt();
      • byte bits = fieldsStream.readByte();
      • boolean compressed = (bits & FieldsWriter.FIELD_IS_COMPRESSED) != 0;
      • boolean tokenize = (bits & FieldsWriter.FIELD_IS_TOKENIZED) != 0;
      • boolean binary = (bits & FieldsWriter.FIELD_IS_BINARY) != 0;
      • if (binary)
        • int toRead = fieldsStream.readVInt();
        • final byte[] b = new byte[toRead];
        • fieldsStream.readBytes(b, 0, b.length);
        • if (compressed)
          • int toRead = fieldsStream.readVInt();
          • final byte[] b = new byte[toRead];
          • fieldsStream.readBytes(b, 0, b.length);
          • uncompress(b),
      • else
        • fieldsStream.readString()

    4.1.3. 词向量(Term Vector)的数据信息(.tvx,.tvd,.tvf)——term vector用于打分,存储StoreTermVectors的field 

    termvector

    词向量信息是从索引(index)到文档(document)到域(field)到词(term)的正向信息,有了词向量信息,我们就可以得到一篇文档包含那些词的信息。

    • 词向量索引文件(tvx)
      • 一个段(segment)包含N篇文档,此文件就有N项,每一项代表一篇文档。
      • 每一项包含两部分信息:第一部分是词向量文档文件(tvd)中此文档的偏移量,第二部分是词向量域文件(tvf)中此文档的第一个域的偏移量。
    • 词向量文档文件(tvd)
      • 一个段(segment)包含N篇文档,此文件就有N项,每一项包含了此文档的所有的域的信息。
      • 每一项首先是此文档包含的域的个数NumFields,然后是一个NumFields大小的数组,数组的每一项是域号。然后是一个(NumFields - 1)大小的数组,由前面我们知道,每篇文档的第一个域在tvf中的偏移量在tvx文件中保存,而其他(NumFields - 1)个域在tvf中的偏移量就是第一个域的偏移量加上这(NumFields - 1)个数组的每一项的值。
    • 词向量域文件(tvf)
      • 此文件包含了此段中的所有的域,并不对文档做区分,到底第几个域到第几个域是属于那篇文档,是由tvx中的第一个域的偏移量以及tvd中的(NumFields - 1)个域的偏移量来决定的。
      • 对于每一个域,首先是此域包含的词的个数NumTerms,然后是一个8位的byte,最后一位是指定是否保存位置信息,倒数第二位是指定是否保存偏移量信息。然后是NumTerms个项的数组,每一项代表一个词(Term),对于每一个词,由词的文本TermText,词频TermFreq(也即此词在此文档中出现的次数),词的位置信息,词的偏移量信息。
    • 读取词向量数据信息的代码如下:

    TermVectorsReader.get(int docNum, String field, TermVectorMapper)

    • int fieldNumber = fieldInfos.fieldNumber(field);//通过field名字得到field号
    • seekTvx(docNum);//在tvx文件中按docNum文档号找到相应文档的项
    • long tvdPosition = tvx.readLong();//找到tvd文件中相应文档的偏移量
    • tvd.seek(tvdPosition);//在tvd文件中按偏移量找到相应文档的项
    • int fieldCount = tvd.readVInt();//此文档包含的域的个数。
    • for (int i = 0; i < fieldCount; i++) //按域号查找域
      • number = tvd.readVInt();
      • if (number == fieldNumber)
        • found = i;
    • position = tvx.readLong();//在tvx中读出此文档的第一个域在tvf中的偏移量
    • for (int i = 1; i <= found; i++)
      • position += tvd.readVLong();//加上所要找的域在tvf中的偏移量
    • tvf.seek(position);
    • int numTerms = tvf.readVInt();
    • byte bits = tvf.readByte();
    • storePositions = (bits & STORE_POSITIONS_WITH_TERMVECTOR) != 0;
    • storeOffsets = (bits & STORE_OFFSET_WITH_TERMVECTOR) != 0;
    • for (int i = 0; i < numTerms; i++)
      • start = tvf.readVInt();
      • deltaLength = tvf.readVInt();
      • totalLength = start + deltaLength;
      • tvf.readBytes(byteBuffer, start, deltaLength);
      • term = new String(byteBuffer, 0, totalLength, "UTF-8");
      • if (storePositions)
        • positions = new int[freq];
        • int prevPosition = 0;
        • for (int j = 0; j < freq; j++)
          • positions[j] = prevPosition + tvf.readVInt();
          • prevPosition = positions[j];
      • if (storeOffsets)
        • offsets = new TermVectorOffsetInfo[freq];
        • int prevOffset = 0;
        • for (int j = 0; j < freq; j++)
        • int startOffset = prevOffset + tvf.readVInt();
        • int endOffset = startOffset + tvf.readVInt();
        • offsets[j] = new TermVectorOffsetInfo(startOffset, endOffset);
        • prevOffset = endOffset;
     
  • 相关阅读:
    Luogu 1080 【NOIP2012】国王游戏 (贪心,高精度)
    Luogu 1314 【NOIP2011】聪明的质检员 (二分)
    Luogu 1315 【NOIP2011】观光公交 (贪心)
    Luogu 1312 【NOIP2011】玛雅游戏 (搜索)
    Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)
    Luogu 1514 引水入城 (搜索,动态规划)
    UVA 1394 And Then There Was One / Gym 101415A And Then There Was One / UVAlive 3882 And Then There Was One / POJ 3517 And Then There Was One / Aizu 1275 And Then There Was One (动态规划,思维题)
    Luogu 1437 [HNOI2004]敲砖块 (动态规划)
    Luogu 1941 【NOIP2014】飞扬的小鸟 (动态规划)
    HDU 1176 免费馅饼 (动态规划)
  • 原文地址:https://www.cnblogs.com/bonelee/p/6394882.html
Copyright © 2011-2022 走看看