从 PDF 中提取文本以进行 Lucene 索引的有效方法
Efficient way to extract text from PDF for Lucene indexing
我正在尝试使用 Apache Tika 从 PDF 文件中提取文本内容,然后将数据传递给 Lucene 进行索引。
public static String extract(File file) throws IOException, SAXException, TikaException {
InputStream input = new FileInputStream(file);
ContentHandler handler = new BodyContentHandler(-1);
Metadata metadata = new Metadata();
new PDFParser().parse(input, handler, metadata, new ParseContext());
String plainText = handler.toString();
input.close();
return plainText;
}
我的查询与通话有关
handler.toString();
现在我们正在使用多个线程(4 到 8 个,可由用户配置)执行提取过程。那么有没有其他方法可以获取我们可以提供给 Lucene 用于索引目的的流。原因是我觉得巨大的字符串会推动更大的堆。
当前索引如果完成为:
doc.add(new TextField(fieldName, ExtractPdf.extract(file), Field.Store.NO));
我们需要提取和索引大约 500K 个大小从 50KB 到 50MB 不等的文档。
我以前没有在 Apache Tika 上工作过,但你的问题很有趣,所以我环顾四周,我没有看到对 toString()
的调用是问题的根本原因。
据我了解 - 可以通过决定是否始终需要 FULL BODY TEXT 来提高效率,而不管文本的大小如何 OR 如果您只检索 N-LENGTH 的部分主体,您的程序逻辑可以正常工作。
我非常确定您将始终需要完整的正文,而您的程序将无法使用部分正文,因此您可以实现的所有效率(假设您始终需要全文)就是分解大将字符串分成块,如部分 here 所示 - 使用自定义内容处理程序装饰器以块 流式传输纯文本。所以在内存方面,你的程序应该仍然能够存储这么大的主体,但是你的主体被分成了块,这可能会简化你的下游索引过程。
您的程序应根据支持的最大文件大小列出其内存要求,使用这种方法您不会在此处得到任何缓解。因此,很早就决定要处理多大的文件。
其他选项似乎开发了一个过程,您可以在其中以增量方式多次解析同一文件,而且效率也不是很高(只是建议作为一种可能的方法,不确定在 Tika 中是否可行)。
啊....写的很长:)
说到以上几点,您还应该注意,您应该尝试将文件解析和索引步骤分离,以便您可以为每个步骤提供不同的调优和配置。
您可以使用线程安全阻塞队列编写典型的生产者-消费者模式,或者您可以使用 Spring Batch API。
使用 Spring 批处理,您的 reader 将负责读取和解析文件,reader 将传递 字符串列表 到处理器,然后 字符串列表列表 将转到编写器,编写器将根据您的块大小配置简单地批量索引几个文件。
解耦在这里是强制性的,因为你应该注意到 Lucene IndexWriter
是线程安全的 class 除了在文件解析级别使用多线程之外,你还可以使用多个线程来进行更快的索引.
希望对您有所帮助!!
此外,请注意,Java 中的字符串如果未被留存,就会像任何普通对象一样被垃圾回收,see
我正在尝试使用 Apache Tika 从 PDF 文件中提取文本内容,然后将数据传递给 Lucene 进行索引。
public static String extract(File file) throws IOException, SAXException, TikaException {
InputStream input = new FileInputStream(file);
ContentHandler handler = new BodyContentHandler(-1);
Metadata metadata = new Metadata();
new PDFParser().parse(input, handler, metadata, new ParseContext());
String plainText = handler.toString();
input.close();
return plainText;
}
我的查询与通话有关
handler.toString();
现在我们正在使用多个线程(4 到 8 个,可由用户配置)执行提取过程。那么有没有其他方法可以获取我们可以提供给 Lucene 用于索引目的的流。原因是我觉得巨大的字符串会推动更大的堆。
当前索引如果完成为:
doc.add(new TextField(fieldName, ExtractPdf.extract(file), Field.Store.NO));
我们需要提取和索引大约 500K 个大小从 50KB 到 50MB 不等的文档。
我以前没有在 Apache Tika 上工作过,但你的问题很有趣,所以我环顾四周,我没有看到对 toString()
的调用是问题的根本原因。
据我了解 - 可以通过决定是否始终需要 FULL BODY TEXT 来提高效率,而不管文本的大小如何 OR 如果您只检索 N-LENGTH 的部分主体,您的程序逻辑可以正常工作。
我非常确定您将始终需要完整的正文,而您的程序将无法使用部分正文,因此您可以实现的所有效率(假设您始终需要全文)就是分解大将字符串分成块,如部分 here 所示 - 使用自定义内容处理程序装饰器以块 流式传输纯文本。所以在内存方面,你的程序应该仍然能够存储这么大的主体,但是你的主体被分成了块,这可能会简化你的下游索引过程。
您的程序应根据支持的最大文件大小列出其内存要求,使用这种方法您不会在此处得到任何缓解。因此,很早就决定要处理多大的文件。
其他选项似乎开发了一个过程,您可以在其中以增量方式多次解析同一文件,而且效率也不是很高(只是建议作为一种可能的方法,不确定在 Tika 中是否可行)。
啊....写的很长:)
说到以上几点,您还应该注意,您应该尝试将文件解析和索引步骤分离,以便您可以为每个步骤提供不同的调优和配置。
您可以使用线程安全阻塞队列编写典型的生产者-消费者模式,或者您可以使用 Spring Batch API。
使用 Spring 批处理,您的 reader 将负责读取和解析文件,reader 将传递 字符串列表 到处理器,然后 字符串列表列表 将转到编写器,编写器将根据您的块大小配置简单地批量索引几个文件。
解耦在这里是强制性的,因为你应该注意到 Lucene IndexWriter
是线程安全的 class 除了在文件解析级别使用多线程之外,你还可以使用多个线程来进行更快的索引.
希望对您有所帮助!!
此外,请注意,Java 中的字符串如果未被留存,就会像任何普通对象一样被垃圾回收,see