我正在尝试解析mbox格式的电子邮件。但是,Tika一直试图在这些消息上使用TNEFParser导致错误:
2012-08-21 17:44:42,139 FATAL org.apache.hadoop.mapred.Child: Error running child : java.lang.OutOfMemoryError: Java heap space
at org.apache.poi.hmef.attribute.TNEFAttribute.<init>(TNEFAttribute.java:50)
at org.apache.poi.hmef.attribute.TNEFAttribute.create(TNEFAttribute.java:76)
at org.apache.poi.hmef.HMEFMessage.process(HMEFMessage.java:74)
at org.apache.poi.hmef.HMEFMessage.process(HMEFMessage.java:98)
at org.apache.poi.hmef.HMEFMessage.process(HMEFMessage.java:98)
at org.apache.poi.hmef.HMEFMessage.<init>(HMEFMessage.java:63)
at org.apache.tika.parser.microsoft.TNEFParser.parse(TNEFParser.java:80)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:242)
at org.apache.tika.parser.mail.MailContentHandler.body(MailContentHandler.java:102)
at org.apache.james.mime4j.parser.MimeStreamParser.parse(MimeStreamParser.java:133)
at org.apache.tika.parser.mail.RFC822Parser.parse(RFC822Parser.java:76)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:242)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:242)
at org.apache.tika.parser.AutoDetectParser.parse(AutoDetectParser.java:120)
at org.lab41.asf.etl.mapred.MailboxToTextMapper.parse(MailboxToTextMapper.java:124)
at org.lab41.asf.etl.mapred.MailboxToTextMapper.map(MailboxToTextMapper.java:88)
at org.lab41.asf.etl.mapred.MailboxToTextMapper.map(MailboxToTextMapper.java:45)
at org.apache.avro.mapred.HadoopMapper.map(HadoopMapper.java:81)
at org.apache.avro.mapred.HadoopMapper.map(HadoopMapper.java:34)
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:50)
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:391)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:325)
at org.apache.hadoop.mapred.Child$4.run(Child.java:266)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1278)
at org.apache.hadoop.mapred.Child.main(Child.java:260)
是否有可能阻止Tika使用TNEFParser?任何的意见都将会有帮助。
答案 0 :(得分:3)
以下是@Gagravarr建议的配置版本。
首先,创建一个tika-config.xml文件:
<properties>
<parsers>
<!-- use the default parser in most cases, it is a composite of all
the parsers listed in META-INF/services/org.apache.tika.parser.Parser -->
<parser class="org.apache.tika.parser.DefaultParser"/>
<!-- Disable tnef extraction-->
<parser class="org.apache.tika.parser.EmptyParser">
<mime>application/vnd.ms-tnef</mime>
<mime>application/x-tnef</mime>
</parser>
</parsers>
</properties>
现在,从这个配置创建一个TikaConfig(假设它在你的类路径的某个地方):
ClassLoader loader = Thread.currentThread().getContextClassLoader();
TikaConfig config = new TikaConfig(loader.getResource("tika-config.xml"), loader);
当您创建新的Parser或使用Tika外观时,请传递您的配置:
AutoDetectParser parser = new AutoDetectParser(config);
ParseContext context = new ParseContext();
context.set(Parser.class, parser);
parser.parse(input, handler, metadata, context);
任何标识为TNEF的文档都将使用EmptyParser,它不返回任何内容,也不会实际解析任何内容。
这实际上是一个黑名单,如果你想要一个白名单,你需要从XML中删除DefaultParser并手动配置每个解析器及其元数据。
答案 1 :(得分:2)
对于长期修复,您应该将此报告为Apache Tika中的错误,将有问题的文件附加到错误报告中,并使用该项目来修复错误。
短期内,解压缩Tika-Parsers jar文件,编辑META-INF/services/org.apache.tika.parser.Parser
文件并从列表中删除TNEF解析器。这将阻止它被AutoDetectParser自动加载和使用
如果不更改Tika Parsers jar文件,那就有点棘手了。有两种选择。一种是自己创建一个TikaConfig实例,而不是依赖于默认实例,并且只提供有限的解析器列表。根据您是否要列入白名单或黑名单,这可能很容易或更困难。或者,您可以使用mimetype的最后一个注册解析器获胜的事实。因此,使用服务文件和您自己的虚拟解析器创建自己的jar。让解析器声明它处理TNEF mimetype,但它没有做任何事情。将jar添加到类路径中,然后将使用虚拟解析器
答案 2 :(得分:2)
以下是 @Gagravarr 建议的程序版本。它用EmptyParser
替换已注册的不必要的解析器。
private Tika createTika(final Parser... unnecessaryParsers)
throws TikaException, IOException {
final TikaConfig config = new TikaConfig();
final AutoDetectParser autoDetectParser = new AutoDetectParser(config);
final Set<MediaType> unnecessaryMimeTypes =
getUnnecessaryMediaTypes(unnecessaryParsers);
disableParsing(autoDetectParser, unnecessaryMimeTypes);
final Detector detector = config.getDetector();
final Tika tika = new Tika(detector, autoDetectParser);
return tika;
}
private Set<MediaType> getUnnecessaryMediaTypes(
final Parser... unnecessaryParsers) {
final Set<MediaType> unnecessaryTypes = new HashSet<MediaType>();
for (final Parser unnecessaryParser: unnecessaryParsers) {
final Set<MediaType> supportedTypes =
unnecessaryParser.getSupportedTypes(null);
unnecessaryTypes.addAll(supportedTypes);
}
return unnecessaryTypes;
}
private void disableParsing(final CompositeParser mainParser,
final Set<MediaType> unnecessaryMediaTypes) {
final EmptyParser emptyParser = new EmptyParser();
final Map<MediaType, Parser> parsers = mainParser.getParsers();
for (final MediaType unnecessaryType: unnecessaryMediaTypes) {
parsers.put(unnecessaryType, emptyParser);
}
mainParser.setParsers(parsers);
}
用法:
final Parser unnecessaryParser = new MP4Parser();
final Tika tika = createTika(unnecessaryParser);
您也可以使用它来避免TIKA-1040: Could not delete temporary file。