2

我有一个格式非常简单的 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 编写一个映射器脚本,我远非专家,但至少可以导航。

我当时的计划是做以下事情:

  1. 使用 StreamXmlRecordReader 逐条解析文件记录
  2. 使用破解映射反序列化
  3. 用制表符隔开的元素的简单反刍来减少它

然而,这种方法一直失败。我使用了各种 Ruby/Wukong 脚本,但都没有成功。这是一个基于这里的文章

#!/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对于行,将所有内容堆叠起来,直到获得 /row,然后对其进行解析。

这是最简单的方法吗?如果是,我如何才能最好地做到这一点?

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

4

2 回答 2

1

如果你有这个问题,Infochimps 的人已经解决了。这是必要的 Wukong 脚本:

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

于 2011-01-17T21:10:18.337 回答
0

一个经常出现的错误是您的脚本“chmod a+x mapper.rb”没有执行权限,请尝试一下。

查看您的工作跟踪器日志以具体了解错误。您还可以从http://namenode:50030/jobtracker.jsp获取信息,单击失败的作业,然后单击地图的“失败/终止任务尝试”中的“失败”。

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

于 2011-01-17T02:23:48.900 回答