前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Lucene系列(六)索引格式之fdt文件

Lucene系列(六)索引格式之fdt文件

作者头像
呼延十
发布2021-02-02 14:35:56
1.3K0
发布2021-02-02 14:35:56
举报
文章被收录于专栏:呼延呼延

前言

本文介绍一下.fdt文件的存储格式.

fdt文件,以正排的方式, 存储了field的原始真实数据. 也就是说, 你添加到所有中的所有field内容. 都会存储在此文件中.

.fdt 文件整体结构

2021-01-27-21-47-15
2021-01-27-21-47-15

其中HeaderFooter, 与其中文件并无差别. 详细字段解释可以看 Lucene系列(二)索引格式之fdm文件

这里主要看一下以chunk为单位进行存储的field信息. 也就是图中的这一部.

2021-01-28-14-06-51
2021-01-28-14-06-51

其中. 对于每一个chunk. 首先会存储一个 ChunkHeader:

2021-01-28-14-07-51
2021-01-28-14-07-51

其中包括:

  • docBase : 当前chunk里的第一个docID.

numBufferedDocs «

slice . 当前块里面缓冲了多少个doc, 可以根据docBase及num来算出每一个docId. 还以bit的方式存储了当前chunk是否分片.

  • 存储每个文档有多少个field. (数组)
  • 存储每个文档的field信息长度(字节长度) (数组)

之后,会将当前chunk的所有field信息进行压缩存储.

2021-01-28-14-34-01
2021-01-28-14-34-01

其中依次罗列了所有的doc, 每个doc中罗列了所有的field.

field信息中, 存储了:

  1. FieldNumberAndType: field的编号及类型
  2. Value: 实际的值, 根据不同类型(int,long,string,bytes等),存储方法不同.

写入代码分析

对.fdt文件的写入, 主要是在CompressingStoredFieldsWriter类中进行.

首先是在构造函数中写入IndexHeader.

2021-01-28-18-44-31
2021-01-28-18-44-31

之后在每次调用flush(), 即每次缓存够一个Chunk时,进行field信息的写入.

2021-01-28-18-46-39
2021-01-28-18-46-39

在图中1处,写入ChunkHeader.

2021-01-28-18-47-22
2021-01-28-18-47-22

按序写入了DocBase, numBufferedDocs|Sliced, NumStoredFields, lengths.

在图中2处,将当前缓冲的所有field信息进行压缩,写入.

内存中缓冲的field信息中包含哪些内容呢? 这部分的写入在CompressingStoredFieldsWriter类的writeField()方法中.

代码语言:javascript
复制
  /**
   * 写了什么?
   * 1.编号及类型
   * 2. 内容
   *    2.1 如果是基本类型,直接存储
   *    2.2 如果是bytes, 写长度和内容
   *    2.3 如果是string, 先写长度,然后写内容
   */
  @Override
  public void writeField(FieldInfo info, IndexableField field)
      throws IOException {

    // 计数+1
    ++numStoredFieldsInDoc;

    int bits = 0;
    final BytesRef bytes;
    final String string;

    Number number = field.numericValue();
    if (number != null) {
      if (number instanceof Byte || number instanceof Short || number instanceof Integer) {
        bits = NUMERIC_INT;
      } else if (number instanceof Long) {
        bits = NUMERIC_LONG;
      } else if (number instanceof Float) {
        bits = NUMERIC_FLOAT;
      } else if (number instanceof Double) {
        bits = NUMERIC_DOUBLE;
      } else {
        throw new IllegalArgumentException("cannot store numeric type " + number.getClass());
      }
      string = null;
      bytes = null;
    } else {
      bytes = field.binaryValue();
      if (bytes != null) {
        bits = BYTE_ARR;
        string = null;
      } else {
        bits = STRING;
        string = field.stringValue();
        if (string == null) {
          throw new IllegalArgumentException("field " + field.name() + " is stored but does not have binaryValue, stringValue nor numericValue");
        }
      }
    }

    // 存储了 field的内部编号, 以及当前field的类型,是四种数字呢,还是字符串,还是二进制串.
    // number , 一个int, 右边的3位是类型, 左边的是编号
    final long infoAndBits = (((long) info.number) << TYPE_BITS) | bits;
    bufferedDocs.writeVLong(infoAndBits);

    if (bytes != null) {
      bufferedDocs.writeVInt(bytes.length);
      bufferedDocs.writeBytes(bytes.bytes, bytes.offset, bytes.length);
    } else if (string != null) {
      bufferedDocs.writeString(string);
    } else {
      if (number instanceof Byte || number instanceof Short || number instanceof Integer) {
        bufferedDocs.writeZInt(number.intValue());
      } else if (number instanceof Long) {
        writeTLong(bufferedDocs, number.longValue());
      } else if (number instanceof Float) {
        writeZFloat(bufferedDocs, number.floatValue());
      } else if (number instanceof Double) {
        writeZDouble(bufferedDocs, number.doubleValue());
      } else {
        throw new AssertionError("Cannot get here");
      }
    }
  }

如代码所示, 首先分析了要存储field的类型及编码, 之后将类型及编号写入一个long,以及field的真实信息,根据不同的类型进行不同的编码,之后缓冲到内存里, 等到一个chunk写入完成或者最终调用finish时,批量的进行写入.

结语

对field原始信息的写入比较简单. 在每次添加一个Document时, 循环调用添加field. 将对应的field编号,类型,内容缓冲到内存里, 每次缓冲够一个Chunk,进行压缩写入.

完。

联系我

最后,欢迎关注我的个人公众号【 呼延十 】,会不定期更新很多后端工程师的学习笔记。 也欢迎直接公众号私信或者邮箱联系我,一定知无不言,言无不尽。

以上皆为个人所思所得,如有错误欢迎评论区指正。

欢迎转载,烦请署名并保留原文链接。

联系邮箱:huyanshi2580@gmail.com

更多学习笔记见个人博客或关注微信公众号 <呼延十 >——>呼延十

var gitment = new Gitment({ id: 'Lucene系列(六)索引格式之fdt文件', // 可选。默认为 location.href owner: 'hublanker', repo: 'blog', oauth: { client_id: '2297651c181f632a31db', client_secret: 'a62f60d8da404586acc965a2ba6a6da9f053703b', }, }) gitment.render('container')



本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • .fdt 文件整体结构
  • 写入代码分析
  • 结语
  • 联系我
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档