如何用Apache Tika 1.5解析大文本文件?

时间:2014-07-03 08:42:22

标签: java out-of-memory apache-tika

问题: 对于我的测试,我想从335 MB的文本文件中提取文本数据,该文件是wikipedia" pagecounts-20140701-060000.txt"与Apache Tika。

我的解决方案: 我尝试使用TikaInputStream,因为它提供缓冲,然后我尝试使用BufferedInputStream,但这并没有解决我的问题。以下是我的测试课程:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.SAXException;

public class Printer {
    public void readMyFile(String fname) throws IOException, SAXException,
            TikaException {
        System.out.println("Working...");

        File f = new File(fname);
        // InputStream stream = TikaInputStream.get(new File(fname));
        InputStream stream = new BufferedInputStream(new FileInputStream(fname));

        Metadata meta = new Metadata();
        ContentHandler content = new BodyContentHandler(Integer.MAX_VALUE);
        AutoDetectParser parser = new AutoDetectParser();

        String mime = new Tika().detect(f);
        meta.set(Metadata.CONTENT_TYPE, mime);

        System.out.println("trying to parse...");
        try {
            parser.parse(stream, content, meta, new ParseContext());
        } finally {
            stream.close();
        }
    }

    public static void main(String[] args) {
        Printer p = new Printer();
        try {
            p.readMyFile("test/pagecounts-20140701-060000.txt");
        } catch (IOException | SAXException | TikaException e) {
            e.printStackTrace();
        }
    }
}

问题: 在调用我parse的{​​{1}}方法时:

parser

我尝试将jre内存消耗增加到-Xms512M -Xmx1024M,这没有用,我也不想使用任何更大的值。

问题: 我的代码出了什么问题? 我应该如何修改我的类以使其从测试文件中提取文本>使用Apache Tika> 300 MB?

3 个答案:

答案 0 :(得分:1)

您可以像这样设置以避免大小限制: -

BodyContentHandler bodyHandler = new BodyContentHandler(-1);

答案 1 :(得分:1)

您可以使用增量解析

    Tika tika = new Tika();
    Reader fulltext = null; 
    String contentStr = null;
    try {                   
        fulltext = tika.parse(response.getEntityInputStream());
        contentStr = IOUtils.toString(fulltext);
    } finally {
        fulltext.close();               
    }

答案 2 :(得分:1)

将BodyContentHandler传递给Writer或OutputStream而不是int

正如Gagravarr所述,您使用的BodyContentHandler正在建立文件内容的内部字符串缓冲区。由于Tika试图一次将所有内容存储在内存中,因此这种方法将对大文件遇到OutOfMemoryError例外。

如果您的目标是将Tika分析结果写到另一个文件中以供以后处理,则可以使用BodyContentHandler(或Writer)构造OutputStream直接),而不是传递int

Path outputFile = Path.of("output.txt"); // Paths.get() if not using Java 11
PrintWriter printWriter = new PrintWriter(Files.newOutputStream(outputFile));
BodyContentHandler content = new BodyContentHandler(printWriter);

然后调用Tika解析:

Path inputFile = Path.of("input.txt");
TikaInputStream inputStream = TikaInputStream.get(inputFile);

AutoDetectParser parser = new AutoDetectParser();
Metadata meta = new Metadata();
ParseContext context = new ParseContext();

parser.parse(inputStream, content, meta, context);

这样做,Tika将在解析时自动将内容写入到outputFile中,而不是尝试将所有内容保留在内存中。 Using a PrintWriter will buffer the output,减少了对磁盘的写入次数。

请注意,Tika将不会自动为您关闭输入或输出流。