运行hadoop作业时发生java.lang.outofmemoryerror

rqqzpn5f  于 2021-06-04  发布在  Hadoop
关注(0)|答案(2)|浏览(435)

我有一个输入文件(大小约31gb),其中包含一些产品的消费者评论,我正试图将这些产品进行柠檬化,并找到相应的引理数。这种方法与hadoop提供的wordcount示例有些相似。我一共有4个类来执行这个处理:stanfordlemmatizer[包含斯坦福corenlp包v3.3.0中用于柠檬化的好东西]、wordcount[驱动程序]、wordcountmapper[Map程序]和wordcountreducer[还原程序]。
我在原始数据集的一个子集(以mb为单位)上测试了这个程序,它运行得很好。不幸的是,当我在大小约31gb的完整数据集上运行作业时,作业失败。我检查了作业的系统日志,其中包含以下内容:
java.lang.outofmemoryerror:edu.stanford.nlp.sequences.exactbestsequencefinder.bestsequence(exactbestsequencefinder)的java堆空间。java:109) [...]
对如何处理这个问题有什么建议吗?
注意:我使用的是预先配置了hadoop-0.18.0的yahoo虚拟机。我还尝试了这个线程中提到的分配更多堆的解决方案:hadoop中的内存不足错误
wordcountmapper代码:

  1. import java.io.IOException;
  2. import org.apache.hadoop.io.IntWritable;
  3. import org.apache.hadoop.io.LongWritable;
  4. import org.apache.hadoop.io.Text;
  5. import org.apache.hadoop.mapred.MapReduceBase;
  6. import org.apache.hadoop.mapred.Mapper;
  7. import org.apache.hadoop.mapred.OutputCollector;
  8. import org.apache.hadoop.mapred.Reporter;
  9. public class WordCountMapper extends MapReduceBase
  10. implements Mapper<LongWritable, Text, Text, IntWritable> {
  11. private final IntWritable one = new IntWritable(1);
  12. private final Text word = new Text();
  13. private final StanfordLemmatizer slem = new StanfordLemmatizer();
  14. public void map(LongWritable key, Text value,
  15. OutputCollector output, Reporter reporter) throws IOException {
  16. String line = value.toString();
  17. if(line.matches("^review/(summary|text).*")) //if the current line represents a summary/text of a review, process it!
  18. {
  19. for(String lemma: slem.lemmatize(line.replaceAll("^review/(summary|text):.", "").toLowerCase()))
  20. {
  21. word.set(lemma);
  22. output.collect(word, one);
  23. }
  24. }
  25. }
  26. }
iyzzxitl

iyzzxitl1#

如果stanfordlemmatizer不是mapreduce作业的一部分,那么配置hadoop堆空间可能对您没有帮助。你能提供这份工作的代码吗?所以,我认为限制您的通常是java堆空间。
在考虑配置之前,请先检查以下内容:
我看了edu.stanford.nlp.sequences.exactbestsequencefinder的代码(你也应该在这里试试)
我不知道你用的是哪个版本的stanford.nlp,我也不太熟悉,但它似乎是基于你输入的“sequencemodel”进行一些操作的。它是这样开始的:

  1. private int[] bestSequenceNew(SequenceModel ts) {
  2. // Set up tag options
  3. int length = ts.length();
  4. int leftWindow = ts.leftWindow();
  5. int rightWindow = ts.rightWindow();
  6. int padLength = length + leftWindow + rightWindow;
  7. int[][] tags = new int[padLength][]; //operations based on the length of ts
  8. int[] tagNum = new int[padLength]; //this is the guilty line 109 according to grepcode

因此ts.length()的输出非常大(或者这个数组没有更多的java堆空间)。你能小一点吗?
编辑
所以很明显绳子

  1. line.replaceAll("^review/(summary|text):.", "").toLowerCase()

对于java堆来说太多了。你能看看这是否真的是你想要的吗?你能打印它的长度吗?也许你应该考虑重新组织你的31gb数据集,使它比现在有更多更小的行(如果可能的话)。这可能是一条线太大的错误和问题的原因。
如果无法完成,请打印异常的完整堆栈跟踪。

展开查看全部
avwztpqn

avwztpqn2#

您需要使正在处理的单个单元(即,Map中的每个Map作业)的大小合理。第一个单位是提供给stanfordcorenlp的annotate()调用的文档大小。您在这里提供的整个文本片段将在内存中进行标记化和处理。在标记化和处理的形式中,它比磁盘上的大小大一个数量级以上。因此,文档大小需要合理。e、 例如,您可以一次通过一个消费者评论(而不是31gb的文本文件!)
其次,向下一级,pos tagger(在lemmatization之前)一次注解一个句子,它使用大型临时动态规划数据结构来标记一个句子,这个句子的大小可能比这个句子大3个数量级。所以,个别句子的长度也需要合理。如果有很长一段文字或垃圾没有分成句子,那么你可能也有这个级别的问题。解决这个问题的一个简单方法是使用 pos.maxlen 属性来避免词性标注超长句。
p、 当然,如果您只需要lemmatizer,就不应该运行parse、dcoref之类的注解器。

相关问题