如果我有一个需要文件路径的构造函数,如果将它打包到jar中,怎么能“假”?

时间:2011-02-10 16:22:52

标签: java jar hadoop apache-pig

这个问题的背景是我正在尝试在我编写的猪脚本中使用maxmind java api ...但是我不认为知道这两者都是回答这个问题的必要条件。

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将是一件很麻烦的事。

这可能吗?

6 个答案:

答案 0 :(得分:2)

尝试:

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

答案 1 :(得分: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

答案 2 :(得分:2)

一种推荐的方法是使用Distributed Cache而不是尝试将其捆绑到jar中。

如果您压缩GeoIP.dat并将其复制到hdfs:// host:port / path / GeoIP.dat.zip。然后将这些选项添加到Pig命令:

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

并且LookupService lookupService = new LookupService("./GeoIP.dat");应该在您的UDF中工作,因为文件将在本地存在于每个节点上的任务。

答案 3 :(得分:2)

这适合我。

假设您有一个包含GeoLiteCity.dat的包org.foo.bar.util

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 );

答案 4 :(得分:1)

使用classloader.getResource(...)方法在类路径中执行文件查找,这将从JAR文件中提取文件。

这意味着您必须更改现有代码以覆盖加载。有关如何执行此操作的详细信息很大程度上取决于您现有的代码和环境。在某些情况下,使用框架子类化和注册子类可能会起作用。在其他情况下,您可能必须确定类路径中类加载的顺序,并在类路径中“更早”地放置一个相同签名的类。

答案 5 :(得分: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放在can上并使用-files参数指定它,它将被放入本地缓存中,然后映射器可以在setup函数中获取。它不必在setup中,但每个映射器只需要完成一次,因此它是一个很好的放置它的地方。 然后使用-libjars参数指定geoiplookup.jar(或者你称之为你的任何东西)并且它将能够使用它。我们不会将geoiplookup.jar放在云上。我假设hadoop会根据需要分配jar。

我希望一切都有道理。我对hadoop / mapreduce非常熟悉,但我没有'在项目中编写使用maxmind geoip组件的部分,所以我不得不做一点挖掘才能理解它,以便做我在这里的解释。

编辑:-files-libjars的其他说明 -files files参数用于通过Hadoop Distributed Cache分发文件。在上面的示例中,我们通过Hadoop分布式缓存分发Max Mind geo-ip数据文件。我们需要访问Max Mind geo-ip数据文件,将用户的IP地址映射到适当的国家,地区,城市,时区。 API要求数据文件存在于本地,这在分布式处理环境中是不可行的(我们无法保证集群中的哪些节点将处理数据)。为了将适当的数据分发到处理节点,我们使用Hadoop分布式缓存基础结构。 GenericOptionsParser和ToolRunner使用-file参数自动促进此操作。请注意,我们分发的文件应该可以在云端(HDFS)中找到。 -libjars -libjars用于分发map-reduce作业所需的任何其他依赖项。与数据文件一样,我们还需要将依赖库复制到将运行作业的集群中的节点。 GenericOptionsParser和ToolRunner使用-libjars参数自动促进这一点。