2011-02-10 43 views
4

這個問題的背景是,我試圖在我寫的豬腳本中使用maxmind java api ...但是,我不認爲要麼知道這兩個問題,要麼回答這個問題是必要的。如果我有一個構造函數需要一個文件路徑,如果它被打包到一個jar文件中,我該如何「僞造」它?

maxmind API有一個構造函數,它需要一個名爲GeoIP.dat的文件的路徑,該文件是一個逗號分隔的文件,它具有所需的信息。

我有一個包含API的jar文件,以及一個實例化類並使用它的包裝類。我的想法是將GeoIP.dat文件打包到jar文件中,然後將其作爲jar文件中的資源進行訪問。問題是我不知道如何構造構造函數可以使用的路徑。

綜觀API,這是他們如何裝載文件:

public LookupService(String databaseFile) throws IOException { 
    this(new File(databaseFile)); 
} 


public LookupService(File databaseFile) throws IOException { 
    this.databaseFile = databaseFile; 
    this.file = new RandomAccessFile(databaseFile, "r"); 
    init(); 
} 

我只粘貼,因爲我不反對編輯API本身來完成這項工作,如果有必要,但不知道我如何能夠複製我這樣的功能。理想情況下,我希望將它放入文件表單中,否則,編輯API將會非常麻煩。

這可能嗎?

+0

有在該文件實際上是讀取源密切關注。你可以重寫該方法嗎? – 2011-02-10 16:26:54

+0

我的目標是能夠從類路徑中的某個文件中獲取文件f。如果我可以做到這一點,那麼我可以改變一些事情,讓其餘的工作。 – 2011-02-10 16:54:07

回答

1

使用classloader.getResource(...)方法在類路徑中執行文件查找,該文件將從JAR文件中提取文件。

這意味着你將不得不改變現有的代碼來覆蓋加載。如何做到這一點的細節很大程度上取決於您現有的代碼和環境。在某些情況下,使用框架進行子類化和註冊子類可能會起作用。在其他情況下,您可能必須確定類路徑中類加載的順序,並在類路徑中「早些時候」放置一個具有相同簽名的類。

2

嘗試:

new File(MyWrappingClass.class.getResource(<resource>).toURI()) 
+0

這將工作與jar文件條目? – 2011-02-10 16:31:04

+0

如果jar在有效的類路徑中,它應該像URI那樣代表網絡上,文件系統上或類路徑中的資源。我在這個建議中做了類似的處理。但是,這已經有一段時間了,我可能會錯過一兩個特定的細節。但是,這個(或者與之相近的東西)應該適用於一個classpath中的jar文件。 – 2011-02-10 16:34:42

2

轉儲你的數據到一個臨時文件,臨時文件養活它。

File tmpFile = File.createTempFile("XX", "dat"); 
tmpFile.deleteOnExit(); 

InputStream is = MyClass.class.getResourceAsStream("/path/in/jar/XX.dat"); 
OutputStream os = new FileOutputStream(tmpFile) 

read from is, write to os, close 
1

以下是我們如何使用maxmind geoIP;

我們將GeoIPCity.dat文件放入雲中,並在啓動過程時使用雲位置作爲參數。 我們得到了GeoIPCity.data文件並創建一個新的LookupService的代碼是:

if (DistributedCache.getLocalCacheFiles(context.getConfiguration()) != null) { 
    List<Path> localFiles = Utility.arrayToList(DistributedCache.getLocalCacheFiles(context.getConfiguration())); 
    for (Path localFile : localFiles) { 
     if ((localFile.getName() != null) && (localFile.getName().equalsIgnoreCase("GeoIPCity.dat"))) { 
      m_geoipLookupService = new LookupService(new File(localFile.toUri().getPath())); 
     } 
    } 
} 

下面是命令的縮寫版本中,我們用它來運行我們的程序

$HADOOP_HOME/bin/hadoop jar /usr/lib/COMPANY/analytics/libjars/MyJar.jar -files hdfs://PDHadoop1.corp.COMPANY.com:54310/data/geoip/GeoIPCity.dat -libjars /usr/lib/COMPANY/analytics/libjars/geoiplookup.jar

這樣做的關鍵部件運行MindMax組件是-files-libjars。這些是GenericOptionsParser中的通用選項。

-files <comma separated list of files> specify comma separated files to be copied to the map reduce cluster
-libjars <comma separated list of jars> specify comma separated jar files to include in the classpath.

我假設Hadoop的使用GenericOptionsParser因爲我能找到我的項目中沒有任何地方提到它。:)

如果你把GeoIPCity.dat上能和它的使用-files參數指定,它會被放入本地緩存該映射器然後可以在setup功能得到。它不必在setup中,但每個映射器只需要執行一次,因此是一個很好的放置位置。 然後使用-libjars參數來指定geoiplookup.jar(或稱爲你的任何東西),它將能夠使用它。我們不把geoiplookup.jar放在雲上。我假設hadoop會根據需要分發jar。

我希望一切都有道理。我對hadoop/mapreduce非常熟悉,但是我沒有在項目中編寫使用maxmind geoip組件的部分,所以我必須做一點深入的瞭解,才能做出我在這裏所做的解釋。

編輯:-files-libjars的附加說明 -files files參數用於通過Hadoop分佈式緩存分發文件。在上面的示例中,我們通過Hadoop分佈式緩存分發Max Mind地理-ip數據文件。我們需要訪問Max Mind geo-ip數據文件,將用戶的IP地址映射到適當的國家,地區,城市,時區。 API要求數據文件在本地存在,這在分佈式處理環境中是不可行的(我們無法保證羣集中哪些節點將處理數據)。爲了將適當的數據分發到處理節點,我們使用Hadoop分佈式緩存基礎結構。 GenericOptionsParser和ToolRunner使用-file參數自動實現這一點。請注意,我們分發的文件應該在雲中可用(HDFS)。 -libjars -libjars用於分發map-reduce作業所需的任何附加依賴項。與數據文件一樣,我們還需要將相關庫複製到要運行作業的羣集中的節點。 GenericOptionsParser和ToolRunner使用-libjars參數自動實現這一點。

2

一種推薦的方法是使用Distributed Cache而不是試圖將它捆綁到一個罐子裏。

如果您壓縮GeoIP.dat並將其複製到hdfs:// host:port/path/GeoIP.dat.zip。然後將這些選項豬命令:

pig ... 
    -Dmapred.cache.archives=hdfs://host:port/path/GeoIP.dat.zip#GeoIP.dat 
    -Dmapred.create.symlink=yes 
... 

而且LookupService lookupService = new LookupService("./GeoIP.dat");應該在你的UDF工作的文件將是局部存在於每個節點上的任務。

2

這適用於我。

假設你有一個包org.foo.bar.util包含GeoLiteCity.dat

URL fileURL = this.getClass().getResource("org/foo/bar/util/GeoLiteCity.dat"); 
File geoIPData = new File(fileURL.toURI()); 
LookupService cl = new LookupService(geoIPData, LookupService.GEOIP_MEMORY_CACHE); 
相關問題