Featured image of post Apache Tika使用指南

Apache Tika使用指南

什么是 Apache Tika?

Apache Tika 是一个内容分析工具包,用于从各种格式的文档中检测和提取元数据及文本内容。Tika 支持检测和解析超过 1000 种文件类型,包括:

  • 文档格式:PDF、Microsoft Office、OpenDocument、RTF、HTML 等
  • 图片格式:JPEG、PNG、TIFF 等(可提取 EXIF 元数据)
  • 邮件格式:MIME 消息
  • 归档格式:ZIP、TAR、GZIP 等
  • 音频/视频:MP3、MP4、AVI 等的元数据
  • 其他:XML、JSON、CSV 等结构化格式

项目集成

Maven 依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<properties>
    <tika.version>3.2.2</tika.version>
</properties>

<dependencies>
    <!-- 核心库 -->
    <dependency>
        <groupId>org.apache.tika</groupId>
        <artifactId>tika-core</artifactId>
        <version>${tika.version}</version>
    </dependency>

    <!-- 解析器包(包含所有主流文档格式的解析器) -->
    <dependency>
        <groupId>org.apache.tika</groupId>
        <artifactId>tika-parsers-standard-package</artifactId>
        <version>${tika.version}</version>
    </dependency>
</dependencies>

注意:tika-parsers-standard-package 会包含所有解析器,如果需要更小的包体积,可以只引入特定解析器。

基础使用

1. 简单文本提取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import org.apache.tika.Tika;
import org.springframework.web.multipart.MultipartFile;

@Service
public class DocumentService {

    private final Tika tika = new Tika();

    public String extractText(MultipartFile file) throws Exception {
        try (InputStream inputStream = file.getInputStream()) {
            return tika.parseToString(inputStream);
        }
    }
}

2. 自动检测文件类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import org.apache.tika.Tika;
import org.apache.tika.mime.MimeType;
import org.apache.tika.mime.MimeTypeException;

@Service
public class ContentTypeDetectionService {

    private final Tika tika = new Tika();

    public String detectContentType(MultipartFile file) {
        try (InputStream inputStream = file.getInputStream()) {
            // 根据文件内容检测类型
            return tika.detect(inputStream, file.getOriginalFilename());
        } catch (Exception e) {
            // 检测失败时回退到 HTTP Content-Type
            return file.getContentType();
        }
    }
}

进阶使用

使用 Parser API 进行精细控制

在项目实践中,我们使用 AutoDetectParserParseContext 进行更精细的控制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.exception.TikaException;
import org.apache.tika.extractor.EmbeddedDocumentExtractor;
import org.apache.tika.parser.pdf.PDFParserConfig;
import org.springframework.web.multipart.MultipartFile;

@Service
public class DocumentParseService {

    private static final int MAX_TEXT_LENGTH = 5 * 1024 * 1024; // 5MB

    public String parseContent(MultipartFile file) throws Exception {
        try (InputStream inputStream = file.getInputStream()) {
            return parseContent(inputStream);
        }
    }

    private String parseContent(InputStream inputStream)
            throws TikaException, IOException, SAXException {

        // 1. 创建自动检测解析器
        AutoDetectParser parser = new AutoDetectParser();

        // 2. 创建内容处理器,限制最大文本长度
        BodyContentHandler handler = new BodyContentHandler(MAX_TEXT_LENGTH);

        // 3. 创建元数据对象
        Metadata metadata = new Metadata();

        // 4. 创建解析上下文
        ParseContext context = new ParseContext();

        // 5. 显式指定 Parser 到 Context(增强健壮性)
        context.set(Parser.class, parser);

        // 6. 禁用嵌入文档解析(避免提取图片引用和临时文件路径)
        context.set(EmbeddedDocumentExtractor.class,
                    new NoOpEmbeddedDocumentExtractor());

        // 7. PDF 专用配置:关闭图片提取,按位置排序文本
        PDFParserConfig pdfConfig = new PDFParserConfig();
        pdfConfig.setExtractInlineImages(false);
        pdfConfig.setSortByPosition(true);
        context.set(PDFParserConfig.class, pdfConfig);

        // 8. 执行解析
        parser.parse(inputStream, handler, metadata, context);

        return handler.toString();
    }
}

禁用嵌入资源解析

在解析 PDF 等文档时,Tika 默认会尝试提取嵌入的图片和附件,这可能导致提取到无用的临时文件路径:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import org.apache.tika.extractor.EmbeddedDocumentExtractor;

// 自定义空提取器,不处理嵌入资源
public class NoOpEmbeddedDocumentExtractor implements EmbeddedDocumentExtractor {

    @Override
    public boolean shouldParseEmbedded(Metadata metadata) {
        return false; // 不解析任何嵌入资源
    }

    @Override
    public void parseEmbedded(InputStream inputStream, ContentHandler contentHandler,
                             Metadata metadata, boolean outputHtml) throws IOException {
        // 空实现,不做任何提取
    }
}

提取元数据

获取文档元数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;

public void extractMetadata(InputStream inputStream) throws Exception {
    AutoDetectParser parser = new AutoDetectParser();
    BodyContentHandler handler = new BodyContentHandler();
    Metadata metadata = new Metadata();

    parser.parse(inputStream, handler, metadata);

    // 获取常用元数据
    System.out.println("标题: " + metadata.get(TikaCoreProperties.TITLE));
    System.out.println("作者: " + metadata.get(TikaCoreProperties.CREATOR));
    System.out.println("创建日期: " + metadata.get(TikaCoreProperties.CREATED));
    System.out.println("修改日期: " + metadata.get(TikaCoreProperties.MODIFIED));
    System.out.println("文件类型: " + metadata.get("Content-Type"));

    // 打印所有元数据
    for (String name : metadata.names()) {
        System.out.println(name + ": " + metadata.get(name));
    }
}

PDF 专用元数据

1
2
3
4
5
6
7
import org.apache.tika.metadata.PDF;

// PDF 特有元数据
System.out.println("PDF 标题: " + metadata.get(PDF.TITLE));
System.out.println("PDF 作者: " + metadata.get(PDF.AUTHOR));
System.out.println("PDF 创建者: " + metadata.get(PDF.CREATOR));
System.out.println("页数: " + metadata.getInt(PDF.NUMBER_OF_PAGES));

解析特定格式

解析 PDF

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.parser.pdf.PDFParserConfig;

PDFParser parser = new PDFParser();
PDFParserConfig config = new PDFParserConfig();
config.setExtractInlineImages(false);  // 不提取内联图片
config.setSortByPosition(true);       // 按位置排序文本(适合中文)
config.setSuppressDuplicateOverlappingText(true); // 抑制重复文本

ParseContext context = new ParseContext();
context.set(PDFParserConfig.class, config);

解析 Microsoft Office 文档

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import org.apache.tika.parser.microsoft.ooxml.OOXMLParser;
import org.apache.tika.parser.microsoft.ParserFactory;
import org.apache.tika.parser.microsoft.OfficeParserConfig;

// Word、Excel、PowerPoint 都使用 OOXMLParser
OOXMLParser parser = new OOXMLParser();
OfficeParserConfig config = new OfficeParserConfig();
config.setConcatenatePhrases(true); // 合并短语

ParseContext context = new ParseContext();
context.set(OfficeParserConfig.class, config);

解析 HTML

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import org.apache.tika.parser.html.HtmlParser;
import org.apache.tika.parser.html.HtmlParserConfig;

// 包含 Jsoup 解析器配置
HtmlParser parser = new HtmlParser();
HtmlParserConfig config = new HtmlParserConfig();
config.setJavascript(false);    // 不执行 JavaScript
config.setMaxTextLength(10000); // 最大文本长度

ParseContext context = new ParseContext();
context.set(HtmlParserConfig.class, config);

文本清洗处理

Tika 提取的文本通常需要进一步清洗才能用于后续处理(如 RAG、知识库等):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Service
public class TextCleaningService {

    // 图片文件名行:image123.png
    private static final Pattern IMAGE_FILENAME_LINE =
            Pattern.compile("(?m)^image\\d+\\.(png|jpe?g|gif|bmp|webp)\\s*$");

    // HTTP/HTTPS 图片链接
    private static final Pattern IMAGE_URL =
            Pattern.compile("https?://\\S+?\\.(png|jpe?g|gif|bmp|webp)(\\?\\S*)?",
                          Pattern.CASE_INSENSITIVE);

    // 文件协议 URL(Tika PDF 临时文件路径等)
    private static final Pattern FILE_URL =
            Pattern.compile("file:(//)?\\S+", Pattern.CASE_INSENSITIVE);

    // 分隔线
    private static final Pattern SEPARATOR_LINE =
            Pattern.compile("(?m)^\\s*[-_*=]{3,}\\s*$");

    // 控制字符
    private static final Pattern CONTROL_CHARS =
            Pattern.compile("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F]");

    public String cleanText(String text) {
        if (text == null || text.isBlank()) {
            return "";
        }

        String t = text;

        // 语义去噪
        t = CONTROL_CHARS.matcher(t).replaceAll("");
        t = IMAGE_FILENAME_LINE.matcher(t).replaceAll("");
        t = IMAGE_URL.matcher(t).replaceAll("");
        t = FILE_URL.matcher(t).replaceAll("");
        t = SEPARATOR_LINE.matcher(t).replaceAll("");

        // 格式规范化
        t = t.replace("\r\n", "\n").replace("\r", "\n");
        t = t.replaceAll("(?m)[ \t]+$", "");
        t = t.replaceAll("\\n{3,}", "\n\n");

        return t.strip();
    }
}

最佳实践

1. 使用流式处理大文件

1
2
3
4
5
// 使用 TikaInputStream 处理大文件
import org.apache.tika.io.TikaInputStream;

TikaInputStream tis = TikaInputStream.of(file.toPath());
parser.parse(tis, handler, metadata, context);

2. 设置合理的超时

1
2
3
4
import org.apache.tika.parser.ParseContext;

ParseContext context = new ParseContext();
context.set("parseMax.timeout", "300000"); // 5 分钟超时

3. 处理编码问题

1
2
3
4
5
6
// 对于纯文本文件,指定编码
Metadata metadata = new Metadata();
metadata.set(Metadata.CONTENT_TYPE, "text/plain; charset=UTF-8");

InputStreamReader reader = new InputStreamReader(
    file.getInputStream(), StandardCharsets.UTF_8);

4. 并行解析多个文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Async
public CompletableFuture<List<String>> parseDocuments(List<MultipartFile> files) {
    return CompletableFuture.supplyAsync(() ->
        files.parallelStream()
            .map(file -> {
                try {
                    return parseContent(file);
                } catch (Exception e) {
                    return "";
                }
            })
            .collect(Collectors.toList())
    );
}

支持的文件类型一览

类别 格式
文档 PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, ODF, RTF, TXT
网页 HTML, XHTML, XML
邮件 MIME, EML, PST, OST
图片 JPEG, PNG, GIF, TIFF, BMP, WebP
归档 ZIP, TAR, GZIP, BZIP2, 7Z
音频 MP3, WAV, FLAC, OGG
视频 MP4, AVI, MOV, WMV, FLV
设计 PSD, AI, Sketch

性能优化建议

  1. 使用 AutoDetectParser 自动检测:智能选择解析器
  2. 禁用不需要的解析器:减少启动时间和内存占用
  3. 设置 MAX_TEXT_LENGTH:防止无限提取
  4. 使用流式处理:避免一次性加载整个文件到内存
  5. 禁用嵌入资源提取:如不需要图片和附件

总结

Apache Tika 是 Java 项目中文档解析的首选工具,它提供了:

  • 统一的 API 来处理多种文档格式
  • 自动检测文件类型
  • 丰富的元数据提取能力
  • 可配置的解析行为
  • 良好的扩展性

通过本指南,你应该能够使用 Tika 构建文档解析服务,实现简历解析、知识库构建、文档检索等功能。

使用 Hugo 构建
主题 StackJimmy 设计

发布了 29 篇文章 | 共 67213 字