2013-11-27 120 views
0

我有一个输入文件(大小约31GB),其中包含有关某些产品的消费者评论,我试图推理并找到相应的引理计数。该方法有点类似于Hadoop提供的WordCount示例。我有4个课程来进行处理:StanfordLemmatizer [包含来自Stanford的coreNLP软件包v3.3.0的词汇推理的好东西],WordCount [驱动程序],WordCountMapper [映射程序]和WordCountReducer [reducer]。运行Hadoop作业的java.lang.OutOfMemoryError

我已经测试了原始数据集的一个子集(以MB为单位)的程序,它运行良好。不幸的是,当我在大小〜31GB的完整数据集上运行作业时,作业失败。我检查作业的日志它包含在此:

java.lang.OutOfMemoryError: Java heap space at edu.stanford.nlp.sequences.ExactBestSequenceFinder.bestSequence(ExactBestSequenceFinder.java:109) [...]

如何处理这有什么建议?

注意:我使用的是预先配置了hadoop-0.18.0的Yahoo VM。我也尝试分配更多的堆的解决方案,在这个线程中提到:out of Memory Error in 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); 
     } 
    } 
    } 
} 

回答

2

您需要使您正在处理的单个单元的大小(即map-reduce中的每个Map作业)合理。第一个单位是您提供给StanfordCoreNLP的annotate()调用的文档的大小。你在这里提供的全部文本将被标记并在内存中处理。以标记和处理形式,它比磁盘上的大小大一个数量级。所以,文件大小需要合理。例如,您可能一次只通过一次消费者评论(而不是31GB的文本文件!)

其次,一级降低,POS标记器(在词形之前)注释一个句子,它使用大量的临时动态规划数据结构来标记一个句子,其大小可能比句子大3个数量级。所以,单个句子的长度也需要合理。如果有很长的文本或垃圾没有被分成句子,那么你在这个级别也可能会遇到问题。解决这个问题的一个简单方法是使用pos.maxlen属性来避免POS标记超长句子。

p.s.当然,如果你只需要lemmatizer,你就不应该运行parse,dcoref等注释器。

+0

谢谢曼宁教授的详细解释和建议。将尝试他们,看看我是否可以管理一些解决方法:) – Aditya

0

配置Hadoop的堆空间可能不会帮助你,如果你的StanfordLemmatizer不是映射精简的一部分工作。你能提供工作的代码吗?所以,我相信一般来说,Java堆空间是你的限制。

在考虑将其配置检查这个第一:

我看了一下edu.stanford.nlp.sequences.ExactBestSequenceFinder的代码(你应该尝试太here

我不知道你使用的是哪个版本的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数据集,以便它的行数比现在多(如果可能的话)。这可能是因为一行错误太大而导致问题的原因。

如果无法完成,请打印Exceptions的完整堆栈跟踪。

+0

谢谢Artem,我使用Stanford coreNLP软件包的v3.3.0。如果您想查看,只需在问题本身中添加我的mapper类的代码即可。而不是修补coreNLP的源代码,我宁愿调整我自己的程序,因为它对我来说要简单得多:) – Aditya

+0

@Aditya不客气!请参阅编辑。 –

+0

谢谢Artem,这非常有道理。我会试着看看在传递给Hadoop执行之前是否可以预先处理数据集。我试图寻找另一种解决方法,但没有运气。因为我觉得这本身就是一个单独的问题,所以我在这里问过它,如果你想看看:http://stackoverflow.com/questions/20256197/use-wget-with-hadoop – Aditya

相关问题