4

这个问题的背景是我正在尝试在我编写的猪脚本中使用 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 将是一件很麻烦的事。

这可能吗?

4

6 回答 6

2

尝试:

new File(MyWrappingClass.class.getResource(<resource>).toURI())
于 2011-02-10T16:29:38.080 回答
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
于 2011-02-10T16:31:43.370 回答
2

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

于 2011-02-11T06:06:34.653 回答
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 );
于 2012-06-11T00:25:35.320 回答
1

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

这意味着您将不得不更改现有代码以覆盖加载。如何做到这一点的细节在很大程度上取决于您现有的代码和环境。在某些情况下,子类化和向框架注册子类可能会起作用。在其他情况下,您可能必须确定类加载沿类路径的顺序,并将具有相同签名的类“较早”放置在类路径中。

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

于 2011-02-10T20:49:16.027 回答