当前位置: 首页 > article >正文

lucene数据写入-02倒排数据缓存组织

上面分析了数据写入的代码逻辑,我们现在来看下倒排数据保存在内存中是什么样的

在索引过程中数据会将term分词的长度、将文档号(doc ID),词频(freq)和位置(prox)信息都存储在bytePool中,其中文档号docID和freqs写到一个块中,而位置信息prox会写到另一个块中,块存储有不同的级别,不同的级别长度和分隔符不同。intPool保存了bytePool中保存的docID、freqs和位置信息的偏移量,所以每个分词在intPool中都会使用两个int保存两个偏移量,第0个表示docid + freq在bytePool中的写入位置偏移量,第1个表示prox在bytePool中的写入位置偏移量。

我们以写入一下数据为例分析一下如何记录这些信息

document.add(new TextField("desc", "common common common common common term", Field.Store.YES));
document1.add(new TextField("desc", "common common common common common term term", Field.Store.YES));
document2.add(new TextField("desc", "term term term common common common common common", Field.Store.YES));
document3.add(new TextField("desc", "term", Field.Store.YES));
  • 写入文档0的第一个common

首先会将common的长度和该分词写入到bytePool中,然后分配两个级别为1的块每个块长度为5,结束符号为16,第一个块用来存储common的docID和freqs,docID和freqs信息总是在下一篇文档的处理过程出现了"common"的时候方才写入,因为当一篇文档没有处理完毕的时候,freq也即词频是无法知道的,第二个块用来存储common的位置信息,此处common在第一位所以位置信息就是0,但是此0应该左移一位,最后一位置0表示没有payload存储。

intPool中分配了两个int,第一个int值为7是记录docID和freqs将要写入的偏移量,第二个int值为13是因为已经写入了第一个common的位置信息了,表示的是下一个位置信息写入的偏移量

posting表记录了common的词频和lastPosition信息等。其中intStarts和byteStarts分别记录了读取intPool和bytePool的起始位置
在这里插入图片描述

  • 写入文档0的第二、三、四个common都和上面类似,bytePool中会写入位置,intPool第二个int会更新,postings中记录的词频和lastPosition会更新

在这里插入图片描述

  • 写入第三个common
    在这里插入图片描述
  • 写入第四个common
    在这里插入图片描述
  • 写入第五个common
    当写入第五个common时候,存储位置信息的快空间不够了已经到达了结束符16,需要进行扩容,新的快层次为2,长度为14,结束符号为17,在缓存的最后分配。原来的块中会腾出4个位置用来存储新位置的指针信息,这里为0 0 0 17,也就是读取的位置是从17开始,将原来结束符前3个字符分别copy到指针之后,也就是将13、14、15的值copy到17、18、19,然后将第五个common的位置写入,同时更新intPool中第二个int为21,posting表中词频和最后位置更新
    在这里插入图片描述
  • 写入文档0的第一个term

bytePool中首先写入term的长度4和term字符串,然后分配两个块,一个块用来存储docID、freqs这里暂时不会写入,另一个块用来存储prox,这里的脚本为5,后面的0表示没有payload,写入值为10,5<<1 + 0 = 10

intPool新分配了两个int用来存储term的docID、freqs和prox在bytePool中的偏移量

postings中更新textStarts记录了分词的起始偏移量,termFreqs词频,lastPosition位置信息,intStarts和byteStarts读取位置
在这里插入图片描述

  • 写入文档1的第一个common

开始写入上一个文档的common的docID和freqs,上一个文档的docID为0,出现的次数为5,存放的信息为[docid<<1 + 0, 5] = [0, 5],docid左移一位,最后一位为0表示freq大于1,写入到bytePool索引位置为8和9的位置。
在这里插入图片描述
在这里插入图片描述
然后写入文档1的第一个common的位置信息,0<<1 + 0 = 0,写入到下标为21的位置

posting更新termFreqs、lastDocIDs、lastDocCodes
在这里插入图片描述

  • 写入文档1的第二个common
    在这里插入图片描述
  • 写入文档1的第三个common
    在这里插入图片描述
  • 写入文档1的第四个common
    在这里插入图片描述
  • 写入文档1的第五个common和写入文档1的第一个term

第一篇文档中的term的docid+freq信息写入,在第一篇文档中term只出现了一次所以只需要一个字节来保存docID和freqs,0|1=1

if (1 == postings.termFreqs[termID]) {
    writeVInt(0, postings.lastDocCodes[termID]|1);
} else {
    writeVInt(0, postings.lastDocCodes[termID]);
    writeVInt(0, postings.termFreqs[termID]);
}

intPool更新第三个int的写入位置记录

postings更新lastDocIDs
在这里插入图片描述
写入文档1的第一个term的位置,在第5个位置,5<<1 + 0 = 10
在这里插入图片描述

  • 写入文档1的第二个term

写入第二个term的位置(fieldState.position-postings.lastPositions[termID])<<1,(6-5)<<1=2

intPool写入prox的偏移量更新

postings中的termFreqs和lastPositions更新
在这里插入图片描述

  • 写入文档2的第一个term

bytePool写入文档1的term的docID和freqs,[docid<<1 + 0, 2] = [2, 2],docid左移一位,最后一位为0表示freq大于1。

intPool更新第三个块的写入偏移量

postings中的lastDocIDs更新
在这里插入图片描述
bytePool写入位置信息0<<1 + 0 = 0

intPool第四个int更新

postings中termFreqs更新、lastPositions更新
在这里插入图片描述

  • 写入文档2的第二个term

和上面一样存储位置信息的空间不够了,需要进行扩容,新的块级别为2,长度为14,结束符号为17,另外将原来分隔符前三个字节copy到原来的分隔符之后,将空出来的空间已经原来的分隔符构成一个int,保存新的指针信息,这里就是46,然后将位置信息写入
在这里插入图片描述

  • 写入文档2的第三个term
    在这里插入图片描述
  • 写入文档2的第一个common

docid+freq信息写入,文档1中的common,出现了5次,存储为[docid << 1 + 0, freq],docid取差值为1,因而存储为 [2, 5]
在这里插入图片描述
bytePool写入common的位置信息,3<<1+0=6
在这里插入图片描述

  • 写入文档2的第二个common
    在这里插入图片描述
  • 写入文档2的第三个common
    在这里插入图片描述
  • 写入文档2的第四个common
    在这里插入图片描述
  • 写入文档2的第五个common

存储common的位置信息的空间已经不足,需要进行扩容,分配新的块,层次为3,大小为20,结束符为18, 和上面一样需要将分隔符前三个字节的数据copy到新的位置,另外包括分隔符和前三个空出来的空间组成一个int指针,指向新的读取位置
在这里插入图片描述

  • 写入文档3的第一个term

term的docID+freqs信息,文档号为2,出现了3次,存储为[docid<<1+0, freq],docid取差值为1,因而存储为[2, 3],但是存储docID和freqs的空间已经满了,一样需要进行扩容,这里新分配的快层级为2,空间长度为14,结束符号为17,重新的尾部分配空间,将原来分隔符前的三个字节copy到新位置,原来的分隔符和空出来的空间组成一个int保存指针信息
在这里插入图片描述
写入term的位置信息
在这里插入图片描述
所有数据写入完毕最终内存空间如下
在这里插入图片描述
postings中主要记录的是分词的读取时候的信息,而intPool主要记录的是docID+freqs和prox在bytePool中的写入位置信息,而bytePool则是记录倒排数据。在flush写入文件的过程中则是一个读取的过程,将这些信息读出来写入.pos文件、.doc文件、.tim文件等


http://www.kler.cn/news/366412.html

相关文章:

  • STM32 从0开始系统学习 1
  • 8.three.js相机详解
  • java智能物流管理系统源码(springboot)
  • 05方差分析续
  • 数字IC后端实现 | Innovus各个阶段常用命令汇总
  • mac nwjs程序签名公证(其他mac程序也一样适用)
  • 【c++ arx 选项板2】
  • Python Pandas 数据分析的得力工具:简介
  • 中小企业设备资源优化:Spring Boot系统实现
  • Kafka-代码示例
  • 408算法题leetcode--第40天
  • MemoRAG:重新定义长期记忆的AI问答模型
  • 如何测手机到路由器的内网带宽【使用iperf3】
  • 【Android常见开发模式】
  • 尚硅谷-react教程-求和案例-数据共享(下篇)-完成数据共享-笔记
  • 神经种群动态优化算法(NPDOA)-2024年9年SCI一区新算法-公式原理详解 Matlab代码免费获取
  • LeetCode 热题100之哈希
  • Android Activity 自定义方法 不混淆,可以使用@Keep注解
  • go 内存分配管理
  • 安全见闻6-7
  • NumPy学习Day18
  • RHCSA基础命令整理1
  • 将jinjia2后端传到前端的字典数据转化为json
  • 【实验六】基于前馈神经网络的二类任务
  • 梦熊十三联测 A题 加减乘除
  • JS无限执行隔行变色