使用 hive 解析 XML 中的多次出现问题
Posted
技术标签:
【中文标题】使用 hive 解析 XML 中的多次出现问题【英文标题】:Multiple occurance issue in XML Parsing using hive 【发布时间】:2016-05-25 14:31:36 【问题描述】:我正在尝试使用 com.ibm.spss.hive.serde2.xml.XmlSerDe 从 XML 文件中创建 Hive 表。这对于单次出现的标签非常有效。但我有一个多次出现的问题。
下面是我的源 XML。
<Item>
<TimeStamp>2016-02-19T12:27:06.387Z</TimeStamp>
<AlsoSeen End="2014-08-21T13:44:32.557Z" Start="2014-08-21T13:44:04.637Z" />
<AlsoSeen End="2014-08-21T13:44:33.557Z" Start="2014-08-21T13:45:04.637Z" />
<AlsoSeen End="2014-08-21T13:44:34.557Z" Start="2014-08-21T13:46:04.637Z" />
<Title ID="112031424">FAULT IN OUR STARS, THE</Title>
<FileName>The Fault in Our Stars (2014) EXTENDED HDRip x264 AAC-CPG</FileName>
</Item>
下面是我的 Hive Table DDL
add jar hivexmlserde-1.0.5.3.jar;
CREATE EXTERNAL TABLE xml_test
(
Item_TimeStamp String
,Item_AS_Start String
,Item_AS_End String
,Item_Title String
,Item_ID String
,Item_Artist String
,Item_Author String
,Item_FileName String
)
ROW FORMAT SERDE 'com.ibm.spss.hive.serde2.xml.XmlSerDe'
WITH SERDEPROPERTIES (
"column.xpath.Item_TimeStamp"="/Item/TimeStamp/text()",
"column.xpath.Item_AS_Start"="/Item/AlsoSeen/@Start",
"column.xpath.Item_AS_End"="/Item/AlsoSeen/@End",
"column.xpath.Item_Title"="/Item/Title/text()",
"column.xpath.Item_ID"="/Item/Title/@ID",
"column.xpath.Item_FileName"="/Item/FileName/text()"
)
STORED AS
INPUTFORMAT 'com.ibm.spss.hive.serde2.xml.XmlInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat'
LOCATION '/user/xxxxxx/XML_text'
TBLPROPERTIES (
"xmlinput.start"="<Item>",
"xmlinput.end"="</Item>"
);
当我查询表格时,我得到以下值
2016-02-19T12:27:06.387Z <string>2014-08-21T13:44:04.637Z2014-08-21T13:45:04.637Z2014-08-21T13:46:04.637Z</string> <string>2014-08-21T13:44:32.557Z2014-08-21T13:44:33.557Z2014-08-21T13:44:34.557Z</string> FAULT IN OUR STARS, THE 112031424 The Fault in Our Stars (2014) EXTENDED HDRip x264 AAC-CPG
但我预计输出应该是 3 个不同的行,用于 3 个不同出现的 AlsoSeen 标签,如下所示
2016-02-19T12:27:06.387Z 2014-08-21T13:44:04.637Z 2014-08-21T13:44:32.557Z FAULT IN OUR STARS, THE 112031424 The Fault in Our Stars (2014) EXTENDED HDRip x264 AAC-CPG
2016-02-19T12:27:06.387Z 2014-08-21T13:45:04.637Z 2014-08-21T13:44:33.557Z FAULT IN OUR STARS, THE 112031424 The Fault in Our Stars (2014) EXTENDED HDRip x264 AAC-CPG
2016-02-19T12:27:06.387Z 2014-08-21T13:46:04.637Z 2014-08-21T13:44:34.557Z FAULT IN OUR STARS, THE 112031424 The Fault in Our Stars (2014) EXTENDED HDRip x264 AAC-CPG
谁能帮帮我?
【问题讨论】:
我对 SerDe 一无所知,但表达式确实看起来像 XPath;所以/Item/AlsoSeen[2]/@Start
会给你在每个元素<Item>
内第二次出现元素<AlsoSeen>
的属性。但是 AFAIK 你不能用 XPath 迭代,你需要 Java 代码——或者一个 XSLT 样式表。
顺便说一句,从结果来看,我猜 SerDe 会为所有 XPath 表达式找到“最细粒度的公共元素”,假设它意味着 一条记录,然后从拆分源开始在将每个 XPath 表达式输入列(即单元格)之前,“记录”中的 XML。
所以我建议您在将 XML 加载到 Hadoop 之前对其进行转换。使用 Linux 实用程序xsltproc
和一个简单的 XSLT 脚本,您可以获得一个包含 1 列的 CSV,其中所有“开始”属性由空格 分隔(对于自定义分隔符,您需要一个符合 XSLT 2 的解析器,即 Saxon ) -- 然后你可以在 Hive 中读取 CSV 并将数组“分解”成多行。多个数组更棘手,但可以通过“索引爆炸”来完成,并通过仅选择具有匹配索引的开始和结束值来过滤掉笛卡尔混乱。
@SamsonScharfrichter 你说得对,它是 Xpath。 Xpath 支持像 *
、 @*
和 node()
这样的通配符,它们将匹配多个值。 SerDe 是 HIVE 的 Java 库约定,用于对数据进行序列化和反序列化,并且有许多文件格式的 SerDe。 Hive 可以使用 'delimited by' 或 SerDe 来定义文件格式。在这种情况下,XML SerDe 将进行迭代。源代码在这里:github.com/dvasilen/Hive-XML-SerDe。我很惊讶这个例子有效,请参阅下面的答案。
【参考方案1】:
文档对此有一些示例。 https://github.com/dvasilen/Hive-XML-SerDe/wiki/XML-data-sources
使用text()
或@Elementname
为您提供单个(原始)值,并且您的表已被声明为所有STRING
列,您可能需要复杂类型来保存多个值,即Map、Struct 或Array .
您看到的行为与上述链接中的文档中的(5. 复杂类型)有关。
"被用作原始类型的复杂内容将被转换为 通过添加名为
<string>
"的根元素来获得有效的 XML 字符串
在您的示例中,您看到的结果是 @Start 属性的 3 个值连接起来,然后用 <string>
标记包装:
<string>2014-08-21T13:44:04.637Z2014-08-21T13:45:04.637Z2014-08-21T13:46:04.637Z</string>
您的 XPath 使用的是 @Start
和 @End
,而不是 /*
模式,所以我很惊讶它完全有效。
我了解您想要的结果,但我不确定它是否真的与数据建模方式相匹配。我认为<Item>
实际上是单行。 Item 有一个<TimeStamp>
和一个<Title>
,它有一个@ID 属性,它还有一个名为<AlsoSeen>
的属性,它可以有多个@End 和@Start 值。从 XML 到 Hive 表的直接映射可能是这种复杂的数据类型:
ARRAY<STRUCT<End: TIMESTAMP, Start: TIMESTAMP>>
,包含结束和开始时间戳的结构数组。
很遗憾,您的数据不符合 Hive 期望的时间戳字符串格式,因此您可以使用 STRING,如 https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-timestamp
所以你最终会得到这个表创建语句(我已经删除了原始创建表中的 Item_Artist 和 Item_Author,因为你在 SERDEPROPERTIES 中没有与这些列匹配的 xpath)
CREATE EXTERNAL TABLE xml_test
(
Item_TimeStamp String
,Item_AlsoSeen ARRAY<STRUCT<End: STRING, Start: STRING>>
,Item_Title String
,Item_ID String
,Item_FileName String
)
ROW FORMAT SERDE 'com.ibm.spss.hive.serde2.xml.XmlSerDe'
WITH SERDEPROPERTIES (
"column.xpath.Item_TimeStamp"="/Item/TimeStamp/text()",
"column.xpath.Item_AlsoSeen"="/Item/AlsoSeen",
"column.xpath.Item_Title"="/Item/Title/text()",
"column.xpath.Item_ID"="/Item/Title/@ID",
"column.xpath.Item_FileName"="/Item/FileName/text()"
)
STORED AS
INPUTFORMAT 'com.ibm.spss.hive.serde2.xml.XmlInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat'
LOCATION '/user/xxxxxx/XML_text'
TBLPROPERTIES (
"xmlinput.start"="<Item>",
"xmlinput.end"="</Item>"
);
注意我用于 AlsoSeen 字段的 xpath:"/Item/AlsoSeen"
这是上面链接的文档中的数组和结构的模式。
它会给你类似的结果
+--------------------+--------------------+--------------------+---------+--------------------+
| Item_TimeStamp| Item_AlsoSeen| Item_Title| Item_ID| Item_FileName|
+--------------------+--------------------+--------------------+---------+--------------------+
|2016-02-19T12:27:...|[[2014-08-21T13:4...|FAULT IN OUR STAR...|112031424|The Fault in Our ...|
+--------------------+--------------------+--------------------+---------+--------------------+
Item_AlsoSeen 列包含这个,一个由逗号分隔的 Structs [] 的 Array(),每个结构都有结束和开始。
WrappedArray([2014-08-21T13:44:32.557Z,2014-08-21T13:44:04.637Z], [2014-08-21T13:44:33.557Z,2014-08-21T13:45:04.637Z], [2014-08-21T13:44:34.557Z,2014-08-21T13:46:04.637Z])
从那里,您可以使用LATERAL VIEW explode()
技术查询您想要的结果集
例如
SELECT
Item_TimeStamp,
--Item_AlsoSeen,
ias.End,
ias.Start,
Item_Title,
Item_ID,
Item_FileName
FROM xml_test
LATERAL VIEW explode(Item_AlsoSeen) ias as ias
请注意,由于我将 AlsoSeen 创建为结构数组,explode()
函数将每个结构作为一行返回。 LATERAL VIEW
然后有效地进行交叉连接或可能更好地称为CROSS APPLY
以获得笛卡尔积。
+--------------------+--------------------+--------------------+--------------------+---------+--------------------+
| Item_TimeStamp| End| Start| Item_Title| Item_ID| Item_FileName|
+--------------------+--------------------+--------------------+--------------------+---------+--------------------+
|2016-02-19T12:27:...|2014-08-21T13:44:...|2014-08-21T13:44:...|FAULT IN OUR STAR...|112031424|The Fault in Our ...|
|2016-02-19T12:27:...|2014-08-21T13:44:...|2014-08-21T13:45:...|FAULT IN OUR STAR...|112031424|The Fault in Our ...|
|2016-02-19T12:27:...|2014-08-21T13:44:...|2014-08-21T13:46:...|FAULT IN OUR STAR...|112031424|The Fault in Our ...|
+--------------------+--------------------+--------------------+--------------------+---------+--------------------+
参考 Hive 数据类型:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types
【讨论】:
【参考方案2】:有自定义编写的 UDF,它们是 array_index , numeric_range 很容易解决问题。为了使用这些函数,列类型应该是一个数组。请参考帖子Hive Explode / Lateral View multiple arrays
【讨论】:
以上是关于使用 hive 解析 XML 中的多次出现问题的主要内容,如果未能解决你的问题,请参考以下文章