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

这个问题的上下文是我试图在我编写的猪脚本中使用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本身以使其工作,如果有必要,但不知道如何复制我的function。 理想情况下,我希望将其纳入文件格式,否则编辑API将是一件非常繁琐的事。

这可能吗?

尝试:

 new File(MyWrappingClass.class.getResource().toURI()) 

将数据转储到临时文件,并将临时文件提供给它。

 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 

一种推荐的方法是使用分布式缓存而不是尝试将其捆绑到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中工作,因为文件将在本地存在于每个节点上的任务。

这对我有用。

假设您有一个包含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 ); 

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

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

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

我们将GeoIPCity.dat文件放入云中,并在启动流程时使用云位置作为参数。 我们获取GeoIPCity.data文件并创建新LookupService是:

 if (DistributedCache.getLocalCacheFiles(context.getConfiguration()) != null) { List 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 specify comma separated files to be copied to the map reduce cluster
-libjars specify comma separated jar files to include in the classpath.

我假设Hadoop使用GenericOptionsParser因为我在项目的任何地方都找不到对它的引用。 🙂

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

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

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