使用Guava MapSplitters配置Hadoop
在本文中,我們將為通過Context對象將配置參數傳遞給Hadoop Mapper提供新的思路。 通常,我們在啟動map-reduce作業時將配置參數設置為Context對象上的鍵/值對。 然后,在Mapper中,我們使用鍵來檢索用于我們的配置需求的值。 不同之處在于,我們將在Context對象上設置一個特殊格式的字符串,并在Mapper中檢索值時,使用Guava MapSplitter將格式化后的字符串轉換為將用于獲取配置參數的HashMap 。 我們可能會問自己為什么要去解決這個麻煩? 通過以這種方式進行配置,我們可以在Context對象上設置單個鍵值對的情況下將多個參數傳遞給Mapper。 為了說明一種可能的用法,我們將回顧最后一篇文章 ,其中介紹了如何執行減少側聯接。 該職位提出的解決方案存在兩個問題。 首先,我們假設要加入的鍵始終是文件中帶分隔符的字符串中的第一個值。 其次,我們假設每個文件都使用相同的定界符。 如果我們要從密鑰位于每個文件中不同位置的文件中加入數據,而某些文件使用不同的定界符怎么辦? 另外,我們想對輸出的所有數據使用相同的定界符(如果有的話),而與任何輸入文件中使用的定界符無關。 盡管這確實是人為的情況,但它將很好地用于演示目的。 首先讓我們研究一下MapSplitter類是什么以及如何使用它。
MapSplitter
MapSplitter是Splitter類中的嵌套類。 Spitter接受一個字符串,并使用給定的定界符將其拆分為多個部分。 MapSplitter通過從字符串創建Map <String,String>進一步走了一步,該字符串的鍵值對之間用一個定界符分隔,而對值本身則完全用另一個定界符分隔。 讓我們看一個例子:
Map<String,String> configParams = Splitter.splitOn("#").withKeyValueSeparator("=").split("6=June#7=July#8=August");在上面的示例中,字符串"6=June#7=July#8=August"將被轉換為Map,鍵6,7和8分別映射到June,July和August。 MapSplitter是一個非常簡單但功能強大的類。 現在我們知道了MapSplitter工作原理,讓我們看一下如何使用它來幫助我們為map-reduce作業設置配置參數
使用MapSplitter進行配置
以前,我們通過在Context對象中為map-reduce作業設置值,來將連接鍵和分隔符的索引位置設置為對所有文件相同。 現在,我們希望能夠根據需要在每個輸入文件的基礎上進行設置。 我們仍將根據需要提供默認值。 為了完成此更改,我們將創建一個屬性文件,該屬性文件將文件名作為鍵,并且該值將是格式設置為MapSplitter使用的MapSplitter 。 我們的屬性文件如下所示:
oneToManyEmployer2.txt=keyIndex=1&separator=| oneToManyVehicles2.txt=keyIndex=1&separator=#在這里,我們指示文件oneToManyEmployer2.txt在索引位置1處具有我們的連接鍵,而分隔符為“ |” 豎線字符和oneToManyVehicles2.txt文件的連接鍵位于索引位置1,并使用“,”逗號作為分隔符。 我們將對驅動程序類進行一些更改。 首先,我們將加載屬性文件(假設我們已將文件放置在相對于調用hadoop的目錄中)。
InputStream inputStream = new FileInputStream(new File("./jobs/join-config.properties")); Properties properties = new Properties(); properties.load(inputStream);首先,我們定義一個常規的Splitter對象,該對象將在斜杠“ /”上拆分文件名。 接下來,當我們遍歷文件名時,通過對從Splitter.split方法調用返回的Iterable對象調用Iterables.getLast來獲得文件的基本名稱。 然后,我們嘗試在Properties.getProperty方法中為每個文件檢索配置的屬性字符串。 請注意,如果找不到文件的屬性,我們還將傳遞defaultMapConfig變量,該變量提供默認值。 我們還添加了一些其他配置鍵和值。 將值連接在一起時使用的分隔符以及文件的連接順序,該順序由文件在提供給程序的參數中的位置確定。 然后,我們僅使用文件名作為鍵將格式化后的字符串放入Context對象。
String defaultMapConfig = "keyIndex=0&separator=,"; Splitter splitter = Splitter.on('/'); for (int i = 0; i < args.length - 1; i++) {String fileName = Iterables.getLast(splitter.split(args[i]));String mapConfig = properties.getProperty(fileName, defaultMapConfig);builder.append(mapConfig).append("&joinDelimiter=,&joinOrder=").append(i + 1);config.set(fileName, builder.toString());builder.setLength(0);filePaths.append(args[i]).append(","); }使用配置值
要使用我們的配置值,我們首先必須檢索存儲為包含我們的配置參數的字符串的HashMap
private Splitter.MapSplitter mapSplitter = Splitter.on("&").withKeyValueSeparator("="); ....... private Map<String,String> getConfigurationMap(Context context){FileSplit fileSplit = (FileSplit)context.getInputSplit();String configString = context.getConfiguration().get(fileSplit.getPath().getName());return mapSplitter.split(configString);}在這里,我們使用MapSplitter實例變量,并通過使用此Mapper使用的文件名檢索存儲在Context的格式化字符串來創建HashMap 。 現在,我們可以簡單地從映射中拉出所需的配置參數,如setup方法中所示:
protected void setup(Context context) throws IOException, InterruptedException {Map<String,String> configMap = getConfigurationMap(context);keyIndex = Integer.parseInt(configMap.get("keyIndex"));String separator = configMap.get("separator");splitter = Splitter.on(separator).trimResults();String joinDelimiter = configMap.get("joinDelimiter");joiner = Joiner.on(joinDelimiter);joinOrder = Integer.parseInt(configMap.get("joinOrder"));}map方法中的代碼與我們先前的文章中的代碼相同。現在,我們對每個文件都有完全可配置的設置,而不必局限于將join鍵放在一個位置或對每個文件使用相同的定界符。 當然,這只是一個示例,但是此處概述的方法可用于配置許多其他設置,并且只需要Context對象中的一個鍵即可。
結果
最初,我們的數據如下所示:
oneToManyEmployer2.txt:
Creative Wealth|cdd8dde3-0349-4f0d-b97a-7ae84b687f9c Susie's Casuals|81a43486-07e1-4b92-b92b-03d0caa87b5f Super Saver Foods|aef52cf1-f565-4124-bf18-47acdac47a0e .....oneToManyVehicles2.txt:
2003 Holden Cruze#cdd8dde3-0349-4f0d-b97a-7ae84b687f9c 2012 Volkswagen T5#81a43486-07e1-4b92-b92b-03d0caa87b5f 2009 Renault Trafic#aef52cf1-f565-4124-bf18-47acdac47a0e .....singlePersonRecords.txt:
cdd8dde3-0349-4f0d-b97a-7ae84b687f9c,Esther,Garner,4071 Haven Lane,Okemos,MI 81a43486-07e1-4b92-b92b-03d0caa87b5f,Timothy,Duncan,753 Stadium Drive,Taunton,MA aef52cf1-f565-4124-bf18-47acdac47a0e,Brett,Ramsey,4985 Shinn Street,New York,NY ......運行我們的map-reduce作業后,結果看起來就像我們想要的一樣:
08db7c55-22ae-4199-8826-c67a5689f838,John,Gregory,258 Khale Street,Florence,SC,2010 Nissan Titan,Ellman's Catalog Showrooms 0c521380-f868-438c-9916-4ab4ea76d316,Robert,Eversole,518 Stratford Court,Fayetteville,NC,2002 Toyota Highlander,Specialty Restaurant Group 1303e8a6-0085-45b1-8ea5-26c809635da1,Joe,Nagy,3438 Woodstock Drive,El Monte,CA,2011 Hyundai ix35,Eagle Food Centers 15360125-38d6-4f1e-a584-6ab9d1985ab8,Sherri,Hanks,4082 Old House Drive,Alexandria,OH,2003 Toyota Solara,Odyssey Records & Tapes ......資源資源
- Jimmy Lin和Chris Dyer 使用MapReduce進行的數據密集型處理
- Hadoop: Tom White 的權威指南
- 來自博客的源代碼和測試
- 愛德華·卡普里奧洛(Edward Capriolo),迪恩·沃普勒(Dean Wampler)和杰森·盧瑟格倫(Jason Rutherglen)的編程蜂巢
- 通過Alan Gates對Pig進行編程
- Hadoop API
- MRUnit用于單元測試Apache Hadoop映射減少工作
翻譯自: https://www.javacodegeeks.com/2013/09/configuring-hadoop-with-guava-mapsplitters.html
總結
以上是生活随笔為你收集整理的使用Guava MapSplitters配置Hadoop的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 50个Servlet面试问答
- 下一篇: 编码Java时的10个微妙的最佳实践