2017-08-24 60 views
0

我在MR作業的映射階段中使用了一個自定義可寫類作爲VALUEOUT,其中類有兩個字段A org.apache.hadoop.io.Textorg.apache.hadoop.io.MapWritable。在我的reduce函數中,遍歷每個鍵的值,並執行兩個操作:1. filter,2. aggregate。在過濾器中,我有一些規則來檢查MapWritable中的某些值(鍵爲Text,值爲IntWritableDoubleWritable)是否滿足某些條件,然後將其簡單地添加到ArrayList中。在過濾操作結束時,我有一個過濾的自定義可寫對象列表。在彙總階段,當我訪問這些對象時,結果是最後一個被成功過濾的對象已經覆蓋了數組列表中的所有其他對象。在對最後一個對象覆蓋所有其他對象的SO上列出了一些類似的問題之後,我確認了我沒有靜態字段,也沒有通過設置不同的值來重複使用相同的自定義可寫(這被引用爲可能的原因)一個問題)。對於減速器中的每個鍵,我都確保CustomWritableText鍵和MapWritable是新對象。另外,我還通過在我的reduce中刪除了過濾器&聚合操作並剛剛迭代了這些值並使用for循環將它們添加到ArrayList中來執行簡單測試。在循環中,每次我將一個CustomWritable添加到列表中時,我都記錄了列表中所有內容的值。我在將元素添加到列表之前和之後進行了記錄。這兩個日誌都表明前一組元素已被覆蓋。我很困惑這種情況如何發生。一旦迭代值中的下一個元素被循環for (CustomWritable result : values)訪問,列表內容就被修改了。我無法弄清楚這種行爲的原因。如果任何人都可以對此有所瞭解,這將非常有幫助。謝謝。迭代減速器中定製可寫組件的問題

+0

我注意到這裏有一個類似的問題:可迭代到ArrayList的元素改變(https://stackoverflow.com/questions/23329173/iterable-to-arraylist-elements-change?rq=1)。也許問題是相似的,但它有相同的值,不知道它是最後一個元素還是第一個訪問的元素。即便如此,我有一個複雜的對象,每次都不得不重新創建一個新對象,這看起來像是一種笨拙和痛苦的選擇,我不想訴諸於此。任何其他更好的選擇? – KNP

回答

1

reducer中的「values」迭代器在迭代時重用該值。這是一種用於性能和更小內存佔用的技術。在幕後,Hadoop將下一條記錄反序列化爲同一個Java對象。如果你需要「記住」一個對象,你需要克隆它。

您可以利用Writable接口並使用原始字節來填充新對象。

IntWritable first = WritableUtils.clone(values.next(), context.getConfiguration()); 
IntWritable second = WritableUtils.clone(values.next(), context.getConfiguration()); 
+0

謝謝傑夫。像魅力一樣工作。我想知道它是如何工作的,因爲我們使用HBase org.apache.hadoop.hbase.client.Result作爲值,因爲它不是一個Writable類。儘管如此,我不記得遇到過這種Result對象的問題。 – KNP