使用可变长度/非分隔二进制文件的hadoop中的gis拆分

l5tcr1uw  于 2021-06-04  发布在  Hadoop
关注(0)|答案(1)|浏览(506)

我刚刚开始为开放街道Map数据开发一个基于hadoop的摄取器。有几种格式-但我一直针对基于protocolbuffer的格式(注意-它不是纯pb)。
在我看来,将文件预拆分为序列文件会更有效—而不是以自定义记录读取器/输入格式处理可变长度编码—但需要进行健全性检查。
格式在pbf format description中有更详细的描述,但基本上它是[blobheader,blob]块的集合。
有一个水滴头

  1. message BlobHeader {
  2. required string type = 1;
  3. optional bytes indexdata = 2;
  4. required int32 datasize = 3;
  5. }

然后是blob(其大小由标头中的datasize参数定义)

  1. message Blob {
  2. optional bytes raw = 1; // No compression
  3. optional int32 raw_size = 2; // Only set when compressed, to the uncompressed size
  4. optional bytes zlib_data = 3;
  5. // optional bytes lzma_data = 4; // PROPOSED.
  6. // optional bytes OBSOLETE_bzip2_data = 5; // Deprecated.
  7. }

很明显,一旦深入到blob中,就会有更多的结构——但我会在mapper中处理这个问题——我想做的是,最初每个mapper有一个blob(稍后可能是每个mapper blob的倍数)。
其他一些输入格式/记录读取器使用“足够大”的拆分大小,然后向后/向前查找分隔符-但是由于没有分隔符可以让我知道blob/headers的偏移量-也没有指向它们的索引-我看不到任何方法来获取拆分点,而不首先对文件进行流式处理。
现在,我不需要从磁盘上读取整个文件—我可以从读取头开始,使用该信息查找blob,将其设置为第一个分割点,然后重复。但这是我能想到的唯一一个可以替代预分割成序列文件的方法。
有没有更好的方法来处理这个问题?如果没有,对这两个建议有什么想法?

toiithl6

toiithl61#

好吧,我用getsplits方法解析二进制文件——由于跳过了99%以上的数据,所以速度非常快(planet osm 22gb world文件大约20秒)。如果其他人遇到了问题,下面是getsplits方法。

  1. @Override
  2. public List<InputSplit> getSplits(JobContext context){
  3. List<InputSplit> splits = new ArrayList<InputSplit>();
  4. FileSystem fs = null;
  5. Path file = OSMPBFInputFormat.getInputPaths(context)[0];
  6. FSDataInputStream in = null;
  7. try {
  8. fs = FileSystem.get(context.getConfiguration());
  9. in = fs.open(file);
  10. long pos = 0;
  11. while (in.available() > 0){
  12. int len = in.readInt();
  13. byte[] blobHeader = new byte[len];
  14. in.read(blobHeader);
  15. BlobHeader h = BlobHeader.parseFrom(blobHeader);
  16. FileSplit split = new FileSplit(file, pos,len + h.getDatasize(), new String[] {});
  17. splits.add(split);
  18. pos += 4;
  19. pos += len;
  20. pos += h.getDatasize();
  21. in.skip(h.getDatasize());
  22. }
  23. } catch (IOException e) {
  24. sLogger.error(e.getLocalizedMessage());
  25. } finally {
  26. if (in != null) {try {in.close();}catch(Exception e){}};
  27. if (fs != null) {try {fs.close();}catch(Exception e){}};
  28. }
  29. return splits;
  30. }

工作良好,迄今为止-虽然我还没有地面truthed输出尚未。它肯定比将pbf复制到hdfs、在一个Map器中转换成一个序列,然后摄取(复制时间占主导)要快得多。它也比在hdfs中使用外部程序拷贝到序列文件,然后针对hdfs运行Map程序(后者编写脚本)快20%。所以这里没有抱怨。
请注意,这将为每个块生成一个Map器,即行星世界文件的~23kMap器。实际上,我是在每次拆分时捆绑多个块—只需在拆分添加到集合之前循环x次。
对于blobheader,我刚刚从上面的osmwiki链接编译了protobuf.proto文件。如果需要,也可以从osm二进制类中提取预生成的-maven片段是:

  1. <dependency>
  2. <groupId>org.openstreetmap.osmosis</groupId>
  3. <artifactId>osmosis-osm-binary</artifactId>
  4. <version>0.43-RELEASE</version>
  5. </dependency>
展开查看全部

相关问题