如何使用Hadoop将XML转换为TSV?

时间:2011-01-14 22:41:00

标签: ruby xml hadoop tsv

我有一个非常简单的格式化XML文档,我想将其转换为适合导入Hive的TSV。这份文件的格式很简单:

<root>
   <row>
      <ID>0</ID>
      <ParentID>0</ParentID>
      <Url></Url>
      <Title></Title>
      <Text></Text>
      <Username></Username>
      <Points>0</Points>
      <Type>0</Type>
      <Timestamp></Timestamp>
      <CommentCount>0</CommentCount>
   </row>
</root>

我有一个可用的Ruby脚本,可以将上面格式化的文档正确地转换为TSV。就在这里:

require "rubygems"
require "crack"

xml = Crack::XML.parse(File.read("sample.xml"))

xml['root']['row'].each{ |i|
  puts "#{i['ID']}      #{i['ParentID']}        #{i['Url']}     #{i['Title']}..." 
}

不幸的是,我需要翻译的文件比这个脚本可以处理的文件大得多(> 1 GB)。

Hadoop的用武之地。最简单的解决方案可能是用Java编写MapReduce作业,但鉴于我缺乏Java技能,这不是一个选择。所以我想在Python或Ruby中编写一个mapper脚本,我远非专家,但至少可以导航。

我的计划是做以下事情:

  1. 使用StreamXmlRecordReader按记录解析文件记录
  2. 使用crack映射反序列化
  3. 通过选项卡间隔的元素的简单反流来减少它
  4. 然而,这种方法一直失败。我使用了各种Ruby / Wukong脚本但没有成功。这是一篇基于文章here的文章:

    #!/usr/bin/env ruby
    
    require 'rubygems'
    require 'crack'
    
    xml = nil
    STDIN.each_line do |line|
      puts |line|
      line.strip!
    
      if line.include?("<row")
        xml = Crack::XML.parse(line)
        xml['root']['row'].each{ |i|
          puts "#{i['ID']}      #{i['ParentID']}        #{i['Url']}..."     
      else
        puts 'no line'
      end
    
      if line.include?("</root>")
        puts 'EOF'
      end
    end
    

    此工作和其他工作失败如下:

    hadoop jar /usr/lib/hadoop-0.20/contrib/streaming/hadoop-streaming-0.20.2+737.jar -input /hackernews/Datasets/sample.xml -output out -mapper mapper.rb -inputreader "StreamXmlRecordReader,begin=<row,end=</row>"
    packageJobJar: [/var/lib/hadoop-0.20/cache/sog/hadoop-unjar1519776523448982201/] [] /tmp/streamjob2858887307771024146.jar tmpDir=null
    11/01/14 17:29:17 INFO mapred.FileInputFormat: Total input paths to process : 1
    11/01/14 17:29:17 INFO streaming.StreamJob: getLocalDirs(): [/var/lib/hadoop-0.20/cache/sog/mapred/local]
    11/01/14 17:29:17 INFO streaming.StreamJob: Running job: job_201101141647_0001
    11/01/14 17:29:17 INFO streaming.StreamJob: To kill this job, run:
    11/01/14 17:29:17 INFO streaming.StreamJob: /usr/lib/hadoop-0.20/bin/hadoop job  -Dmapred.job.tracker=localhost:8021 -kill job_201101141647_0001
    11/01/14 17:29:17 INFO streaming.StreamJob: Tracking URL: http://localhost:50030/jobdetails.jsp?jobid=job_201101141647_0001
    11/01/14 17:29:18 INFO streaming.StreamJob:  map 0%  reduce 0%
    11/01/14 17:30:05 INFO streaming.StreamJob:  map 100%  reduce 100%
    11/01/14 17:30:05 INFO streaming.StreamJob: To kill this job, run:
    11/01/14 17:30:05 INFO streaming.StreamJob: /usr/lib/hadoop-0.20/bin/hadoop job  -Dmapred.job.tracker=localhost:8021 -kill job_201101141647_0001
    11/01/14 17:30:05 INFO streaming.StreamJob: Tracking URL: http://localhost:50030/jobdetails.jsp?jobid=job_201101141647_0001
    11/01/14 17:30:05 ERROR streaming.StreamJob: Job not Successful!
    11/01/14 17:30:05 INFO streaming.StreamJob: killJob...
    Streaming Command Failed!
    

    第一个问题是我无法分辨我失败的地方:我的脚本或StreamXmlRecordReader。

    第二个问题是,一位亲切而乐于助人的专家告诉我,因为StreamXmlRecordReader没有产生额外的记录分隔符,这种方法可能不会起作用,而且我需要单一阅读行,grep for row,堆叠所有内容,直到你得到/ row,然后解析它。

    这是最简单的方法,如果是这样,我最好如何做到这一点?

    性能不是一个大问题,因为这些文件每隔几周左右就会批量处理,以防万一。

2 个答案:

答案 0 :(得分:1)

如果你遇到这个问题,那么Infochimps的人们就解决了这个问题。这是必要的悟空剧本:

http://thedatachef.blogspot.com/2011/01/processing-xml-records-with-hadoop-and.html

答案 1 :(得分:0)

一个常常的错误就是没有脚本的执行权限“chmod a + x mapper.rb”试一试。

查看您的工作跟踪器日志以明确获取错误。您还可以从http://namenode:50030/jobtracker.jsp点击失败的作业,然后在地图上的“失败/被杀死的任务尝试”中的“失败”中获取信息。

此外,当您运行流作业时,在选项行上放置“-verbose”,可能会提供更多信息。