杰瑞科技汇

Java中Document类如何使用?

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

Java中Document类如何使用?-图1
(图片来源网络,侵删)

要使用 Document,你通常需要引入 Lucene 的依赖。


Document 是什么?它的核心作用是什么?

想象一下传统的关系型数据库,它由 组成,每一行代表一条记录,每一列代表一个字段。

在 Apache Lucene 中,Document 对象就扮演着 “数据库中的一行记录” 的角色。

一个 Document 对象是一个由多个 Field(字段)组成的集合,每个 Field 代表一个数据项,类似于数据库中的一列,你可以将一个 Document 理解为一个灵活的、无模式的文档容器,用于存储你需要被索引和搜索的数据。

Java中Document类如何使用?-图2
(图片来源网络,侵删)

核心作用: Document 是 Lucene 索引和搜索系统的基本数据单元,你首先将你的数据(比如一篇文章、一个产品信息、一个用户评论)封装成一个或多个 Document 对象,然后将这些 Document 添加到 Lucene 的 IndexWriter 中进行索引,当用户进行搜索时,Lucene 会在索引中查找匹配的 Document,然后将它们返回给你。


Document 的核心组成部分:Field

一个 Document 就是由多个 Field 组成的,理解 Field 是理解 Document 的关键。

Field 对象代表文档中的一个字段,它由两部分组成:

  1. 字段名:一个字符串,用于标识这个字段是什么("title", "content", "author")。
  2. 字段值:字段的实际内容,可以是字符串、数字、日期等,Lucene 提供了不同的类型来存储这些值。

Field 的关键特性:FieldType

Lucene 中的 Field 非常灵活,其行为由 FieldType 决定。FieldType 定义了字段如何被索引和存储,这对于搜索性能和功能至关重要。

Java中Document类如何使用?-图3
(图片来源网络,侵删)

FieldType 主要有三个核心选项,可以通过布尔值组合来设置:

  1. 是否存储

    • stored=true: 字段的原始值会被完整地保存在索引中,这意味着搜索后,你可以直接从 Document 中取出这个字段的原始值。
    • stored=false: 字段的原始值不会被保存,它只用于构建索引,用于匹配搜索条件。
    • 用途:对于像标题、URL、ID 这样的字段,通常需要 stored=true,因为搜索后你需要显示它们,对于像正文内容这样的大段文本,如果只是为了搜索匹配,可以设为 stored=false 以节省存储空间。
  2. 是否索引

    • indexed=true: 字段的值会被分词,并构建成倒排索引,这是进行全文搜索的基础。
    • indexed=false: 字段的值不会被索引,因此无法用于搜索。
    • 用途、内容等需要被搜索的字段,必须设为 indexed=true,对于像文件大小、创建日期这样的元数据,如果你不需要按它们来搜索,可以设为 indexed=false
  3. 是否分词

    • 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 工作流的起点和核心数据载体。

  1. 数据准备:你从数据库、文件或其他来源获取原始数据。
  2. 创建 Document:将原始数据解析并封装成一个或多个 Document 对象,并为每个字段选择合适的 Field 类型。
  3. 索引:使用 IndexWriterDocument 写入索引。IndexWriter 会读取 Document 中的 Field,根据其 FieldType 进行分词、索引和存储。
  4. 搜索:用户输入查询语句。IndexSearcher 在索引中查找匹配的文档,并返回一个 TopDocs 对象,其中包含了匹配文档的 ID(ScoreDoc)。
  5. 获取结果:使用 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 LuceneDocument,理解其与 FieldFieldType 的关系,是掌握 Lucene 的第一步。

分享:
扫描分享到社交APP
上一篇
下一篇