Document 并不属于 Java 的标准核心库(如 java.lang 或 java.util)。 它是一个外部库中的类,最常见、最核心的来源是 Apache Lucene。

要使用 Document,你通常需要引入 Lucene 的依赖。
Document 是什么?它的核心作用是什么?
想象一下传统的关系型数据库,它由 表、行 和 列 组成,每一行代表一条记录,每一列代表一个字段。
在 Apache Lucene 中,Document 对象就扮演着 “数据库中的一行记录” 的角色。
一个 Document 对象是一个由多个 Field(字段)组成的集合,每个 Field 代表一个数据项,类似于数据库中的一列,你可以将一个 Document 理解为一个灵活的、无模式的文档容器,用于存储你需要被索引和搜索的数据。

核心作用:
Document 是 Lucene 索引和搜索系统的基本数据单元,你首先将你的数据(比如一篇文章、一个产品信息、一个用户评论)封装成一个或多个 Document 对象,然后将这些 Document 添加到 Lucene 的 IndexWriter 中进行索引,当用户进行搜索时,Lucene 会在索引中查找匹配的 Document,然后将它们返回给你。
Document 的核心组成部分:Field
一个 Document 就是由多个 Field 组成的,理解 Field 是理解 Document 的关键。
Field 对象代表文档中的一个字段,它由两部分组成:
- 字段名:一个字符串,用于标识这个字段是什么("title", "content", "author")。
- 字段值:字段的实际内容,可以是字符串、数字、日期等,Lucene 提供了不同的类型来存储这些值。
Field 的关键特性:FieldType
Lucene 中的 Field 非常灵活,其行为由 FieldType 决定。FieldType 定义了字段如何被索引和存储,这对于搜索性能和功能至关重要。

FieldType 主要有三个核心选项,可以通过布尔值组合来设置:
-
是否存储
stored=true: 字段的原始值会被完整地保存在索引中,这意味着搜索后,你可以直接从Document中取出这个字段的原始值。stored=false: 字段的原始值不会被保存,它只用于构建索引,用于匹配搜索条件。- 用途:对于像标题、URL、ID 这样的字段,通常需要
stored=true,因为搜索后你需要显示它们,对于像正文内容这样的大段文本,如果只是为了搜索匹配,可以设为stored=false以节省存储空间。
-
是否索引
indexed=true: 字段的值会被分词,并构建成倒排索引,这是进行全文搜索的基础。indexed=false: 字段的值不会被索引,因此无法用于搜索。- 用途、内容等需要被搜索的字段,必须设为
indexed=true,对于像文件大小、创建日期这样的元数据,如果你不需要按它们来搜索,可以设为indexed=false。
-
是否分词
tokenized=true: 字段的值在索引前会被“分词”,字符串 "Hello world" 会被分成两个词项 "hello" 和 "world",这对于全文搜索至关重要。tokenized=false: 字段的值被视为一个整体,不会被拆分。- 用途、内容等文本,需要
tokenized=true,对于像 "ID"、"国家代码" 这样的整体性标识,需要tokenized=false。
Lucene 提供的常用 Field 类型(预定义的 FieldType)
为了方便使用,Lucene 提供了许多预定义好的 Field 子类,它们已经配置好了合适的 FieldType:
| Field 类型 | 存储索引配置 | 典型用途 |
|---|---|---|
TextField |
stored=false, indexed=true, tokenized=true |
文章正文、评论、描述等需要全文搜索的大段文本。 |
StringField |
stored=true, indexed=true, tokenized=false |
标题、国家、作者姓名、产品型号等不需要分词的文本。 |
IntPoint / LongPoint |
stored=false, indexed=true, tokenized=false |
数值范围查询(价格、年份、ID)。注意:它不存储原始值,需要配合 StoredField。 |
StoredField |
stored=true, indexed=false, tokenized=false |
仅用于存储,不用于搜索,常与 Point 类型配合使用,或存储文件大小等。 |
KeywordField |
stored=true, indexed=true, tokenized=false |
类似 StringField,但更强调其作为“关键词”的语义。 |
如何使用 Document(代码示例)
你需要添加 Lucene 的依赖,如果你使用 Maven,添加如下依赖:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>9.8.0</version> <!-- 使用最新稳定版本 -->
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>9.8.0</version>
</dependency>
示例:创建并填充一个 Document
假设我们要索引一篇博客文章。
import org.apache.lucene.document.Document;
import org.apache.document.Field;
import org.apache.document.TextField;
import org.apache.document.StringField;
import org.apache.document.StoredField;
import org.apache.document.IntPoint;
public class LuceneDocumentExample {
public static void main(String[] args) {
// 1. 创建一个新的 Document 对象
Document doc = new Document();
// 2. 添加不同的 Field
// 文章ID:需要存储,也需要作为精确搜索条件,但不分词
doc.add(new StringField("id", "doc-001", Field.Store.YES));
// 文章标题:需要存储,也需要作为搜索条件,并且需要分词
doc.add(new TextField("title", "Getting Started with Apache Lucene", Field.Store.YES));
// 文章内容:需要全文搜索(索引+分词),但内容可能很大,可以不存储
// 注意:如果搜索后需要显示内容,则应该存储
String content = "Apache Lucene is a high-performance, full-text search engine library...";
doc.add(new TextField("content", content, Field.Store.YES));
// 发布年份:需要用于范围查询,但不存储
doc.add(IntPoint.newRange("year", 2025, 2025));
// 文章标签:需要存储和搜索,但不分词
doc.add(new StringField("tags", "lucene,search,java", Field.Store.YES));
// 3. (在实际应用中) 将这个 Document 添加到 IndexWriter 中进行索引
// IndexWriter writer = ...;
// writer.addDocument(doc);
// writer.commit();
// 4. 验证 Document 内容
System.out.println("Document created successfully!");
System.out.println("Number of fields in the document: " + doc.getFields().size());
System.out.println("Title: " + doc.get("title")); // get() 方法获取 stored 字段的值
System.out.println("ID: " + doc.get("id"));
}
}
Document 在 Lucene 生命周期中的位置
Document 是整个 Lucene 工作流的起点和核心数据载体。
- 数据准备:你从数据库、文件或其他来源获取原始数据。
- 创建
Document:将原始数据解析并封装成一个或多个Document对象,并为每个字段选择合适的Field类型。 - 索引:使用
IndexWriter将Document写入索引。IndexWriter会读取Document中的Field,根据其FieldType进行分词、索引和存储。 - 搜索:用户输入查询语句。
IndexSearcher在索引中查找匹配的文档,并返回一个TopDocs对象,其中包含了匹配文档的 ID(ScoreDoc)。 - 获取结果:使用
IndexSearcher.doc(docId)方法,通过 ID 从索引中重新获取完整的Document对象,这时你就可以从Document中取出stored的字段(如标题、URL)来展示给用户。
其他库中的 Document
虽然 Lucene 的 Document 最著名,但在其他领域也有同名或概念相似的类:
- DOM (Document Object Model): 在 Java 的 XML 处理中,
org.w3c.dom.Document接口及其实现(如org.apache.xerces.dom.DeocumentImpl)代表了一个 XML 文件的内存树形结构,它与 Lucene 的Document完全不同,后者是用于搜索的扁平化数据结构。 - Apache POI: 在处理 Microsoft Office 文档(如 Word
.docx)时,org.apache.poi.xwpf.usermodel.XWPFDocument类代表一个 Word 文档对象,它也与 Lucene 的Document无关。
当你在 Java 上下文中看到 Document 类,并且与 搜索、索引、全文检索 相关时,几乎可以肯定它指的是 Apache Lucene 的 Document,理解其与 Field 和 FieldType 的关系,是掌握 Lucene 的第一步。
