Java 如果我有一个需要文件路径的构造函数,我怎么能;假;如果它被包装在一个罐子里?
这个问题的背景是,我试图在我编写的pig脚本中使用maxmind java api。。。然而,我不认为有必要了解这两种情况来回答这个问题 maxmind API有一个构造函数,它需要一个名为GeoIP.dat的文件的路径,该文件是一个逗号分隔的文件,其中包含所需的信息 我有一个包含API的jar文件,还有一个包装类,它实例化并使用该类。我的想法是将GeoIP.dat文件打包到jar中,然后作为jar文件中的资源访问它。问题是我不知道如何构造构造函数可以使用的路径 查看API,以下是加载文件的方式:Java 如果我有一个需要文件路径的构造函数,我怎么能;假;如果它被包装在一个罐子里?,java,jar,hadoop,apache-pig,Java,Jar,Hadoop,Apache Pig,这个问题的背景是,我试图在我编写的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将是一件非常繁琐的事情
这可能吗?使用
classloader.getResource(…)
方法在类路径中查找文件,这将从JAR文件中提取它
这意味着您必须更改现有代码以覆盖加载。如何做到这一点的细节在很大程度上取决于您现有的代码和环境。在某些情况下,子类化和向框架注册子类可能会起作用。在其他情况下,您可能必须确定类沿类路径加载的顺序,并在类路径中“更早”放置一个具有相同符号的类。尝试:
new File(MyWrappingClass.class.getResource(<resource>).toURI())
新文件(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
下面是我们如何使用maxmind geoIP 我们将
geoicity.dat
文件放入云中,并在启动流程时使用云位置作为参数。
获取geoicity.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()));
}
}
}
if(DistributedCache.getLocalCacheFiles(context.getConfiguration())!=null){
List localFiles=Utility.arrayToList(DistributedCache.getLocalCacheFiles(context.getConfiguration());
用于(路径localFile:localFiles){
如果((localFile.getName()!=null)&&(localFile.getName().equalsIgnoreCase(“geoicity.dat”)){
m_geoipLookupService=newlookupservice(新文件(localFile.toUri().getPath());
}
}
}
下面是用于运行流程的命令的缩写版本
$HADOOP\u HOME/bin/HADOOP jar/usr/lib/COMPANY/analytics/libjars/MyJar.jar-文件hdfs://PDHadoop1.corp.COMPANY.com:54310/data/geoip/GeoIPCity.dat -libjars/usr/lib/COMPANY/analytics/libjars/geoiplookup.jar
运行MindMax组件的关键组件是-files
和-libjars
。这些是中的通用选项
-文件指定要复制到map reduce群集的逗号分隔文件
-libjars指定要包含在类路径中的逗号分隔的jar文件。
我假设Hadoop使用了GenericOptionsParser
,因为我在项目中的任何地方都找不到对它的引用
如果将geoicity.dat
放在can上,并使用-files
参数指定它,它将被放入本地缓存中,然后映射程序可以在设置
函数中获取该缓存。它不必在设置中,但每个映射器只需执行一次,因此是放置它的最佳位置。
然后使用-libjars
参数指定geoiplookup.jar(或您所称的任何内容),它将能够使用它。我们不会将geoiplookup.jar放在云上。我相信hadoop会根据需要分发jar
我希望这一切都有意义。我对hadoop/mapreduce已经相当熟悉了,但是我没有在项目中编写使用maxmind geoip组件的文章,所以我不得不做一些挖掘工作来充分理解它,以便完成这里的解释
编辑:对-files
和-libjars
-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参数自动实现这一点。推荐的方法之一是使用,而不是尝试将其捆绑到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=newlookupservice(“./GeoIP.dat”)
应该在您的UDF中工作,因为文件将在每个节点上的任务本地显示。这对我很有用
假设您有一个包含GeoLiteCity的包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 );