将 Hive 订单与客户数据关联

大数据Beginner
立即练习

介绍

零售商的订单告诉你卖出了什么,但每个客户的地区保存在另一张表里。把地区文本复制到每个订单会重复信息。你可以在查询时,将订单的客户标识符连接到客户记录。这个操作称为关联(join)。

你将检查关系两侧的数据,为已付款订单补充地区,探索客户无法匹配时会发生什么,并构建地区收入报表。关联需要有意义的匹配规则:没有规则,不相关的行可能组合起来,夸大报表数值。预置客户表中,每个客户标识符恰好只有一行,因此每个能匹配的订单都只有一个客户匹配。

本实验独立准备六个干净订单、两个客户,以及单独的缺失匹配示例。Hive 和 Beeline 已就绪。你应该了解 SELECT、WHERE、分组和十进制销售计算;这里会介绍关联语法。无需 Java、Python 或其他实验的文件。请使用终端。

找到匹配键

在这一步中,你将辨认两张表如何描述同一批客户。先进入本地工作目录:

cd /home/labex/project

查看提供的订单和客户记录:

cat /home/labex/project/data/orders.csv
cat /home/labex/project/data/customers.csv

订单中的 customer_id 会重复,因为一个客户可能下多个订单。客户表中每个 customer_id 只有一条记录,c1 位于 East(东区),c2 位于 West(西区)。这个标识符就是关联键(join key)。相同的行位置或看起来相似的名称,都不是可靠的匹配规则。

通过 Hive 读取并保存客户对照表。Beeline 的 -u 选择服务,-n 选择用户名,-e 指定 SQL 语句。TSV 输出和禁用表头使结果行容易保存;> 替换指定本地文件:

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -e "SELECT customer_id, region FROM retail_joins.customers ORDER BY customer_id;" > /home/labex/project/output/customers.tsv
cat /home/labex/project/output/customers.tsv

预期为两行以制表符分隔的 c1 East 和 c2 West。现在你可以预测订单 o1 的匹配:它的 c1 标识符连接到 East。o2 的 c2 则连接到 West。这种表通常称为维表(dimension table)或对照表,因为它为订单记录补充描述性背景。

本练习提供唯一的对照键。真实数据集中,重复客户键可能使每个订单产生多个关联行,夸大收入;了解预期关系是验证关联的一部分。

使用 INNER JOIN 补充已付款订单

在这一步中,你将为每个已付款订单添加地区。orders o 为表提供简短的别名 o,customers c 为另一张表提供别名 c。o.customer_id 这样的引用说明列来自哪张表,尤其适合两表具有同名列的情况。

INNER JOIN 保留两侧都有匹配的行。明确的 ON o.customer_id = c.customer_id 条件给出匹配规则。使用 here-document 保存完整查询:Shell 会把带引号的开始标记 SQL 与最后 SQL 之间的各行原样写入文件:

cat > /home/labex/project/queries/enriched-orders.sql <<'SQL'
SELECT o.order_id, o.customer_id, c.region,
       o.quantity * o.unit_price AS order_amount
FROM retail_joins.orders o
INNER JOIN retail_joins.customers c ON o.customer_id = c.customer_id
WHERE o.order_status = 'paid'
ORDER BY o.order_id;
SQL
beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -f /home/labex/project/queries/enriched-orders.sql > /home/labex/project/output/enriched-orders.tsv
cat /home/labex/project/output/enriched-orders.tsv

文件执行选项 -f 运行已保存 SQL。预期有四行:

订单 客户 地区 金额
o1 c1 East 20.00
o2 c2 West 25.00
o4 c1 East 50.00
o6 c2 West 30.00

四个已付款订单都各找到一个客户。关联增加了描述信息,没有改变计算金额;总金额仍为 125.00。INNER JOIN 会丢弃没有客户匹配的订单。接下来将单独观察这种情况,保持干净报表数据不变。

使用 LEFT JOIN 保留未匹配订单

在这一步中,你将通过一个独立小例子比较两种关联。读取它的两条记录:

cat /home/labex/project/data/example-orders.csv

example1 引用 c1,example2 引用没有对照记录的 c_missing。运行之前,先预测 INNER JOIN 结果:

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -e "SELECT o.order_id, o.customer_id, c.region
FROM retail_joins.example_orders o
INNER JOIN retail_joins.customers c ON o.customer_id = c.customer_id
ORDER BY o.order_id;" > /home/labex/project/output/example-inner.tsv
cat /home/labex/project/output/example-inner.tsv

应该只出现 example1,地区为 East。未匹配订单消失了,因为 INNER JOIN 要求匹配。

LEFT JOIN 保留左侧表的每一行,即使右侧没有匹配键。缺少右侧记录提供的列会变为 NULL。只修改关联类型:

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -e "SELECT o.order_id, o.customer_id, c.region
FROM retail_joins.example_orders o
LEFT JOIN retail_joins.customers c ON o.customer_id = c.customer_id
ORDER BY o.order_id;" > /home/labex/project/output/example-left.tsv
cat /home/labex/project/output/example-left.tsv

现在预期有两行:example1/c1/East 和 example2/c_missing/NULL。NULL 描述缺少对照匹配,不是一个名为“NULL”的已知地区。原始客户标识符从左表保留下来,有助于辨认尚未解决的客户。

选择 INNER JOIN 还是 LEFT JOIN 是业务决策。对干净且全部匹配的数据生成完整地区报表时,可以使用 INNER JOIN;数据质量审核可能需要 LEFT JOIN 保留未解决记录。示例表独立于 orders,因此不会改变六行销售数据或其收入。

核对地区销售报表

在这一步中,你将对已补充信息的记录应用学过的分组。关联提供地区,WHERE 选择已付款订单,GROUP BY 按地区合并订单。增加聚合时,仍应保留明确的匹配条件:

cat > /home/labex/project/queries/regional-sales.sql <<'SQL'
SELECT c.region, SUM(o.quantity * o.unit_price) AS revenue
FROM retail_joins.orders o
INNER JOIN retail_joins.customers c ON o.customer_id = c.customer_id
WHERE o.order_status = 'paid'
GROUP BY c.region
ORDER BY c.region;
SQL
beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -f /home/labex/project/queries/regional-sales.sql > /home/labex/project/output/regional-sales.tsv
cat /home/labex/project/output/regional-sales.tsv

预期 East 为 70.00,West 为 55.00,合计与未关联源数据的已付款收入 125.00 一致。唯一客户键和完整匹配意味着没有已付款订单被重复扩增或丢失。

做一个小练习:预测只有 10 月 14 日时的地区金额。将已学日期条件应用到分组前的订单行:

cat > /home/labex/project/queries/regional-sales-one-day.sql <<'SQL'
SELECT c.region, SUM(o.quantity * o.unit_price) AS revenue
FROM retail_joins.orders o
INNER JOIN retail_joins.customers c ON o.customer_id = c.customer_id
WHERE o.order_status = 'paid' AND o.order_date = DATE '2026-10-14'
GROUP BY c.region
ORDER BY c.region;
SQL
beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -f /home/labex/project/queries/regional-sales-one-day.sql > /home/labex/project/output/regional-sales-one-day.tsv
cat /home/labex/project/output/regional-sales-one-day.tsv

金额现在应该为 East 20.00、West 25.00,合计与当天的 45.00 一致。匹配规则没有改变,只有所选订单行改变。主文件 regional-sales.sql 保留完整的两日报表。

现在,你既能解释新增的描述列,也能解释未改变的业务总计。接下来,日期分区将把这些 SQL 日期条件与每日文件的组织和注册方式联系起来。

总结

你用唯一客户键匹配订单,通过别名明确表达关系,并比较了缺失匹配时 INNER JOIN 和 LEFT JOIN 的行为。随后,你将地区已付款销售总计与源数据对账,并在不改变关联的情况下修改日期条件。接下来,你将使用 Hive 分区元数据组织每日数据。