快速实验篇(A3)基于 Hive 的气象数据数仓构建与干旱指标初步分析

小肥柴的Hadoop之旅 快速实验篇(A3)基于 Hive 的气象数据数仓构建与干旱指标初步分析

    • 目录
    • [0. 背景知识:为什么要用 Hive?](#0. 背景知识:为什么要用 Hive?)
    • [1. 任务概述与目标](#1. 任务概述与目标)
    • [2. 低资源环境下的内存与执行策略论证(核心工作)](#2. 低资源环境下的内存与执行策略论证(核心工作))
      • [2.1 资源基础:可供 Hive 消耗的内存上限](#2.1 资源基础:可供 Hive 消耗的内存上限)
      • [2.2 MR 作业内存消耗的通用分析/估算](#2.2 MR 作业内存消耗的通用分析/估算)
        • [step 1:确定作业类型与阶段数](#step 1:确定作业类型与阶段数)
        • [step 2:估算 Map 阶段内存](#step 2:估算 Map 阶段内存)
        • [step 3:估算 Reducer 内存消耗公式](#step 3:估算 Reducer 内存消耗公式)
        • [step 4:估算 Shuffle 数据传输量](#step 4:估算 Shuffle 数据传输量)
        • [step 5:物化表写入开销](#step 5:物化表写入开销)
      • [2.3 综合评总结](#2.3 综合评总结)
        • [2.3.1 评估矩阵](#2.3.1 评估矩阵)
        • [2.3.2 需要避免的操作](#2.3.2 需要避免的操作)
        • [2.3.3 本地模式的真实作用范围](#2.3.3 本地模式的真实作用范围)
    • [3. 环境与资源背景](#3. 环境与资源背景)
    • [4. Hive 最小化安装与配置(实际操作记录)](#4. Hive 最小化安装与配置(实际操作记录))
      • [4.1 下载与解压](#4.1 下载与解压)
      • [4.2 配置环境变量](#4.2 配置环境变量)
    • [4.3 创建必要目录](#4.3 创建必要目录)
      • [4.4 hive-site.xml配置](#4.4 hive-site.xml配置)
    • [4.5 初始化元数据库](#4.5 初始化元数据库)
        • [4.5.1 第一次尝试](#4.5.1 第一次尝试)
    • [5. 建表与数据加载(实际操作记录)](#5. 建表与数据加载(实际操作记录))
      • [5.1 会话参数设置](#5.1 会话参数设置)
      • [5.2 建表 DDL](#5.2 建表 DDL)
    • [6. 分析查询与结果(含数据驱动的迭代调整过程)](#6. 分析查询与结果(含数据驱动的迭代调整过程))
      • [6.1 数据概览](#6.1 数据概览)
      • [6.2 站点维度分析](#6.2 站点维度分析)
      • [6.3 时间维度分析](#6.3 时间维度分析)
      • [6.4 干旱指标初步分析(含阈值迭代调整)](#6.4 干旱指标初步分析(含阈值迭代调整))
        • [6.4.1 查询降水量最少月份](#6.4.1 查询降水量最少月份)
        • [6.4.2 站点级干旱分析(含阈值探索与调整)](#6.4.2 站点级干旱分析(含阈值探索与调整))
    • [7. 查询优化原则与方法总结](#7. 查询优化原则与方法总结)
    • [8. 问题与排查记录](#8. 问题与排查记录)
    • [9. A3阶段总结](#9. A3阶段总结)

目录

0. 背景知识:为什么要用 Hive?

在前面两个阶段(A2-1 和 A2-2),我们使用 Java 和 Python 编写 MapReduce 程序完成了数据清洗。MapReduce 虽然强大,但每完成一个统计任务都需要编写几十上百行代码、编译、打包、提交作业,门槛高、效率低

(1)在实际的海量数据处理中,工程师们更习惯用 SQL (结构化查询语言)来分析数据。Hive 就是这样一个工具------它把 SQL 语句自动翻译成 MapReduce 作业,让用户在熟悉的表格操作模式下完成大数据分析,而不用写一行 Java 代码(其背后被隐藏起来的引擎等底层原理请自行深入研究)。

打个比方:如果 MapReduce 是"汇编语言",那 Hive 就是"高级语言"。你只需要告诉它"我要按站点统计观测次数",它就会自动生成 MapReduce 任务去执行。

(2)需要注意的是:对Hive的理解不能简单的认为它是MR程序的替身,而应该从数据的角度去认知;且在数据视角下,仍需要意识到:Hive 不是一个数据库,而是一个数据仓库工具 。它本身不存储数据,数据仍然在 HDFS 上;它存储的是"元数据"------即表名、列名、列类型等信息。这些元数据需要一个小的数据库来管理,且在当前资源紧张场景下我们选择了 Derby

(3)Derby 是一个纯 Java 的嵌入式数据库,非常轻量(几 MB 大小),不需要单独安装和启动服务,适合单用户学习实验。Hive 会把表结构等信息存在 Derby 里,而真正的海量数据仍然留在 HDFS 上,查询时再从 HDFS 读取。在 2GB 内存的集群中,Derby 内嵌模式是最合适的选择------它不占用额外内存,不需要额外进程,让每一兆内存都用在刀刃上。


1. 任务概述与目标

项目 说明
定位 承接 A2-2 的清洗结果,使用 Hive 替代手写 MapReduce,构建数据仓库,对气象数据进行多维聚合分析
目标 1. 在 2GB 集群上搭建最小化 Hive(Derby 内嵌元数据库) 2. 创建外部表加载 cleaned 数据(9,218,700 行) 3. 使用 SQL 安全执行数据概览、站点聚合、时间聚合及干旱指标初步查询 4. 所有查询均在内存安全边界内完成,不触发 OOM 5. 总结低资源环境下的内存估算规程与查询优化原则
输入 HDFS 路径 /drought/output_a2_2/cleaned-m-*(1.23 GB,22 列 CSV)
输出 聚合结果表 + 物化中间表 + 分析结论 + 内存估算模型

2. 低资源环境下的内存与执行策略论证(核心工作)

在 2GB 内存集群上运行 Hive,任何一条复杂 SQL 都可能触发 OOM。我们需从资源基础、估算规程、具体计算最终得到安全设置策略,形成完整的推演链条。

2.1 资源基础:可供 Hive 消耗的内存上限

资源项 数值 说明
单节点物理内存 2 GB (2048 MB) 虚拟机分配
OS + 基础服务占用 ~700 MB 内核、缓存、DataNode、NodeManager 进程
YARN 可管理内存 1024 MB/节点 yarn.nodemanager.resource.memory-mb 控制
集群总 YARN 内存 3072 MB (3节点) ---
单容器最大值 384 MB mapreduce.map.memory.mbmapreduce.reduce.memory.mb 统一设定
单容器 JVM 堆 256 MB -Xmx256m 控制,剩余 128 MB 用于 JVM 堆外、进程开销

【结论2-1】 :任何 YARN 容器(Map 或 Reduce)可用堆内存上限为 256 MB ,可用堆外内存约为 128 MB,所有后续计算必须基于此边界。 ⇒ so,分布式难就难在计算机底层原理的十八般武艺,要样样精通啊!学习成本非常高。

2.2 MR 作业内存消耗的通用分析/估算

针对 Hive 翻译后的 MR 作业,按以下步骤逐项估算:

step 1:确定作业类型与阶段数
  • Map-only 作业 (如 COUNT(*)WHERE 过滤):仅 Map 阶段,无 Shuffle,最安全。
  • Map + Reduce 作业 (如 GROUP BYORDER BY):Map 阶段 + Shuffle 传输 + Reduce 聚合。
step 2:估算 Map 阶段内存

Map 阶段逐行流式读取输入数据,不积攒行。内存消耗 = 输入缓冲(由 io.sort.mb 控制,已设为 64 MB)+ 行解析临时对象(约 10~20 MB)。总和通常 < 100 MB,远小于容器 384 MB 上限。

【结论2-2】:Map 阶段在实验中始终安全,无需重点建模。

step 3:估算 Reducer 内存消耗公式

Reducer 阶段的内存消耗由三部分组成:

bash 复制代码
Reducer 内存 ≈ 分组状态大小 + Shuffle 缓冲 + 排序缓冲
  • 分组状态大小 = 该 Reducer 处理的唯一键数量 × 每个键的状态大小
  • Shuffle 缓冲 :接收 Map 输出的缓冲区,由 mapreduce.reduce.shuffle.input.buffer.percent(默认 0.7)控制,约为 JVM 堆的 70% = 179 MB(以 256 MB 堆计算)
  • 排序缓冲:对拉取的数据进行排序,与 Shuffle 缓冲复用同一内存区域

关键变量:分组状态大小。本实验中,所有聚合操作的分组键数量均可预估:

聚合操作 分组键 预估键数 单键状态 分组状态大小 是否安全(< 256 MB 堆)
GROUP BY station_id 站点 ID ~10 万 一个 long 计数器(8 字节)+ HashMap 开销 ≈ 40 字节 ~4 MB
GROUP BY month 月份 (yyyy-MM) 12~24 个 同上 < 1 MB
ORDER BY ... LIMIT N 无需分组,仅保留前 N 条 N ≤ 100 整行数据 ≈ 1 KB < 1 MB
COUNT(DISTINCT station_id) 维护全局去重集合 10 万 每个键约 40 字节 + 内存膨胀 1020 MB ✅(但 Hash 碰撞可能增加)
窗口函数(单站点,几千行) 单分区内排序 几千行 窗口缓冲区 ≈ 几万行 × 100 字节 15 MB

【结论2-3】(核心结论):分组状态大小(4~20 MB)远小于 Shuffle 缓冲(179 MB),更远小于容器堆上限(256 MB),且Reducer 内存始终安全。

step 4:估算 Shuffle 数据传输量

Map 端输出键值对(如 <station_id, "1">),经序列化后每条约 30 字节。全量 9.2M 行 → 约 276 MB。均匀散列到 3 个 Reducer 后,每个 Reducer 接收约 92 MB 的 Shuffle 数据,在 179 MB 缓冲区内完全可容纳,不会触发磁盘溢写。

step 5:物化表写入开销

CTAS 作业的最后阶段是将 Reducer 结果写入 HDFS 表文件(数据库数据的落盘/物化,这块知识点如果不知晓,请自行补全《数据库原理及应用》课程内容,尤其是需要了解分布式数据库的一些基础套路)。

  • 物化表 station_counts 输出约 10 万行 × 30 字节 ≈ 3 MB
  • 物化表 monthly_summary 输出几十行,< 1 MB。
  • I/O 缓冲占用堆外内存,不影响 JVM 堆。

【结论2-4】:写入阶段无额外内存风险。

2.3 综合评总结

2.3.1 评估矩阵

用矩阵形式给出所有考虑因素的疑点+结论,方面后续作为语料投喂给AI做他用。

查询 作业类型 Map 内存 Reducer 键数 分组状态 Shuffle/Red 物化后大小 安全结论
SELECT COUNT(*) Map-only < 100 MB 无 Reduce --- --- --- ✅ 安全
approx_count_distinct Map+Red < 100 MB 内部 hash sketch < 10 MB ~92 MB/Red --- ✅ 安全
CTAS station_counts Map+Red < 100 MB ~10 万 ~4 MB ~92 MB/Red ~3 MB ✅ 安全
CTAS monthly_summary Map+Red < 100 MB 12~24 < 1 MB ~92 MB/Red < 1 MB ✅ 安全
ORDER BY + LIMIT Map+Red < 100 MB TopN 堆 < 1 MB ~92 MB/Red --- ✅ 安全
窗口函数(单站点) Map+Red < 100 MB 单分区 ~5 MB < 10 MB --- ✅ 安全
2.3.2 需要避免的操作
操作 原因
COUNT(DISTINCT col) 在大表上 需维护全量去重集合,若唯一值数百万则分组状态可能膨胀至百 MB 级
多表 JOIN 需要多次 Shuffle 或 Map 端全量加载小表,在 384 MB 容器中极易 OOM
全量 ORDER BY 无 LIMIT Reducer 需对全量数据排序,9.2M 行完全塞不进 256 MB 堆
窗口函数在全量数据上 需要按分区排序,若分区数多且数据倾斜,某个 Reducer 可能接收大量行
2.3.3 本地模式的真实作用范围

Hive不一定必须运行在子节点上:

  • 虽然 hive-site.xml 中开启了 hive.exec.mode.local.auto=true
  • 但其触发条件是:输入数据量 < hive.exec.mode.local.auto.inputbytes.max(默认 128 MB);
  • 本实验输入 1.23 GB,几乎所有查询都会提交为 YARN 作业。
    实际执行日志也验证了这一点:
bash 复制代码
Cannot run job locally: Input Size (= 1291086910) is larger than 
hive.exec.mode.local.auto.inputbytes.max (= 134217728)
Starting Job = job_1780156095426_0001 ...

本地模式仅对从物化表(如 station_counts,仅 3 MB)读取的查询或 LIMIT 子查询有效。自此,所有 SQL 均已按 MR 作业进行内存规划。

3. 环境与资源背景

项目 配置
节点数 3(master + worker1/2/3)
每节点内存 2 GB RAM
每节点磁盘 30 GB
YARN 可用内存 每节点 1024 MB,单容器最大 384 MB
Hive 版本 3.1.3
元数据库 Derby(内嵌)
执行引擎 MapReduce
数据路径 /drought/output_a2_2/cleaned-m-*(1.23 GB)

4. Hive 最小化安装与配置(实际操作记录)

4.1 下载与解压

清华镜像站返回 404,改用华为云镜像站(也可以考虑跟换为其他镜像):

bash 复制代码
cd /usr/local
sudo wget https://mirrors.huaweicloud.com/apache/hive/hive-3.1.3/apache-hive-3.1.3-bin.tar.gz
sudo tar -xzf apache-hive-3.1.3-bin.tar.gz
sudo mv apache-hive-3.1.3-bin hive
sudo chown -R hadoop:hadoop /usr/local/hive

4.2 配置环境变量

以追加形式填写hive相关环境变量:

bash 复制代码
echo '' >> ~/.bashrc
echo '# ========== Hive 环境变量 ==========' >> ~/.bashrc
echo 'export HIVE_HOME=/usr/local/hive' >> ~/.bashrc
echo 'export PATH=$HIVE_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

执行上述动作后验证:

bash 复制代码
hive --version

输出Hive版本号后,确认安全成功;当前环境中,实际输出为"Hive 3.1.3 "。

4.3 创建必要目录

主要是为使用Derby做准备工作:

bash 复制代码
# HDFS 仓库目录
hdfs dfs -mkdir -p /user/hive/warehouse /tmp/hive
hdfs dfs -chmod g+w /user/hive/warehouse /tmp/hive

# 本地 Derby 元数据库目录
mkdir -p /home/hadoop/hive_metastore

4.4 hive-site.xml配置

若初始未创建配置文件可使用 cat > 直接覆盖写入(其他情况自行咨询AI解决):

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property>
        <name>javax.jdo.option.ConnectionURL</name>
        <value>jdbc:derby:;databaseName=/home/hadoop/hive_metastore/metastore_db;create=true</value>
    </property>
    <property>
        <name>javax.jdo.option.ConnectionDriverName</name>
        <value>org.apache.derby.jdbc.EmbeddedDriver</value>
    </property>
    <property>
        <name>hive.metastore.warehouse.dir</name>
        <value>/user/hive/warehouse</value>
    </property>
    <property>
        <name>hive.exec.mode.local.auto</name>
        <value>true</value>
    </property>
    <property>
        <name>hive.auto.convert.join</name>
        <value>false</value>
    </property>
    <property>
        <name>hive.exec.dynamic.partition.mode</name>
        <value>nonstrict</value>
    </property>
    <property>
        <name>hive.exec.scratchdir</name>
        <value>/tmp/hive</value>
    </property>
</configuration>

【关键经验,仅供参考】 :Derby 路径必须使用绝对路径 。使用相对路径时 schematool 会在当前工作目录创建数据库,导致后续 Hive CLI 启动时找不到元数据。⇒ 瞧!哪里都有CLI,命令行才是正统!哈哈。

4.5 初始化元数据库

  • 【叠甲】一下是我做实验的真实记录,含排错过程 ,自己实践时可以先将这段内容抛给AI,给出精简版本的指导书;但我个人还是秉持那个观点:数据清洗、分析和处理的过程,在实际工程落地中不会一次到位的,反反复复,拉扯纠结才是常态。
4.5.1 第一次尝试
  • 初始化
    从这里开始,所有操作均在master上完成。
bash 复制代码
schematool -dbType derby -initSchema

报错:

bash 复制代码
Error: FUNCTION 'NUCLEUS_ASCII' already exists. (state=X0Y68,code=30000)
  • 排错与修复
    (1)发现 hive-site.xml 未创建,导致 Derby 使用相对路径 metastore_db 创建在用户主目录
    (2)创建正确的 hive-site.xml(见 4.4)
    (3)彻底清理残留,后重新初始化:
bash 复制代码
rm -rf /home/hadoop/hive_metastore/metastore_db
rm -rf ~/metastore_db
rm -f ~/derby.log
bash 复制代码
schematool -dbType derby -initSchema

最后看到:Initialization script completedschemaTool completed字样,代表初始化成功。

  • 根本原因 :首次初始化时未指定 hive-site.xml,Derby 使用相对路径创建了不完整的元数据库。后续创建了配置文件,但残留的相对路径数据库文件仍存在,导致重复初始化冲突;彻底删除所有残留后重置解决。
  • 启动验证
bash 复制代码
hive

成功进入 Hive CLI,输出 Hive Session ID = ...,确认 Hive 安装完成。

具体而言,应根据实验阶段分步启动服务:

阶段 需启动服务 原因
Hive CLI 建表 仅 HDFS(start-dfs.sh 外部表注册仅需 HDFS 可访问
执行分析查询 HDFS + YARN(start-yarn.sh MR 作业需要 YARN 调度容器

【实际执行经验参考】:建表阶段仅启动 HDFS,建表完成并验证表结构后,再启动 YARN 执行查询。这样可以隔离故障,且建表阶段节省 YARN 进程所占的约 300 MB 内存。 ⇒ 还是内存限制闹的。

5. 建表与数据加载(实际操作记录)

5.1 会话参数设置

因为每次关闭hive会话,缓存会被清空,所以每次进入 Hive CLI 后首先执行:

sql 复制代码
SET hive.execution.engine=mr;
SET mapreduce.map.memory.mb=384;
SET mapreduce.map.java.opts=-Xmx256m;
SET mapreduce.reduce.memory.mb=384;
SET mapreduce.reduce.java.opts=-Xmx256m;
SET mapreduce.job.reduces=3;
SET hive.auto.convert.join=false;

以配置运行参数。

【注意】 :第一条 SET hive.execution.engine=mr 会触发弃用警告 Hive-on-MR is deprecated in Hive 2...,这是正常提示,不影响使用;在 2GB 集群上 MR 是唯一可行的引擎。

5.2 建表 DDL

在 Hive 中,DDL 的全称是 Data Definition Language(数据定义语言),用于定义、修改或删除数据库对象(如数据库、表、视图等)。

sql 复制代码
CREATE EXTERNAL TABLE drought_cleaned (
    station_id      STRING  COMMENT '站点ID',
    record_date     STRING  COMMENT '日期 yyyy-MM-dd',
    col_2           STRING,
    col_3           STRING,
    col_4           STRING,
    precip          DOUBLE  COMMENT '降水量 PRECTOT',
    col_6           STRING,
    col_7           STRING,
    temp            DOUBLE  COMMENT '温度 T2M',
    col_9           STRING,
    col_10          STRING,
    col_11          STRING,
    col_12          STRING,
    col_13          STRING,
    col_14          STRING,
    col_15          STRING,
    wind_speed      DOUBLE  COMMENT '风速 WS10M',
    col_17          STRING,
    col_18          STRING,
    col_19          STRING,
    col_20          STRING,
    col_21          STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE
LOCATION '/drought/output_a2_2'
TBLPROPERTIES ("skip.header.line.count"="0");

若执行结果显示OK,则说明建表成功;且初学者可以看到:HiveQL其实与SQL区别不大,就当强化学习了。接着需要查询:表结构验证,进一步确认数据正常加载。

sql 复制代码
DESCRIBE drought_cleaned;

【预期】输出 22 个字段,耗时 0.453 秒,字段名、类型、注释均正确。

6. 分析查询与结果(含数据驱动的迭代调整过程)

【注】以下实践过程,都是我在集群上跑过一轮,确认之后的展示;所谓"预期结果"其实就是供参考的实际执行效果;相关查询过程就是对数据操作和研究其特点的一个过程示范。

6.1 数据概览

  • step 1:查看总行数
sql 复制代码
SELECT COUNT(*) AS total_rows FROM drought_cleaned;
指标 数值
返回结果 9,218,700
与 A2-2 一致性 ✅ 完全一致
Map 数 5
Reduce 数 1(Hive 优化为单 Reducer 汇总计数)
总耗时 49.626 秒
累计 CPU 时间 20.94 秒
HDFS 读取 1,291,175,507 字节
执行模式 YARN 集群模式(本地模式因数据量超 128 MB 自动切换)
  • step 2:站点数(去重)

尝试使用 approx_count_distinct 失败(函数不存在),改用标准 COUNT(DISTINCT) 并增加 Reducer 数保障安全:

sql 复制代码
SET mapreduce.job.reduces=5;
SELECT COUNT(DISTINCT station_id) AS exact_stations FROM drought_cleaned;
指标 数值
返回结果 102,430
与 A2-2 唯一键数量 ✅ 完全匹配
Reduce 数 1(Hive 对 COUNT(DISTINCT) 强制单 Reducer 以保证正确性)
耗时 34.265 秒
内存安全性 10.2 万个站点 ID 的去重集合约 10~20 MB,远低于 256 MB 堆上限
  • step 3:查询日期范围
sql 复制代码
SELECT MIN(record_date) AS min_date, MAX(record_date) AS max_date FROM drought_cleaned;
指标 数值
最小日期 2012-04-03
最大日期 2020-12-29
数据跨度 约 8 年 9 个月
耗时 37.142 秒

【预期执行结果】:数据总量 9,218,700 行,覆盖 102,430 个站点,时间跨度 2012-04 至 2020-12。

6.2 站点维度分析

  • step 1:物化站点统计表
sql 复制代码
CREATE TABLE station_counts AS
SELECT station_id, COUNT(*) AS obs_count
FROM drought_cleaned
GROUP BY station_id;
指标 数值
Map 数 5
Reduce 数 3(mapreduce.job.reduces=3 生效)
耗时 41.971 秒
HDFS 写入 2,395,232 字节(约 2.28 MB)
  • step 2:Top 20 站点观测数
sql 复制代码
SELECT station_id, obs_count
FROM station_counts
ORDER BY obs_count DESC
LIMIT 20;

本地模式执行,耗时 3.616 秒。结果显示 Top 20 站点的观测数均为 90 次,表明数据集中观测次数高度一致。

  • step 3:站点观测数分布
    【注】认真观察正经的SQL编写是有缩进的,思考下为什么这会称为行业习惯?赶紧抛弃那种一行成仙的SQL写法。
sql 复制代码
SELECT 
    CASE 
        WHEN obs_count < 10 THEN '1-9'
        WHEN obs_count < 30 THEN '10-29'
        WHEN obs_count < 50 THEN '30-49'
        WHEN obs_count < 70 THEN '50-69'
        WHEN obs_count < 90 THEN '70-89'
        ELSE '90'
    END AS obs_range,
    COUNT(*) AS station_cnt
FROM station_counts
GROUP BY 
    CASE 
        WHEN obs_count < 10 THEN '1-9'
        WHEN obs_count < 30 THEN '10-29'
        WHEN obs_count < 50 THEN '30-49'
        WHEN obs_count < 70 THEN '50-69'
        WHEN obs_count < 90 THEN '70-89'
        ELSE '90'
    END
ORDER BY obs_range;
观测次数范围 站点数量
90 102,430

【预期结果】发现所有 102,430 个站点的观测次数均为 90 次。数据呈高度规整,平均每个站点每天一次观测,覆盖 90 天(约 3 个月),分散在 2012-2020 年间的不同时段。这一特征为后续分析提供了重要基线。

6.3 时间维度分析

  • step 1:物化月度汇总表
sql 复制代码
CREATE TABLE monthly_summary AS
SELECT 
    substr(record_date, 1, 7) AS month_key,
    COUNT(*) AS obs_count,
    AVG(temp) AS avg_temp,
    SUM(precip) AS total_precip
FROM drought_cleaned
WHERE temp IS NOT NULL
GROUP BY substr(record_date, 1, 7);
指标 数值
Map 数 5
Reduce 数 3
耗时 39.313 秒
HDFS 写入 5,590 字节(约 5.5 KB)
  • step 2:月度数据查询
sql 复制代码
SELECT * FROM monthly_summary ORDER BY month_key;

本地模式,耗时 1.822 秒。数据覆盖 105 个月(2012-04 至 2020-12)。

【预期结果】:将会有关键发现

  • 温度最低月份 :2014-03,平均温度 -0.30℃ ;其次为 2014-02,平均温度 -0.25℃
  • 温度最高月份 :2012-09,平均温度 24.93℃
  • 数据整体呈现温带气候特征,冬冷夏热,年温差约 25℃。

6.4 干旱指标初步分析(含阈值迭代调整)

6.4.1 查询降水量最少月份
sql 复制代码
SELECT month_key, total_precip 
FROM monthly_summary 
ORDER BY total_precip ASC 
LIMIT 5;
排名 月份 降水量 (mm)
1 2014-03 271,840.87
2 2015-02 278,634.47
3 2014-02 292,937.57
4 2013-03 313,575.06
5 2012-04 327,628.77

降水量最少的月份集中在冬末春初(2~4 月),符合气候规律。

6.4.2 站点级干旱分析(含阈值探索与调整)
  • step 1:首次尝试时,选取任意站点计算连续无降水天数

选择一个观测数为 90 的站点(此处设定为-1000799230488340175,你也可以根据实际情况自定义站点),创建单站点数据子集:

sql 复制代码
CREATE TABLE single_site_data AS
SELECT record_date, precip
FROM drought_cleaned
WHERE station_id = '-1000799230488340175';

上述操作耗时 55.876 秒,HDFS 写入仅 1,442 字节。

接着,执行连续无降水天数查询(precip = 0),返回 NULL。于是检查该站点降水量范围:

sql 复制代码
SELECT MIN(precip) AS min_precip, MAX(precip) AS max_precip
FROM single_site_data;

(1)实际执行结果 :最小降水量 2.1 mm ,最大降水量 13.69 mm

(2)表明 :该站点在 90 天观测期内没有一天的降水量为 0

由此引出下一步思考。

  • step 2:全局探索:是否存在降水量为 0 的记录?
sql 复制代码
SELECT station_id, COUNT(*) AS zero_days
FROM drought_cleaned
WHERE precip = 0
GROUP BY station_id
ORDER BY zero_days DESC
LIMIT 5;

操作耗时 33.074 秒,且返回空集 ,说明整个数据集中没有任何降水量为 0 的记录。这意味着数据集可能经过了预处理,仅保留了有降水的观测,或者数据来源的地区/季节本身不存在绝对无降水日;这暗示我们的检测规则要根据数据实际情况做出必要的调整。

  • step 3:策略调整,从"无降水天数"改为"低降水天数"

既然没有零值,我们转向寻找降水量最低的站点,并以接近 0 的阈值定义"干旱倾向"。查询降水量最低的站点:

sql 复制代码
SELECT station_id, MIN(precip) AS min_precip, AVG(precip) AS avg_precip
FROM drought_cleaned
GROUP BY station_id
ORDER BY min_precip ASC
LIMIT 5;
站点 ID 最小降水量 (mm) 平均降水量 (mm)
6812413573084174289 0.10 1.28
-838090275501305730 0.10 1.28
-8020525461484131147 0.11 1.33
-6442896892518939203 0.11 2.10
1046629422960063977 0.11 1.47

从商标可知:几乎所有站点的最小降水量均为 0.1 mm,平均降水量在 1.28~2.10 mm 之间。这些站点降水极少,干旱倾向明显;由实际情况触发,可以调整分析阈值的设定。

  • step 4:重新定义干旱阈值,计算连续低降水量天数(< 0.5 mm)

选择最小降水量最低的站点 6812413573084174289,替换单站点表:

sql 复制代码
DROP TABLE single_site_data;
CREATE TABLE single_site_data AS
SELECT record_date, precip
FROM drought_cleaned
WHERE station_id = '6812413573084174289';

使用阈值 precip < 0.5 作为"近似无降水",计算连续低降水天数:

sql 复制代码
WITH daily_precip AS (
    SELECT record_date, precip FROM single_site_data
),
precip_flag AS (
    SELECT 
        record_date,
        CASE WHEN precip < 0.5 THEN 0 ELSE 1 END AS is_dry,
        ROW_NUMBER() OVER (ORDER BY record_date) - 
        SUM(CASE WHEN precip < 0.5 THEN 0 ELSE 1 END) OVER (ORDER BY record_date) AS grp
    FROM daily_precip
)
SELECT MAX(consecutive_dry) AS max_dry_days
FROM (
    SELECT grp, COUNT(*) AS consecutive_dry
    FROM precip_flag
    WHERE is_dry = 0
    GROUP BY grp
) t;
指标 数值
最大连续低降水天数 1 天
执行模式 3 个 Stage,前两个为 YARN 模式,最后一个为本地模式
总耗时 63.882 秒

【结果解读】:即使是最干旱的站点,降水量低于 0.5 mm 的天数也是零散分布的,从未连续两天达到此阈值。这表明数据集中不存在传统意义上"连续无降水"的干旱事件,或数据集的时间粒度(非连续日)和筛选条件限制了此类分析。


7. 查询优化原则与方法总结

以下原则基于标题2的内存估算论证得出,适用于本实验所有 SQL:

原则 方法 目的
增加 Reducer 数 SET mapreduce.job.reduces=3~5 分散单 Reducer 数据量与键数量,避免单点 OOM
避免 COUNT(DISTINCT) 使用 approx_count_distinct(若不可用则增加 Reducer 数) 减少 Reducer 内存排序/去重压力
善用 ORDER BY + LIMIT 聚合查询末尾加 LIMIT N Reducer 仅保留前 N 条,无需全量排序
WHERE 尽早过滤 聚合前用 WHERE 滤除 NULL 或无关行 减少 Map 输出量和 Shuffle 传输量
积极使用物化中间表 将常用聚合结果用 CTAS 保存为表 避免重复全表扫描,后续查询极快且轻量
单站点/小范围测试 复杂逻辑先用一个站点或一个月的数据验证 防止未知内存爆炸拖垮集群
禁止多表 JOIN 本实验不涉及任何 JOIN 操作 JOIN 在 2GB 节点上几乎必然 OOM
监控 YARN WebUI 查询期间观察 8088 端口容器状态 及时发现 Container killed 并调整参数

8. 问题与排查记录

现象 原因 解决 备注
清华镜像站下载 404 路径不存在或版本已迁移 改用华为云镜像站 mirrors.huaweicloud.com
hive-site.xml: No such file or directory 未创建配置文件 使用 cat > 直接写入完整配置
NUCLEUS_ASCII already exists 首次未指定配置文件,Derby 用相对路径创建了不完整库;后续配置指定绝对路径后,残留文件与新初始化冲突 删除所有路径下的 metastore_dbderby.log,重新 schematool -initSchema 核心教训:Derby 路径必须使用绝对路径,且初始化前确保无残留
Hive-on-MR is deprecated 警告 Hive 3.x 推荐 Tez/Spark,但 MR 仍可用 忽略,MR 是 2GB 集群唯一可行引擎
Cannot run job locally 信息 输入 1.29 GB 超过本地模式阈值 128 MB,自动切换 YARN 正常行为,无需处理 验证了阈值设置的合理性
Invalid function approx_count_distinct Hive 3.1.3 默认不支持此 UDF 改用 COUNT(DISTINCT),增加 Reducer 保证安全
rm -rf 在 Hive CLI 内误执行 hive> 提示符下执行了 shell 命令 quit; 退出 CLI,再执行 shell 命令 CLI 与 shell 环境隔离
连续无降水天数返回 NULL 所选站点无 precip = 0 的记录 检查数据后发现全数据集均无零值,调整阈值到 < 0.5,重新分析 体现"以数据为准,迭代调整分析策略"的原则
窗口函数触发 3 个 Stage 且 YARN 模式 即使单站点数据极小,Hive 仍可能因 Reducer 数 >1 而提交 YARN 正常执行,耗时略长但内存安全 后续可考虑临时设置 mapreduce.job.reduces=1 并强制本地模式

9. A3阶段总结

  1. Hive 环境搭建与数据加载:通过华为云镜像站下载 Hive 3.1.3,使用 Derby 内嵌模式存储元数据,经过路径配置错误和元数据库残留问题排查后成功初始化,创建外部表指向 A2-2 清洗数据,总行数 9,218,700 与上一阶段一致。
  2. 内存估算模型有效 :所有 MR 作业均稳定运行,无任何容器被杀或 OOM 发生。Map 阶段内存消耗约 100 MB,Reducer 分组状态仅 4~20 MB,远低于 256 MB 堆上限。物化表 station_counts(2.28 MB)和 monthly_summary(5.5 KB)极大加速了后续查询。
  3. 分析结果摘要:数据覆盖 102,430 个站点、105 个月(2012-04 ~ 2020-12),每个站点均匀观测 90 次。温度范围 -0.30℃ ~ 24.93℃,降水量最低月份在冬末春初。最干旱站点的最小降水量为 0.1 mm,平均 1.28 mm;连续低降水天数(<0.5mm)最长为 1 天,表明数据集中无显著连续干旱事件。
  4. 低资源优化原则有效:增加 Reducer 数、积极使用物化表、小范围测试、避免 JOIN 等原则在实践中得到验证。窗口函数即使在极小数据集上也可能触发 YARN 模式,但内存安全。
  5. 数据驱动的迭代分析思路贯穿始终 :从发现数据中无零降水量记录,到调整干旱阈值为 < 0.5,最终得出符合数据实际的结论。这种"以数据为准,持续调整分析策略"的理念是数据工程的核心能力,也在本实验中得到了充分体现。
  6. 技术门槛的跨越:在短短几天的实践周内,从手写 MapReduce 代码到使用 SQL 进行大数据分析,完成了从"汇编"到"高级语言"的跨越;Derby 内嵌模式的轻量化和 Hive 的 SQL 抽象,使得在 2GB 内存集群上进行海量数据分析成为可能。
相关推荐
卷毛迷你猪1 小时前
快速实验篇(A4)Hive 数据仓库进阶:全站点干旱事件识别与多维统计分析
数据仓库·hive·hadoop·分布式
HannahTx1 小时前
解锁客户资料管理新姿势:便捷查找不再是梦
大数据
Nile2 小时前
解密Palantir系列一:3. Palantir 是谁
大数据·人工智能·ai
云天AI实战派2 小时前
AI 智能体总是跑偏怎么办?ChatGPT/API/Agent 故障排查指南与全流程修复手册
大数据·人工智能·chatgpt·agent
逸Y 仙X2 小时前
文章六:ElasticSearch 集群通信安全权限
java·大数据·服务器·elasticsearch·搜索引擎·全文检索
小脑斧1232 小时前
AI Skills 全链路自动化运营实践:抖音热点、小红书种草与文生图一体化方案
大数据·人工智能·小红书·skills·自动化运营
白露与泡影2 小时前
告别OOM焦虑:Flink 内存模型原理与诊断调优
大数据·flink
清辞8532 小时前
Ai应用——数据分析
大数据
冯RI375II694872 小时前
样品准备指南:LFGB认证检测送样要求详解
大数据