Hive实战:大数据仓库建设与数据分析应用
Hive实战:大数据仓库建设与数据分析应用
引言
痛点引入:为什么需要大数据仓库?
在数字化时代,企业的数据量呈爆炸式增长——用户行为日志、业务交易数据、物联网传感器数据等分散在各个系统中(比如MySQL、Redis、日志文件),像“数据孤岛”一样难以整合。传统的数据库(如MySQL)无法处理TB级以上的大规模数据,查询慢、扩展性差;而直接用Hadoop MapReduce写代码分析,又需要掌握复杂的Java编程,门槛高、效率低。
你是否遇到过这些问题?
- 想分析用户最近30天的购买行为,但原始日志分散在100个文件中,手动合并太麻烦;
- 业务部门要求“每天早上8点拿到前一天的日活数据”,但用Python处理100GB数据需要2小时,根本赶不上进度;
- 数据重复、缺失值多,分析结果总是不准确,不知道如何清洗?
解决方案:用Hive构建大数据仓库
Hive是基于Hadoop的数据仓库工具,它将结构化数据映射到HDFS上的文件,通过**类SQL(HQL)**语句实现对大规模数据的查询和分析。相比MapReduce,Hive的优势在于:
- 低门槛:用SQL就能处理大数据,不需要写Java代码;
- 高扩展性:依托Hadoop集群,支持PB级数据存储和计算;
- 灵活的数据模型:支持外部表、分区表、分桶表等,适应不同场景;
- 丰富的生态:整合Spark、Tez等计算引擎,支持Parquet、ORC等高效存储格式。
最终效果展示
假设我们是一家电商公司,通过Hive构建的数据仓库,能实现:
- 快速查询:用10秒内从1TB用户行为日志中算出“2023年10月1日的日活用户数(DAU)”;
- 多维度分析:关联用户表、商品表、订单表,分析“25-30岁女性用户最喜欢购买的TOP5商品类别”;
- 自动化流程:通过Airflow调度Hive作业,每天凌晨自动完成数据清洗、建模和分析,早上8点准时向业务部门推送报表。
准备工作:环境与基础知识
1. 所需环境
- Hadoop集群:Hive依赖HDFS存储数据,YARN负责资源管理。建议使用Hadoop 3.x版本(稳定且支持更多特性)。
- Hive安装:下载Hive 3.1.x版本(与Hadoop 3.x兼容),配置
hive-site.xml(指定元数据存储、HDFS路径等)。 - 元数据存储:默认用Derby,但生产环境建议用MySQL(支持多用户并发访问)。
- 辅助工具:Hue(Hadoop UI,方便操作Hive)、Airflow(任务调度)、Tableau(数据可视化)。
2. 基础知识要求
- Hadoop基础:了解HDFS(分布式存储)、YARN(资源管理)、MapReduce(分布式计算)的核心概念;
- SQL基础:掌握SELECT、JOIN、GROUP BY、函数(如COUNT、SUM)等基本语法;
- 数据仓库概念:了解分层架构(ODS、DWD、DWS、ADS)、维度建模(星型/雪花 schema)。
3. 环境搭建参考
- Hadoop集群搭建:官方文档;
- Hive安装配置:官方文档;
- MySQL作为元数据存储:修改
hive-site.xml中的javax.jdo.option.ConnectionURL为MySQL的连接地址,并添加驱动jar包到Hive的lib目录。
核心步骤:Hive大数据仓库建设实战
一、数据仓库设计:分层架构与模型设计
数据仓库的核心是分层,通过将数据按“原始-清洗-汇总-应用”的流程划分,实现“数据复用、效率提升、风险隔离”的目标。常见的分层架构如下:
| 层级 | 英文全称 | 作用 | 示例数据 |
|---|---|---|---|
| ODS | Operational Data Store | 原始数据层,存储未加工的原始数据(保留原始特征) | 用户行为日志(.log)、业务数据库导出(.csv) |
| DWD | Data Warehouse Detail | 明细数据层,对ODS数据进行清洗、结构化(去重、补缺失、格式转换) | 清洗后的用户行为表(user_behavior)、订单明细(order_detail) |
| DWS | Data Warehouse Summary | 汇总数据层,按主题(用户、商品、订单)进行聚合(天/周/月汇总) | 用户日活表(user_dau)、商品周销量表(product_week_sales) |
| ADS | Application Data Store | 应用数据层,面向具体业务需求(如报表、 dashboard) | 运营报表(operation_report)、用户留存率表(user_retention) |
1. ODS层设计:原始数据存储
ODS层的核心是**“保留原始数据”,避免后续处理破坏原始信息。通常使用外部表(EXTERNAL TABLE)**,因为外部表不管理数据的生命周期(数据存储在HDFS的指定路径,删除表不会删除数据),适合存储原始日志。
示例:创建ODS层用户行为日志表
-- 1. 创建外部表(存储原始日志)
CREATE EXTERNAL TABLE IF NOT EXISTS ods.user_behavior_log (
user_id STRING COMMENT '用户ID',
action_type STRING COMMENT '行为类型(click/purchase)',
product_id STRING COMMENT '商品ID',
action_time STRING COMMENT '行为时间(yyyy-MM-dd HH:mm:ss)',
ip STRING COMMENT '用户IP'
)
-- 指定数据存储路径(HDFS)
LOCATION '/user/hive/warehouse/ods/db/user_behavior_log'
-- 指定输入格式(日志文件通常用TextInputFormat)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t' -- 日志字段分隔符(根据实际情况调整)
-- 跳过首行(如果日志有表头)
TBLPROPERTIES ('skip.header.line.count'='1');
数据导入:用LOAD DATA语句将本地或HDFS中的日志文件导入ODS表:
-- 从HDFS导入(推荐,因为Hadoop集群读取HDFS更快)
LOAD DATA INPATH '/data/raw/user_behavior_2023-10-01.log'
OVERWRITE INTO TABLE ods.user_behavior_log;
2. DWD层设计:数据清洗与结构化
DWD层的核心是**“清洗与结构化”,解决数据中的脏数据**问题(缺失值、重复值、异常值)。常用的清洗操作包括:
- 去重:用
DISTINCT或ROW_NUMBER()窗口函数; - 补缺失值:用
COALESCE函数(如COALESCE(user_id, 'unknown')); - 格式转换:将字符串类型的时间转换为
TIMESTAMP(如FROM_UNIXTIME(UNIX_TIMESTAMP(action_time, 'yyyy-MM-dd HH:mm:ss'))); - 过滤异常值:用
WHERE条件(如action_time >= '2023-10-01'过滤无效时间)。
示例:创建DWD层用户行为明细桌
-- 1. 创建内部表(存储清洗后的数据)
CREATE TABLE IF NOT EXISTS dwd.user_behavior (
user_id STRING COMMENT '用户ID',
action_type STRING COMMENT '行为类型(click/purchase)',
product_id STRING COMMENT '商品ID',
action_time TIMESTAMP COMMENT '行为时间(转换为TIMESTAMP格式)',
ip STRING COMMENT '用户IP',
dt STRING COMMENT '分区字段(yyyy-MM-dd)' -- 按日期分区,提高查询效率
)
-- 指定存储格式(Parquet,列式存储,压缩率高,查询快)
STORED AS PARQUET
-- 按dt分区(每天的数据存储在不同的目录)
PARTITIONED BY (dt STRING)
-- 压缩设置(SNAPPY,平衡压缩率和速度)
TBLPROPERTIES ('parquet.compression'='SNAPPY');
-- 2. 从ODS层导入数据并清洗
INSERT OVERWRITE TABLE dwd.user_behavior PARTITION (dt)
SELECT
-- 去重:保留每个用户每个行为的最新记录(假设action_time唯一)
user_id,
action_type,
product_id,
-- 格式转换:将字符串转换为TIMESTAMP
FROM_UNIXTIME(UNIX_TIMESTAMP(action_time, 'yyyy-MM-dd HH:mm:ss')) AS action_time,
ip,
-- 提取日期作为分区字段(yyyy-MM-dd)
DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP(action_time, 'yyyy-MM-dd HH:mm:ss')), 'yyyy-MM-dd') AS dt
FROM ods.user_behavior_log
-- 过滤异常值:排除user_id为空或action_type无效的数据
WHERE user_id IS NOT NULL
AND action_type IN ('click', 'purchase')
-- 去重:同一用户同一时间的同一行为只保留一条
DISTINCT;
2. DWS层设计:主题汇总
DWS层的核心是**“按主题聚合”**,将DWD层的明细数据按用户、商品、订单等主题进行汇总(如天、周、月),减少后续分析的计算量。
示例:创建DWS层用户日活表(user_dau)
CREATE TABLE IF NOT EXISTS dws.user_dau (
dt STRING COMMENT '日期(yyyy-MM-dd)',
dau BIGINT COMMENT '日活用户数'
)
STORED AS PARQUET
TBLPROPERTIES ('parquet.compression'='SNAPPY');
-- 从DWD层聚合数据
INSERT OVERWRITE TABLE dws.user_dau
SELECT
dt,
COUNT(DISTINCT user_id) AS dau -- 计算日活(去重用户ID)
FROM dwd.user_behavior
GROUP BY dt;
3. ADS层设计:业务应用
ADS层的核心是**“面向业务需求”**,将DWS层的汇总数据进一步加工成业务报表或 dashboard 所需的格式。
示例:创建ADS层运营报表(operation_report)
CREATE TABLE IF NOT EXISTS ads.operation_report (
dt STRING COMMENT '日期(yyyy-MM-dd)',
dau BIGINT COMMENT '日活',
total_order BIGINT COMMENT '总订单数',
total_sales DECIMAL(10,2) COMMENT '总销售额',
avg_order_amount DECIMAL(10,2) COMMENT '平均订单金额'
)
STORED AS PARQUET
TBLPROPERTIES ('parquet.compression'='SNAPPY');
-- 关联DWS层用户日活表和订单表(假设订单表在DWS层)
INSERT OVERWRITE TABLE ads.operation_report
SELECT
a.dt,
a.dau,
b.total_order,
b.total_sales,
-- 计算平均订单金额(总销售额/总订单数,避免除以0)
CASE WHEN b.total_order > 0 THEN b.total_sales / b.total_order ELSE 0 END AS avg_order_amount
FROM dws.user_dau a
LEFT JOIN (
-- 从DWS层订单汇总表获取总订单数和总销售额
SELECT
dt,
COUNT(DISTINCT order_id) AS total_order,
SUM(order_amount) AS total_sales
FROM dws.order_summary
GROUP BY dt
) b ON a.dt = b.dt;
二、数据建模:维度建模与关联分析
数据仓库的建模方式主要有两种:维度建模(适合分析)和实体-关系建模(适合 transactional 系统)。Hive中常用维度建模,通过“事实表+维度表”的组合,支持多维度分析。
1. 事实表(Fact Table)
事实表存储业务事件的度量值(如订单金额、销量),通常包含:
- 维度外键(如user_id、product_id、time_id);
- 度量值(如order_amount、quantity)。
示例:订单事实表(order_fact)
CREATE TABLE IF NOT EXISTS dwd.order_fact (
order_id STRING COMMENT '订单ID',
user_id STRING COMMENT '用户ID(关联用户维度表)',
product_id STRING COMMENT '商品ID(关联商品维度表)',
time_id STRING COMMENT '时间ID(关联时间维度表)',
order_amount DECIMAL(10,2) COMMENT '订单金额',
quantity INT COMMENT '购买数量',
dt STRING COMMENT '分区字段(yyyy-MM-dd)'
)
STORED AS PARQUET
PARTITIONED BY (dt)
TBLPROPERTIES ('parquet.compression'='SNAPPY');
2. 维度表(Dimension Table)
维度表存储描述性信息(如用户属性、商品类别),用于过滤和分组。常见的维度表有:
- 时间维度表(time_dim):存储日期的详细信息(年、月、周、季度);
- 用户维度表(user_dim):存储用户属性(性别、年龄、注册时间);
- 商品维度表(product_dim):存储商品属性(类别、品牌、价格)。
示例:时间维度表(time_dim)
CREATE TABLE IF NOT EXISTS dim.time_dim (
time_id STRING COMMENT '时间ID(yyyy-MM-dd)',
year INT COMMENT '年',
month INT COMMENT '月',
day INT COMMENT '日',
week INT COMMENT '周(一年中的第几周)',
quarter INT COMMENT '季度(1-4)',
is_weekend BOOLEAN COMMENT '是否周末(TRUE/FALSE)'
)
STORED AS PARQUET
TBLPROPERTIES ('parquet.compression'='SNAPPY');
-- 插入数据(可以用Hive生成或从外部导入)
INSERT OVERWRITE TABLE dim.time_dim
SELECT
dt AS time_id,
YEAR(dt) AS year,
MONTH(dt) AS month,
DAY(dt) AS day,
WEEKOFYEAR(dt) AS week,
QUARTER(dt) AS quarter,
-- 判断是否周末(周六或周日)
CASE WHEN DAYOFWEEK(dt) IN (1,7) THEN TRUE ELSE FALSE END AS is_weekend
FROM (
-- 生成2023年全年的日期(示例)
SELECT DATE_ADD('2023-01-01', pos) AS dt
FROM (SELECT posexplode(sequence(0, 364)) AS (pos, val)) t
) d;
3. 关联分析:事实表与维度表JOIN
通过JOIN事实表和维度表,可以实现多维度分析。例如,分析“2023年第三季度,25-30岁女性用户购买的TOP5商品类别”:
SELECT
p.category AS product_category, -- 商品类别(来自商品维度表)
COUNT(DISTINCT o.order_id) AS order_count, -- 订单数
SUM(o.order_amount) AS total_sales -- 总销售额
FROM dwd.order_fact o
-- 关联用户维度表(获取用户年龄、性别)
JOIN dim.user_dim u ON o.user_id = u.user_id
-- 关联商品维度表(获取商品类别)
JOIN dim.product_dim p ON o.product_id = p.product_id
-- 关联时间维度表(获取季度)
JOIN dim.time_dim t ON o.time_id = t.time_id
WHERE
t.quarter = 3 -- 第三季度
AND u.gender = 'female' -- 女性用户
AND u.age BETWEEN 25 AND 30 -- 25-30岁
GROUP BY p.category
ORDER BY total_sales DESC
LIMIT 5; -- TOP5商品类别
三、数据分析应用:从需求到实现
Hive的核心价值在于用SQL解决大数据分析问题。以下是几个常见的业务场景示例:
1. 场景一:用户留存率分析
需求:计算2023年10月1日新增用户的7天留存率(即10月1日注册的用户中,10月8日仍活跃的比例)。
步骤:
- 定义“新增用户”:首次产生行为(如注册)的用户;
- 定义“活跃用户”:产生任何行为(如点击、购买)的用户;
- 计算留存率:(7天后活跃的新增用户数)/(新增用户总数)。
代码实现:
-- 1. 计算2023-10-01的新增用户(首次行为的用户)
WITH new_users AS (
SELECT
user_id,
MIN(action_time) AS first_action_time -- 首次行为时间
FROM dwd.user_behavior
WHERE dt = '2023-10-01' -- 2023-10-01的行为数据
GROUP BY user_id
HAVING first_action_time >= '2023-10-01 00:00:00'
AND first_action_time < '2023-10-02 00:00:00' -- 首次行为在10月1日当天
),
-- 2. 计算2023-10-08的活跃用户(10月8日有行为的用户)
active_users_7d AS (
SELECT DISTINCT user_id
FROM dwd.user_behavior
WHERE dt = '2023-10-08' -- 2023-10-08的行为数据
)
-- 3. 计算7天留存率
SELECT
COUNT(DISTINCT nu.user_id) AS new_user_count, -- 新增用户总数
COUNT(DISTINCT au.user_id) AS retained_user_count, -- 7天留存用户数
-- 留存率(保留两位小数)
ROUND(COUNT(DISTINCT au.user_id) / COUNT(DISTINCT nu.user_id), 2) AS retention_rate
FROM new_users nu
LEFT JOIN active_users_7d au ON nu.user_id = au.user_id;
2. 场景二:商品关联分析(Apriori算法)
需求:分析用户购买的商品之间的关联关系(如“购买牛奶的用户中,有60%也购买了面包”),用于推荐系统。
步骤:
- 计算“支持度”(Support):商品组合出现的概率(如
P(牛奶, 面包)); - 计算“置信度”(Confidence):购买A后购买B的概率(如
P(面包|牛奶)); - 计算“提升度”(Lift):置信度与B的支持度的比值(如
Lift(牛奶→面包) = Confidence(牛奶→面包) / Support(面包)),提升度>1表示有正关联。
代码实现(简化版):
-- 1. 计算每个订单的商品组合(假设一个订单有多个商品)
WITH order_products AS (
SELECT
order_id,
collect_set(product_id) AS product_set -- 将订单中的商品收集成集合
FROM dwd.order_fact
WHERE dt BETWEEN '2023-10-01' AND '2023-10-31' -- 10月的订单数据
GROUP BY order_id
),
-- 2. 计算商品组合的支持度(如{牛奶, 面包}的支持度)
item_support AS (
SELECT
product1,
product2,
COUNT(DISTINCT order_id) AS order_count, -- 包含该组合的订单数
total_orders -- 总订单数(子查询获取)
FROM (
SELECT
op.order_id,
p1 AS product1,
p2 AS product2,
(SELECT COUNT(DISTINCT order_id) FROM order_products) AS total_orders
FROM order_products op
-- 炸开商品集合,生成所有两两组合(避免重复,如{牛奶,面包}和{面包,牛奶}视为同一组合)
LATERAL VIEW explode(product_set) p AS p1
LATERAL VIEW explode(product_set) q AS p2
WHERE p1 < p2 -- 避免重复组合
) t
GROUP BY product1, product2, total_orders
),
-- 3. 计算置信度和提升度
item_association AS (
SELECT
product1,
product2,
-- 支持度:P(product1, product2) = 包含该组合的订单数 / 总订单数
order_count / total_orders AS support,
-- 置信度:P(product2|product1) = 包含该组合的订单数 / 包含product1的订单数
order_count / (SELECT COUNT(DISTINCT order_id) FROM order_products WHERE array_contains(product_set, product1)) AS confidence,
-- 提升度:Confidence / P(product2)
(order_count / (SELECT COUNT(DISTINCT order_id) FROM order_products WHERE array_contains(product_set, product1)))
/
(SELECT COUNT(DISTINCT order_id) FROM order_products WHERE array_contains(product_set, product2)) / total_orders AS lift
FROM item_support
)
-- 筛选出高关联的商品组合(支持度>0.1,置信度>0.5,提升度>1.2)
SELECT
product1,
product2,
support,
confidence,
lift
FROM item_association
WHERE support > 0.1
AND confidence > 0.5
AND lift > 1.2
ORDER BY lift DESC;
四、性能优化:让Hive查询飞起来
Hive的默认配置可能无法充分发挥集群的性能,以下是几个实战中常用的优化技巧:
1. 使用分区表(Partition)
作用:将数据按某个字段(如dt、region)分割成多个目录,查询时只扫描指定分区的数据,减少数据扫描量。
示例:按日期分区的用户行为表(dwd.user_behavior),查询2023-10-01的日活数据时,只需要扫描dt='2023-10-01'的分区:
SELECT COUNT(DISTINCT user_id) AS dau FROM dwd.user_behavior WHERE dt = '2023-10-01';
2. 使用分桶表(Bucket)
作用:将数据按某个字段(如user_id)的哈希值分割成多个桶(Bucket),减少JOIN时的数据 shuffle(数据传输)。例如,将用户表和订单表都按user_id分桶,JOIN时可以直接在同一个桶内进行(Map Join),提高效率。
示例:创建分桶表:
CREATE TABLE IF NOT EXISTS dwd.user_behavior_bucket (
user_id STRING,
action_type STRING,
product_id STRING,
action_time TIMESTAMP,
dt STRING
)
STORED AS PARQUET
PARTITIONED BY (dt)
-- 按user_id分桶(16个桶)
CLUSTERED BY (user_id) INTO 16 BUCKETS
TBLPROPERTIES ('parquet.compression'='SNAPPY');
3. 使用列式存储格式(Parquet/ORC)
作用:列式存储(如Parquet、ORC)相比行式存储(如Text),具有更高的压缩率和查询效率(只读取需要的列)。例如,查询“用户ID和订单金额”时,列式存储只需要读取这两列的数据,而行式存储需要读取整个行的数据。
示例:创建Parquet格式的表:
CREATE TABLE IF NOT EXISTS dwd.order_fact (
order_id STRING,
user_id STRING,
product_id STRING,
order_amount DECIMAL(10,2),
dt STRING
)
STORED AS PARQUET -- 使用Parquet格式
PARTITIONED BY (dt)
TBLPROPERTIES ('parquet.compression'='SNAPPY'); -- 使用SNAPPY压缩
4. 优化JOIN操作
- Map Join:当其中一个表很小(如<1GB)时,使用Map Join(将小表加载到内存中,在Map阶段进行JOIN),避免Reduce阶段的 shuffle。Hive 0.11+会自动优化小表JOIN,也可以手动指定:
SELECT /*+ MAPJOIN(u) */ -- 手动指定Map Join(小表是user_dim) o.order_id, u.user_name, o.order_amount FROM dwd.order_fact o JOIN dim.user_dim u ON o.user_id = u.user_id; - Bucket Join:当两个表都按相同字段分桶时,使用Bucket Join(每个桶内的数据进行JOIN),减少 shuffle 量。需要开启
hive.optimize.bucketmapjoin参数。
5. 启用成本基础优化器(CBO)
作用:CBO(Cost-Based Optimizer)会根据数据的统计信息(如行数、列的基数)选择最优的执行计划(如JOIN顺序、是否使用索引)。启用CBO需要:
- 开启参数:
set hive.cbo.enable=true;; - 收集统计信息:
ANALYZE TABLE dwd.user_behavior COMPUTE STATISTICS;(收集表的统计信息); - 收集列的统计信息:
ANALYZE TABLE dwd.user_behavior COMPUTE STATISTICS FOR COLUMNS user_id, action_type;(收集列的基数、直方图等信息)。
总结与扩展
1. 回顾:Hive数据仓库建设流程
- 需求分析:明确业务需求(如需要哪些报表、分析哪些指标);
- 架构设计:设计分层架构(ODS、DWD、DWS、ADS);
- 模型设计:设计事实表和维度表(维度建模);
- 数据开发:编写HQL语句,实现数据导入、清洗、建模;
- 性能优化:使用分区、分桶、列式存储、CBO等优化技巧;
- 调度与监控:用Airflow调度Hive作业,用YARN监控作业运行状态。
2. 常见问题(FAQ)
- Q:Hive查询慢怎么办?
A:检查是否使用了分区表(是否按查询条件分区)、是否使用了列式存储、是否启用了CBO、是否有数据倾斜(如某个分区的数据量特别大)。 - Q:如何处理增量数据?
A:ODS层使用分区表,每天导入新增的数据(如LOAD DATA INPATH '/data/raw/2023-10-02.log' INTO TABLE ods.user_behavior_log PARTITION (dt='2023-10-02'));DWD层使用INSERT OVERWRITE覆盖当天的分区数据。 - Q:Hive支持实时分析吗?
A:Hive默认是离线分析(批处理),实时分析可以使用Hive的**LLAP(Low-Latency Analytical Processing)**或结合Spark SQL、Flink等流处理引擎。
3. 下一步:深入学习方向
- Hive高级功能:学习UDF(用户自定义函数,处理复杂逻辑)、UDAF(用户自定义聚合函数,如计算中位数)、UDTF(用户自定义表生成函数,如炸开数组);
- 数据湖整合:学习Hive与数据湖技术(如Iceberg、Hudi)的整合,支持ACID事务和增量数据处理;
- 实时分析:学习Spark SQL(批处理+流处理)、Flink(低延迟流处理),实现实时数据仓库;
- 可视化工具:学习Tableau、Power BI等工具,将Hive中的数据可视化,生成 dashboard。
4. 资源推荐
- 书籍:《Hive编程指南》(O’Reilly,Hive权威指南)、《大数据仓库实践》(阿里技术专家编写,实战经验丰富);
- 文档:Hive官方文档(https://hive.apache.org/docs/)、Hadoop官方文档(https://hadoop.apache.org/docs/);
- 社区:Apache Hive邮件列表(https://lists.apache.org/list.html?dev@hive.apache.org)、Stack Overflow(Hive标签)。
结语
Hive作为大数据仓库的核心工具,凭借其SQL友好、高扩展性的特点,成为企业处理大规模数据的首选。通过本文的实战教程,你应该掌握了Hive数据仓库的建设流程、数据分析的实现方法以及性能优化技巧。
最后,送给你一句话:数据仓库的价值不在于“存储了多少数据”,而在于“能为业务带来多少 insights”。希望你能通过Hive,将数据转化为业务增长的动力!
如果本文对你有帮助,欢迎点赞、收藏、转发,也可以在评论区分享你的Hive实战经验或问题,我们一起讨论!
更多推荐


所有评论(0)