2013-11-27 180 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

相關問題