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

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

我有一个输入文件(大小约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代码:

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;

public class WordCountMapper extends MapReduceBase
    implements Mapper<LongWritable, Text, Text, IntWritable> {

  private final IntWritable one = new IntWritable(1);
  private final Text word = new Text();
  private final StanfordLemmatizer slem = new StanfordLemmatizer();

  public void map(LongWritable key, Text value,
      OutputCollector output, Reporter reporter) throws IOException {

    String line = value.toString();

    if(line.matches("^review/(summary|text).*"))    //if the current line represents a summary/text of a review, process it! 
    {
        for(String lemma: slem.lemmatize(line.replaceAll("^review/(summary|text):.", "").toLowerCase()))
        {
            word.set(lemma);
            output.collect(word, one);
        }
    }
  }
}
iyzzxitl

iyzzxitl1#

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

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

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

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之类的注解器。

相关问题