如何在 Hive 中使用横向视图分解 XML 数据格式?
Posted
技术标签:
【中文标题】如何在 Hive 中使用横向视图分解 XML 数据格式?【英文标题】:How to use lateral view explode in Hive for XML data format? 【发布时间】:2018-11-20 00:54:50 【问题描述】:我正在尝试将 XML 格式的销售数据加载到 Hive 表中。 下面是数据的一个小样本。
我知道,如果我将以下数据分成几个表,然后根据需要将它们连接起来,我可以将其加载到 Hive。但只是想知道我是否可以将它们加载到单个表中,并且预期的输出应该类似于所附的屏幕截图。
请帮助我了解我应该使用的表格结构以及如何有效地使用横向视图分解选项来实现这一点。
样本数据:
<Store>
<Version>1.1</Version>
<StoreId>16695</StoreId>
<Bskt>
<TillNo>4</TillNo>
<BsktNo>1753</BsktNo>
<DateTime>2017-10-31T11:19:34.000+11:00</DateTime>
<OpID>50056</OpID>
<Itm>
<ItmSeq>1</ItmSeq>
<GTIN>29559</GTIN>
<ItmDsc>CHOCALATE</ItmDsc>
<ItmProm>
<PromCD>CM</PromCD>
</ItmProm>
</Itm>
<Itm>
<ItmSeq>2</ItmSeq>
<GTIN>59653</GTIN>
<ItmDsc>CORN FLAKES</ItmDsc>
</Itm>
<Itm>
<ItmSeq>3</ItmSeq>
<GTIN>42260</GTIN>
<ItmDsc> MILK CHOCOLATE 162GM</ItmDsc>
<ItmProm>
<PromCD>MTSRO</PromCD>
<OfferID>11766</OfferID>
</ItmProm>
</Itm>
</Bskt>
<Bskt>
<TillNo>5</TillNo>
<BsktNo>1947</BsktNo>
<DateTime>2017-10-31T16:24:59.000+11:00</DateTime>
<OpID>50063</OpID>
<Itm>
<ItmSeq>1</ItmSeq>
<GTIN>24064</GTIN>
<ItmDsc>TOMATOES 2KG</ItmDsc>
<ItmProm>
<PromCD>INSTORE</PromCD>
</ItmProm>
</Itm>
<Itm>
<ItmSeq>2</ItmSeq>
<GTIN>81287</GTIN>
<ItmDsc>ROTHMANS BLUE</ItmDsc>
<ItmProm>
<PromCD>TF</PromCD>
</ItmProm>
</Itm>
</Bskt>
</Store>
期望的输出
enter image description here
表结构:
CREATE EXTERNAL TABLE IF NOT EXISTS POC_BASKET_ITEM_PROMO (
`Version` string,
`StoreId` string,
`DateTime` array<string>,
`BsktNo` array<double>,
`TillNo` array<int>,
`Item_Seq_num` array<int>,
`GTIN` array<string>,
`ItmDsc` array<string>,
`Promo_CD` array<string>,
`Offer_ID` array<int>
)
ROW FORMAT SERDE 'com.ibm.spss.hive.serde2.xml.XmlSerDe'
WITH SERDEPROPERTIES (
"column.xpath.Version"="/Store/Version/text()",
"column.xpath.StoreId"="/Store/StoreId/text()",
"column.xpath.DateTime"="/Store/Bskt/DateTime/text()",
"column.xpath.BsktNo"="/Store/Bskt/BsktNo/text()",
"column.xpath.TillNo"="/Store/Bskt/TillNo/text()",
"column.xpath.Item_Seq_num"="/Store/Bskt/Itm/ItmSeq/text()",
"column.xpath.GTIN"="/Store/Bskt/Itm/GTIN/text()",
"column.xpath.ItmDsc"="/Store/Bskt/Itm/ItmDsc/text()",
"column.xpath.Promo_CD"="/Store/Bskt/Itm/ItmProm/PromCD/text()",
"column.xpath.Offer_ID"="/Store/Bskt/Itm/ItmProm/OfferID/text()"
)
STORED AS INPUTFORMAT 'com.ibm.spss.hive.serde2.xml.XmlInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION 'hdfs://namenode:8020/DEV/TEST/nanda_test'
TBLPROPERTIES (
"xmlinput.start"="<Store","xmlinput.end"="</Store>"
);
输出: enter image description here
尝试下面的查询来读取数据,它没有以我想要的方式显示结果。
select Version,StoreId,basket_dtm,basket_number,till_number from POC_BASKET_ITEM_PROMO
LATERAL VIEW explode(DateTime) table1 as basket_dtm
LATERAL VIEW explode(BsktNo) table2 as basket_number
LATERAL VIEW explode(TillNo) table3 as till_number;
结果:
enter image description here
【问题讨论】:
到目前为止您尝试过什么?你有什么错误吗? 我已经创建了上面的表结构,并将所有数据加载到一行中。现在我需要正确分解数组以获得截图中附加的输出。我不熟悉爆炸选项,只是想知道我该怎么做 有什么方法可以使用 XML 的 XSD 模式文件并将数据加载到 HIve 表中。就像我们对具有 AVRO 模式的 AVRO 文件所做的那样?如果可以的话,那就太好了。 我相信我需要使我的查询更好以获得所需的输出,非常感谢任何帮助。 【参考方案1】:数组对象的分解类似于交叉连接。 因此,如果您有 3 列,每列包含 2 个元素的数组,则对所有列应用 explode 将为您提供 8 行。
您不能将一个对象从数组映射到另一个对象。
实际上,您可以使用posexplode
,它为每个元素提供index
。您可以根据条件使用它来加入。但是,当您有多个列并且每列的数组大小不同时,这很棘手。
解决方案
如果要分解的列较少且数组大小相同,请使用posexplode
。对于你的情况,这是行不通的。所以
将 XML 存储为复杂数据类型:将整个 XML 存储为复杂数据类型(不仅仅是数组),我说的是基于您的 xml 创建一个 struct
。
如果你没有太多复杂的xml,你可以做到这一点。然而,xmlSerde
在将文件转换为复杂数据类型时不如JSONserde
好。
所以在你的情况下最好的解决方案是。
将您的 XML 转换为 JSON。您可以为此使用NiFi
或其他一些技术。
使用JSONserde
创建 Hive 表并加载此文件。
根据您的要求创建视图。
为您的 XML 提供 JSON
"Version":"1.1","StoreId":"16695","Bskt":["TillNo":"4","BsktNo":"1753","DateTime":"2017-10-31T11:19:34.000+11:00","OpID":"50056","Itm":["ItmSeq":"1","GTIN":"29559","ItmDsc":"CHOCALATE","ItmProm":"PromCD":"CM","ItmSeq":"2","GTIN":"59653","ItmDsc":"CORNFLAKES","ItmSeq":"3","GTIN":"42260","ItmDsc":"MILKCHOCOLATE162GM","ItmProm":"PromCD":"MTSRO","OfferID":"11766"],"TillNo":"5","BsktNo":"1947","DateTime":"2017-10-31T16:24:59.000+11:00","OpID":"50063","Itm":["ItmSeq":"1","GTIN":"24064","ItmDsc":"TOMATOES2KG","ItmProm":"PromCD":"INSTORE","ItmSeq":"2","GTIN":"81287","ItmDsc":"ROTHMANSBLUE","ItmProm":"PromCD":"TF"]]
JsonSerde
如果您的文件中有制表符或其他空格,则可能会出现错误。所以最好删除它们。
蜂巢表
create external table temp.test_json
(
Version string,
StoreId string,
Bskt array<struct<
BsktNo:string,
DateTime:string,
OpID:string,
TillNo:string,
Itm:array<struct<
GTIN:string,
ItmDsc:string,
ItmSeq:string,
ItmProm:struct<
OfferID:string,
PromCD:string
>
>
>
>
>
)
row format serde 'org.openx.data.jsonserde.JsonSerDe'
location '/tmp/test_json/table/';
创建视图
SELECT Version,
StoreId,
basket.bsktno,
basket.tillno,
basket.`datetime`,
item.itmseq,
item.itmdsc,
item.gtin,
item.itmprom.offerid,
item.itmprom.promcd
FROM temp.test_json
lateral view explode(bskt) b AS basket
lateral view explode(basket.itm) i AS item
【讨论】:
【参考方案2】:感谢详细的解决方案。我测试了它,它工作得非常好。 我尝试了一种类似的方法,直接使用 XML serde 从 XML 中读取数据。
我的挑战:
1)XML to JSON conversion takes additional development efforts and we don't have Apache Nifi installation parcels in Cloudera by default, we need to install it with custom parcels.
2) My data will definitely have spaces/tab spaces in it, especially in 'Item description' field.We need to load the data with the same names as we receive. So converting to JSON and use the 'org.openx.data.jsonserde.JsonSerDe' didn't help. Queries failed with errors as suggested by you.
下面是 Hive 表结构和我用来读取数据的查询。 我能够成功地爆炸第一级阵列(Bskt)而没有任何问题。
但是当我尝试分解第二级数组 (Itm) 时,它会为“Itm”中的所有字段返回 NULL 结果。
我的查询或表结构本身有什么问题吗?
create external table nanda_scan_xml (
Version string,
StoreId string,
Bskt array<struct<
Bskt:struct<
DateTime:string,
TillNo:string,
BsktNo:string,
Itm:array<struct<
Itm:struct<
ItmSeq:string,
GTIN:string,
ItmDsc:string,
DeptCD:string,
ItmCD:string,
SalesQTY:string,
SalesExGST:string,
Points:string,
CostExGST:string,
GSTRate:string,
DiscAmtExGST:string,
ItmProm:struct<
PromCD:string,
OfferID:string
>
>
>
>
>
>
>
)
row format serde 'com.ibm.spss.hive.serde2.xml.XmlSerDe'
with serdeproperties
(
"column.xpath.Version" = "/Store/Version/text()",
"column.xpath.StoreId" = "/Store/StoreId/text()",
"column.xpath.Bskt" = "/Store/Bskt"
)
stored as
inputformat 'com.ibm.spss.hive.serde2.xml.XmlInputFormat'
outputformat 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION 'hdfs://namenode/LandingArea/Sources/SCANP/IGA_SCAN/STAGING/'
tblproperties
(
"xmlinput.start" = "<Store>",
"xmlinput.end" = "</Store>"
);
查询:
1)对于工作正常的 Bskt:
SELECT Version,
StoreId,
basket.Bskt.DateTime,
basket.Bskt.bsktno,
basket.Bskt.tillno
FROM eim_stg.nanda_scan_xml
LATERAL VIEW EXPLODE(Bskt) b AS basket;
结果:
enter image description here 2) 尝试在单个查询中分解两个横向视图时:
SELECT Version,
StoreId,
basket.Bskt.DateTime,
basket.Bskt.bsktno,
basket.Bskt.tillno,
item.Itm.ItmSeq,
item.Itm.ItmDsc,
item.Itm.GTIN,
item.Itm.itmprom.OfferID,
item.Itm.itmprom.PromCD
FROM eim_stg.nanda_scan_xml
LATERAL VIEW EXPLODE(Bskt) b AS basket
LATERAL VIEW EXPLODE(basket.Bskt.Itm) i AS item limit 100;
结果:
enter image description here
3) 查询:
SELECT Version,
StoreId,
basket.Bskt.DateTime,
basket.Bskt.bsktno,
basket.Bskt.tillno,
item.Itm.ItmSeq,
item.Itm.ItmDsc,
item.Itm.GTIN,
item.Itm.itmprom.OfferID,
item.Itm.itmprom.PromCD
FROM eim_stg.nanda_scan_xml
LATERAL VIEW EXPLODE(Bskt) b AS basket
LATERAL VIEW EXPLODE(basket.Itm) i AS item limit 100;
错误:
enter image description here
【讨论】:
如果你能得到复杂数据类型的xml表。没有任何问题。只是 XML serde 没有 JSON 成熟以上是关于如何在 Hive 中使用横向视图分解 XML 数据格式?的主要内容,如果未能解决你的问题,请参考以下文章