Lucene 8.7.0 版本中dvd、dvm文件详解 - 教程

news/2025/9/29 8:16:39/文章来源:https://www.cnblogs.com/tlnshuju/p/19118035

Lucene 8.7.0 版本中dvd、dvm文件详解 - 教程

2025-09-29 08:12  tlnshuju  阅读(0)  评论(0)    收藏  举报

一、一句话总结

.dvm.dvd 文件共同构成了 Lucene 的 DocValues 数据。

  • .dvm (DocValues Metadata): 元数据文件,记录了哪些字段拥有 DocValues、它们的类型以及在 .dvd 文件中的位置信息。可以理解为是 .dvd 文件的“目录”或“索引”。
  • .dvd (DocValues Data): 数据文件,包含了所有文档的实际 DocValues 值,但这些值经过了高度压缩和特定格式的编码。

二、深入理解:什么是 DocValues?

在了解文件格式之前,必须先理解 DocValues 是什么。

传统的 Lucene 索引是倒排索引 (Inverted Index),它的结构是 词项 -> 文档列表。这非常适合搜索,比如查找包含 “Lucene” 这个词的所有文档。

但是,对于某些操作,倒排索引效率极低,例如:

为了高效地执行这些操作,需要一种能够快速从 文档ID -> 字段值 的数据结构。这就是 DocValues,它是一种正向索引,也被称为列式存储 (Columnar Storage)

核心思想:DocValues 将每个字段的值按文档 ID 顺序存储起来,形成一列数据。当需要对某个字段进行排序或聚合时,Lucene 可以像操作数据库的列一样,快速地、顺序地访问所有文档的该字段值,而无需遍历整个倒排索引,从而极大地提升了性能。


三、.dvm 文件详解 (DocValues Metadata)

.dvm 文件是元数据文件,它的体积很小,但至关重要。它就像一本书的目录,告诉你每一章(每个字段的 DocValues)在正文(.dvd 文件)的哪个位置。

它的主要内容包括:

  1. 头部信息 (Header):包含 Lucene 的编解码器名称和版本号,用于校验文件格式的正确性。
  2. 字段条目 (Field-level Entries):对于索引段 (Segment) 中每一个拥有 DocValues 的字段,.dvm 文件都会有一条记录,包含以下信息:
    • 字段编号 (Field Number):字段在内部的唯一标识符。
    • DocValues 类型 (DocValues Type):这是最关键的信息之一,决定了 .dvd 文件中数据的编码和解码方式。主要类型有:
      • NUMERIC:64位长整型数字。
      • BINARY:可变长度的字节数组(例如字符串)。
      • SORTED:经过字典编码的单值 BINARY 类型,主要用于排序和单值分面。
      • SORTED_SET:经过字典编码的多值 BINARY 类型,用于多值分面(如商品的多个标签)。
      • SORTED_NUMERIC:经过排序的多值 NUMERIC 类型。
    • 数据偏移量 (Offset):指示该字段的 DocValues 数据在 .dvd 文件中的起始位置(字节偏移)。
    • 数据长度 (Length):该字段数据在 .dvd 文件中占用的总字节数。
    • 其他元数据:根据类型不同,可能还包含额外信息。例如,对于 SORTED 类型,可能包含其值基数(唯一值的数量)等。

工作流程:当 Lucene 需要访问某个字段(比如 “price”)的 DocValues 时,它首先会读取 .dvm 文件,找到 “price” 字段对应的条目,获取其类型(NUMERIC)、在 .dvd 文件中的偏移量和长度。然后,它会直接跳转到 .dvd 文件中的指定位置,并使用与 NUMERIC 类型相匹配的解码器来读取数据。


四、.dvd 文件详解 (DocValues Data)

.dvd 文件是真正存储数据的“大家伙”。它是一个二进制数据块,包含了所有字段的 DocValues 值紧密排列在一起。它本身不包含任何元数据,必须依赖 .dvm 文件才能被正确解析。

其内部数据的存储方式完全取决于字段的 DocValues 类型,并且 Lucene 8.7.0 会使用非常高效的压缩策略来节省磁盘空间和提高读取速度。

以下是不同类型的数据在 .dvd 文件中的典型存储方式:

1. NUMERIC 类型 (例如:价格、年龄、时间戳)

Lucene 不会傻瓜式地为每个文档存储一个 64 位的 long。它会分析这个字段中所有值的特点,选择最优的压缩策略:

2. BINARY 类型 (例如:UUID、固定长度的字符串)
  • 固定长度:如果所有值的长度都一样,数据会直接连续存储。
  • 可变长度:通常会把所有字节数据连接成一个大的字节块,然后用一个额外的元数据结构(也存储在 .dvd 中)来记录每个文档对应值的起始和结束位置。
3. SORTED / SORTED_SET 类型 (例如:商品分类、标签)

这是 DocValues 最强大的应用之一,使用了字典编码 (Dictionary Encoding)

这种方式的优势是巨大的:


五、一个形象的比喻

把一个 Lucene 索引段想象成一本关于商品的百科全书。

  • 倒排索引 (.tim, .doc等文件):是书末尾的“名词索引”。你想找“手机”,索引会告诉你它在第 10, 25, 88 页出现过。
  • DocValues (.dvm, .dvd 文件):是一张巨大的表格附录。
    • 表格的列头:价格、品牌、上市日期…
    • 表格的行:第1个商品、第2个商品、第3个商品…
    • .dvm 文件:是这张表格的“图例”和“说明”。它告诉你,“价格”是数字类型,在附录数据区的第1-100KB;“品牌”是文本类型,在101-150KB。
    • .dvd 文件:是这张表格的“主体数据区”,包含了所有商品的真实价格、品牌序数、日期等,并且这些数据被压得很紧实。

当你需要按价格排序时,Lucene 不会去翻阅整本书,而是直接拿出这张表格,只看“价格”那一列,然后快速地对所有商品进行排序。


六、场景设定

我们用一个具体的、简化的例子来展示 dvmdvd 文件的存储格式。这会是一个概念上的表示,而非真实的二进制字节流,但它能清晰地揭示其内部工作原理。

假设我们有一个 Lucene 索引,其中包含 4 个文档(Doc ID 从 0 到 3)。我们关注三个具有 DocValues 的字段:

  1. price (价格): 类型为 NUMERIC
  2. category (分类): 类型为 SORTED (单值文本,用于排序和分面)
  3. tags (标签): 类型为 SORTED_SET (多值文本,用于分面)

原始数据如下:

Doc IDprice (NUMERIC)category (SORTED)tags (SORTED_SET)
0100“Book”[“new”, “bestseller”]
1200“Electronics”[“sale”]
2100“Book”(无标签)
3500“Book”[“new”, “hardcover”]

现在,我们来看看 Lucene 8.7.0 会如何将这些数据存入 .dvm.dvd 文件中。


.dvm 文件内容 (元数据)

这个文件非常小,就像一个目录。它的内容在概念上可以看作:

// --- .dvm File (Conceptual Representation) ---
[Header: Lucene87Codec, version=8.7.0, ...]
[Number of DocValues Fields: 3]
// --- Entry 1 ---
[Field Name: "price"]
[Field Type: NUMERIC]
[Data Offset in .dvd: 0]
[Data Length in .dvd: L1]  // 假设 price 数据块占 L1 字节
// --- Entry 2 ---
[Field Name: "category"]
[Field Type: SORTED]
[Data Offset in .dvd: L1] // 紧跟在 price 数据之后
[Data Length in .dvd: L2]
// --- Entry 3 ---
[Field Name: "tags"]
[Field Type: SORTED_SET]
[Data Offset in .dvd: L1 + L2] // 紧跟在 category 数据之后
[Data Length in .dvd: L3]
[Footer: Checksum, etc.]

解读:
当 Lucene 需要 category 字段的 DocValues 时,它会:

  1. 读取 .dvm 文件。
  2. 找到名为 “category” 的条目。
  3. 得知其类型是 SORTED,数据位于 .dvd 文件中从字节 L1 开始,长度为 L2 的区域。
  4. 然后,它会带着这些信息去 .dvd 文件中读取和解码数据。

.dvd 文件内容 (实际数据)

这个文件是一个连续的二进制数据块,由三个部分拼接而成,每个部分对应一个字段。

// --- .dvd File (Conceptual Representation) ---
// =========================================================================
// == BLOCK 1: 'price' Data (Offset: 0, Length: L1)
// == Type: NUMERIC
// =========================================================================
// Lucene发现所有值 (100, 200, 100, 500) 的最大公约数(GCD)是100。
// 于是采用GCD压缩。
[Metadata for price block: {type: GCD_COMPRESSED, gcd_value: 100}]
// 存储每个原始值除以100后的商。原始值: [100, 200, 100, 500] -> 商: [1, 2, 1, 5]
// 这些小整数可以用 Packed Integers 高效存储。
[Packed Integers Block for quotients: 1, 2, 1, 5]
// =========================================================================
// == BLOCK 2: 'category' Data (Offset: L1, Length: L2)
// == Type: SORTED
// =========================================================================
// Lucene发现该字段只有两个唯一值:"Book" 和 "Electronics"。
// 于是采用字典编码。
// 1. 字典 (Dictionary) 部分: 存储唯一的、排好序的值。
//    序数(ordinal) 0 -> "Book"
//    序数(ordinal) 1 -> "Electronics"
[Dictionary Block: (length=4, "Book"), (length=11, "Electronics")]
// 2. 序数 (Ordinals) 部分: 为每个文档存储其值对应的序数。
//    Doc 0: "Book" -> 0
//    Doc 1: "Electronics" -> 1
//    Doc 2: "Book" -> 0
//    Doc 3: "Book" -> 0
//    序数列表为 [0, 1, 0, 0]。这些小整数用 Packed Integers 存储。
[Packed Integers Block for ordinals: 0, 1, 0, 0]
// =========================================================================
// == BLOCK 3: 'tags' Data (Offset: L1+L2, Length: L3)
// == Type: SORTED_SET
// =========================================================================
// 这比SORTED更复杂,因为它需要处理多值和空值。同样使用字典编码。
// 1. 字典 (Dictionary) 部分: 收集所有唯一的标签并排序。
//    "bestseller", "hardcover", "new", "sale"
//    序数 0 -> "bestseller"
//    序数 1 -> "hardcover"
//    序数 2 -> "new"
//    序数 3 -> "sale"
[Dictionary Block: (len, "bestseller"), (len, "hardcover"), (len, "new"), (len, "sale")]
// 2. 序数列表 (Ordinals List) 部分: 将所有文档的所有标签的序数连接成一个长列表。
//    Doc 0: ["new", "bestseller"] -> [2, 0]
//    Doc 1: ["sale"] -> [3]
//    Doc 2: (无) -> []
//    Doc 3: ["new", "hardcover"] -> [2, 1]
//    连接后的完整序数列表: [2, 0, 3, 2, 1]
[Packed Integers Block for all ordinals: 2, 0, 3, 2, 1]
// 3. 文档到序数的查找表 (Doc-to-Ordinals Lookup) 部分:
//    这是关键!它告诉我们每个文档的序数在上面那个长列表中的起止位置。
//    它是一个包含 (文档数+1) 个指针的列表。
//    - Doc 0 的序数从索引 0 开始。
//    - Doc 1 的序数从索引 2 开始 (因为Doc 0有两个标签)。
//    - Doc 2 的序数从索引 3 开始 (因为Doc 1有一个标签)。
//    - Doc 3 的序数从索引 3 开始 (因为Doc 2没有标签)。
//    - 列表的结尾在索引 5 (因为Doc 3有两个标签,3+2=5)。
//    这个查找表就是: [0, 2, 3, 3, 5]
[Packed Integers Block for lookup table: 0, 2, 3, 3, 5]
工作流程回顾

让我们看看如何获取 Doc 3tags

  1. Lucene 查找 .dvm,定位到 tags 字段在 .dvd 中的数据块。
  2. 进入 tags 数据块,首先找到文档到序数的查找表
  3. 要找 Doc 3,就查看查找表的第 3 和第 4 个元素,得到 35
  4. 这表示 Doc 3 的序数位于序数列表的索引 35 (不含5) 之间,即索引为 34 的位置。
  5. 序数列表中取出索引 34 的值,得到 [2, 1]
  6. 拿着序数 21,去 tags 数据块的字典中查找。
  7. 序数 2 对应 “new”,序数 1 对应 “hardcover”。
  8. 最终得到结果:["new", "hardcover"]

这个例子清晰地展示了 dvmdvd 文件如何协同工作,以及 Lucene 如何利用 GCD 压缩、字典编码、Packed Integers 和查找表等多种技术,以极高的效率存储和检索 DocValues 数据。


总结

在 Lucene 8.7.0 中,.dvm.dvd 文件是实现高效排序、聚合和字段值访问的关键。它们通过列式存储和多种智能压缩算法,以极高的空间和时间效率存储了字段的正向索引数据,是 Lucene 高性能特性的重要基石,也是 Elasticsearch 和 Solr 等搜索引擎能够实现快速聚合分析功能的核心技术所在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/921561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

APEX实战第5篇:利用APEX程序直观体验向量近似检索能力

APEX实战第5篇:利用APEX程序直观体验向量近似检索能力2025-09-29 08:14 AlfredZhao 阅读(0) 评论(0) 收藏 举报在圈内朋友看来,Oracle 数据库的 多模能力 已经不是什么新鲜话题。它不仅在关系型数据管理方面独树…

告别复制粘贴!Chat2File-DeepSeek 让 DeepSeek 对话成果直接变“成品” - 指南

告别复制粘贴!Chat2File-DeepSeek 让 DeepSeek 对话成果直接变“成品” - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-f…

详解 PHP 中的命名空间 Namespace 与 PSR4 自动加载

详解 PHP 中的命名空间 Namespace 与 PSR4 自动加载 随着 PHP 项目规模增长,文件管理和类加载问题逐渐凸显:散乱的目录结构、频繁的 require_once 调用、难以维护的类依赖关系。本文通过 namespace 和自动加载技术,…

html5购物网站模板艾佳工业设计

动态调用的作用 类似于其他语言的反射能够开发框架性代码 Call调用语法 (bool success, bytes data) <address>.call(bytes calldata)call是address的方法call返回值(bool success, bytes data)忽视返回值success&#xff0c;会造成严重问题 calldata的结构 call的…

构建易受攻击的AWS DevOps环境:CloudGoat场景实践

本文详细介绍如何在CloudGoat中构建易受攻击的AWS DevOps环境,包含完整的攻击路径分析,从初始权限提升到供应链安全漏洞利用,展示了真实的云安全测试场景。构建易受攻击的AWS DevOps环境作为CloudGoat场景 CloudGoa…

摩尔线程88天过会,过会当天提交注册:看懂这3个关键,才算懂国产GPU的“生存逻辑”

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087摩尔线程88天冲刺上市:看懂这3个关键,才算懂国产GPU的“生存逻辑…

2025最新四面刨厂家权威推荐排行榜:四面刨厂家实力品牌测评,含定制,高速,重型四面刨优选指南

四面刨作为竹木加工的核心设备,其精度与稳定性直接决定产品合格率与生产效率。当前市场中,既有深耕多年的老牌企业,也涌现出一批技术创新的新锐品牌,但同时存在设备精度参差、定制能力不足、售后响应滞后等问题 —…

Java之泛型使用教程

下面我将为你编写一个使用泛型类的示例代码,这个示例实现了一个通用的"配对"(Pair)类,可以存储两个相同或不同类型的值,并提供基本的操作方法。 这个示例展示了泛型类的几个重要特性:多类型参数:Pair…

单调栈优化DP [ROI 2018] Decryption

题意 要求把一个序列划分成很多段,要求对于每段,最大值是末项,最小值是首项。 求最小划分段数。 解法 我们贪心来思考,若我们要保证一直到 i 是合法的,左端点显然是越往左越好,但是在全局上是并没有这个性质的,…

上海住宅新规调整,背后的野心可大了

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087各位,看到这份文本了吗 添加图片注释,不超过 140 字(可选)没看…

手工调整pip whl 文件内容

手工调整pip whl 文件内容属于一个比较常见的问题,比如我们希望自己修改一个whl 文件的内容,但是还是通过pip install 的模式,不希望通过pip 安装之后再手工进行文件替换,解决方法比较简单 有源码的 可以自己重新构…

魔兽争霸3冰封王座安装包下载

​在即时战略游戏的发展史上,有一款作品如同丰碑般屹立不倒,它就是2003年发布的《魔兽争霸3:冰封王座》。即便时光流转二十余载,这款游戏依旧凭借其深厚的玩法底蕴与强大的玩家粘性,活跃在游戏圈中,成为无数玩家…

重庆 机械有限公司 沙坪坝网站建设wordpress设置恢复

本文主要用于工作记录&#xff0c;在项目中遇到了就记录一下 在早期&#xff0c;原生的JDK8是不支持HTTP/2协议的&#xff0c;所以&#xff0c;要想使用这个特性&#xff0c;需要有web服务器和应用环境的支持&#xff0c; 例如&#xff1a;在VM中增加-Xbootclasspath/p:/Users…

广州网站设计总部自己做的网站给人攻击了怎么办

Eclipse 创建第一个 springboot 应用 1、前言 一直想把笔记整理出来&#xff0c;分享一下 springboot 的搭建&#xff1b; 因为私下 idea 用的比较多&#xff0c;使用比较方便&#xff0c;但恰逢小伙伴问起 eclipse 怎么搭建的问题&#xff0c; 顾整理以记之。 2、springboot …

vscode tunnel远程隧道访问 正确重启方法

因为有时候电脑休眠一下,远程隧道就挂了,重启vscode也没用,下面是摸索出来的方法: 在linux上:关闭vscode 结束后台code-tunnel进程 启动vscode 在远程资源管理器中,注销2个Tunnels 点击设置按钮旁边的账户,重启…

深圳住房和建设局网站网上预约网站图片上的分享怎么做的

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; 是瑶瑶子啦每日一言&#x1f33c;: 所谓自由&#xff0c;不是随心所欲&#xff0c;而是自我主宰。——康德 目录 一、二叉树刷题纲领二、刷题1、104. 二叉树的最大深度2、 二叉…

企业网站建设的成本背景素材

随着AI预训练大模型的价值不断显现&#xff0c;且模型规模愈发庞大。产学各界已经形成了这样一个共识&#xff1a;AI时代&#xff0c;算力就是生产力。 这一认知虽然正确&#xff0c;却并不全面。数字化系统有存、算、网三大支柱&#xff0c;AI技术也是如此。如果抛开存储和网络…

杭州百度推广网站建设北京网站建设好

一、软件设计发展过程二、什么是DDD&#xff1f;2.1 战略设计2.2 战术设计2.3 名词扫盲1. 领域和子域2. 核心域、通用域和支撑域3. 通用语言4. 限界上下文5. 实体和值对象6. 聚合和聚合根 2.4 事件风暴2.5 领域事件 三、DDD与微服务3.1 DDD与微服务的关系3.2 基于DDD进行微服务…

PS时文本框图层如何与图片图层水平中心对齐

背景: 工作遇到临时要处理一个图片1,需要在图片1中加一个文本,要求与图片的水平中心对齐。 工具:PS2021 ==================================================================== 1.打开图片1 2.点击文字工具添加水…

基于推荐算法的网站开发广东工程造价信息网

简介&#xff1a; 伴随着 5G、IoT 等技术的快速发展&#xff0c;边缘计算被越来越广泛地应用于电信、媒体、运输、物流、农业、零售等行业和场景中&#xff0c;成为解决这些领域数据传输效率的关键方式。与此同时&#xff0c;边缘计算形态、规模、复杂度的日益增长&#xff0c;…