Python大数据实战(五):数据仓库Hive从入门到精通——3万字讲透Hive核心原理与实战

Python大数据实战(五):数据仓库Hive从入门到精通(Hive核心原理与实战)


文章目录

  • Python大数据实战(五):数据仓库Hive从入门到精通(Hive核心原理与实战)
  • 前言
  • [一、Hive 概述](#一、Hive 概述)
    • [1.1 什么是 Hive](#1.1 什么是 Hive)
      • [Hive 的本质](#Hive 的本质)
    • [1.2 Hive 和关系型数据库的区别](#1.2 Hive 和关系型数据库的区别)
    • [1.3 Hive 的优缺点](#1.3 Hive 的优缺点)
    • [1.4 Hive 架构详解](#1.4 Hive 架构详解)
  • [二、Hive 安装与部署](#二、Hive 安装与部署)
    • [2.1 三种 Metastore 模式](#2.1 三种 Metastore 模式)
    • [2.2 MySQL 安装与配置](#2.2 MySQL 安装与配置)
    • [2.3 直连数据库模式配置](#2.3 直连数据库模式配置)
    • [2.4 远程服务模式配置](#2.4 远程服务模式配置)
  • [三、Hive SQL 基础](#三、Hive SQL 基础)
  • [四、Hive 查询语句](#四、Hive 查询语句)
    • [4.1 基本查询](#4.1 基本查询)
    • [4.2 WHERE 条件过滤](#4.2 WHERE 条件过滤)
    • [4.3 聚合函数与分组](#4.3 聚合函数与分组)
    • [4.4 JOIN 关联查询](#4.4 JOIN 关联查询)
    • [4.5 排序](#4.5 排序)
    • [4.6 实战案例:基站掉话率分析](#4.6 实战案例:基站掉话率分析)
  • [五、Hive 函数体系](#五、Hive 函数体系)
  • [六、Hive 参数与动态分区](#六、Hive 参数与动态分区)
  • [七、Hive 分桶](#七、Hive 分桶)
    • [7.1 分桶原理](#7.1 分桶原理)
    • [7.2 分桶实战](#7.2 分桶实战)
  • [八、Lateral View、视图与索引](#八、Lateral View、视图与索引)
    • [8.1 Lateral View](#8.1 Lateral View)
    • [8.2 Hive 视图](#8.2 Hive 视图)
    • [8.3 Hive 索引(了解)](#8.3 Hive 索引(了解))
  • [九、Hive 运行方式](#九、Hive 运行方式)
    • [9.1 命令行方式(CLI)](#9.1 命令行方式(CLI))
    • [9.2 脚本运行方式(生产推荐)](#9.2 脚本运行方式(生产推荐))
    • [9.3 HDFS 交互](#9.3 HDFS 交互)
  • 十、总结与展望
    • [10.1 核心知识回顾](#10.1 核心知识回顾)
    • [10.2 学习建议](#10.2 学习建议)
    • [10.3 参考链接](#10.3 参考链接)
  • 下一篇预告

前言

"老板,我想查一下上个月的用户行为数据,能帮我写个 MapReduce 吗?"

这句话在2010年之前的大数据团队里再常见不过了。数据分析师懂业务但不会写 Java,工程师会写 MapReduce 但不理解业务需求。这种"鸡同鸭讲"的局面,直到 Hive 的出现才被打破。

Hive 由 Facebook 开源,它的核心思想简单到令人发指:让不懂 Java 的人也能用 SQL 查询 Hadoop 上的海量数据。它将类 SQL 语句(HQL)自动翻译成 MapReduce 作业,在底层分布式执行。

本文将带你从零开始,系统学习 Hive 的核心原理、安装部署、SQL 语法、函数体系、分区分桶、自定义 UDF 以及生产环境中的运行方式。全文超过 20000 字,配合大量实战案例,目标是让你读完就能上手搭建自己的 Hive 数据仓库。


一、Hive 概述

1.1 什么是 Hive

Apache Hive 的官方定义:

The Apache Hive™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL.

翻译过来就是:Hive 是一个基于 Hadoop 的数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类 SQL 查询功能

Hive 的本质

Hive 的本质可以总结为三个关键点:

层次 说明
数据存储 Hive 处理的数据存储在 HDFS
计算引擎 Hive 分析数据底层的实现是 MapReduce(也支持 Spark/Tez)
任务调度 执行程序运行在 Yarn

简单来说:Hive = HDFS 存储 + MapReduce 计算 + SQL 接口

1.2 Hive 和关系型数据库的区别

很多初学者会问:"Hive 不就是个数据库吗?跟 MySQL 有什么区别?"

这是一个经典的误解。虽然 Hive 提供了类 SQL 的查询接口,但它和传统关系型数据库(RDBMS)在底层架构上有本质区别:

对比项 Hive 关系型数据库(MySQL)
查询语言 HQL(类SQL) SQL
数据存储 HDFS(分布式文件系统) 本地磁盘或 Raw Device
执行引擎 MapReduce / Spark / Tez Executor(单机执行引擎)
数据插入 支持批量导入和单条插入 支持批量导入和单条插入
数据更新/删除 支持追加,不支持行级删除 支持行级别更新和删除
数据规模 PB 级别 GB ~ TB 级别
执行延迟 (秒~分钟级) (毫秒级)
分区 支持 支持
索引 v0.8 后支持(3.0+ 已废弃) 完善支持
数据加载模式 读时模式(Schema on Read) 写时模式(Schema on Write)
扩展性 (水平扩展) 低(垂直扩展为主)
应用场景 海量数据离线分析 实时事务查询

💡 关键洞察:Hive 的"读时模式"意味着数据加载时不校验格式,查询时才解析。这让数据加载极快,但也意味着查询时可能因为格式问题报错。而 MySQL 的"写时模式"在写入时就校验,写入慢但查询快。

1.3 Hive 的优缺点

优点

  1. 类 SQL 语法,学习成本低:会写 SQL 就能上手 Hive,不需要学 MapReduce
  2. 避免手写 MapReduce:大幅降低大数据开发门槛
  3. 适合海量数据离线分析:PB 级数据也能稳定处理
  4. 支持自定义函数(UDF/UDAF/UDTF):可以扩展 Hive 的功能
  5. 完善的生态系统:与 Hadoop、Spark、HBase 等无缝集成

缺点

  1. HQL 表达能力有限:迭代算法、数据挖掘等复杂场景不适用
  2. 执行延迟高:MapReduce 作业启动开销大,不适合实时查询
  3. 调优困难:粒度较粗,优化空间有限
  4. 不支持行级更新/删除:只适合"一次写入、多次读取"的场景

1.4 Hive 架构详解

Hive 的架构可以分为四个核心组件:
#mermaid-svg-nu7xympMqzSDo52P{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nu7xympMqzSDo52P .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nu7xympMqzSDo52P .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nu7xympMqzSDo52P .error-icon{fill:#552222;}#mermaid-svg-nu7xympMqzSDo52P .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nu7xympMqzSDo52P .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nu7xympMqzSDo52P .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nu7xympMqzSDo52P .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nu7xympMqzSDo52P .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nu7xympMqzSDo52P .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nu7xympMqzSDo52P .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nu7xympMqzSDo52P .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nu7xympMqzSDo52P .marker.cross{stroke:#333333;}#mermaid-svg-nu7xympMqzSDo52P svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nu7xympMqzSDo52P p{margin:0;}#mermaid-svg-nu7xympMqzSDo52P .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nu7xympMqzSDo52P .cluster-label text{fill:#333;}#mermaid-svg-nu7xympMqzSDo52P .cluster-label span{color:#333;}#mermaid-svg-nu7xympMqzSDo52P .cluster-label span p{background-color:transparent;}#mermaid-svg-nu7xympMqzSDo52P .label text,#mermaid-svg-nu7xympMqzSDo52P span{fill:#333;color:#333;}#mermaid-svg-nu7xympMqzSDo52P .node rect,#mermaid-svg-nu7xympMqzSDo52P .node circle,#mermaid-svg-nu7xympMqzSDo52P .node ellipse,#mermaid-svg-nu7xympMqzSDo52P .node polygon,#mermaid-svg-nu7xympMqzSDo52P .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nu7xympMqzSDo52P .rough-node .label text,#mermaid-svg-nu7xympMqzSDo52P .node .label text,#mermaid-svg-nu7xympMqzSDo52P .image-shape .label,#mermaid-svg-nu7xympMqzSDo52P .icon-shape .label{text-anchor:middle;}#mermaid-svg-nu7xympMqzSDo52P .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nu7xympMqzSDo52P .rough-node .label,#mermaid-svg-nu7xympMqzSDo52P .node .label,#mermaid-svg-nu7xympMqzSDo52P .image-shape .label,#mermaid-svg-nu7xympMqzSDo52P .icon-shape .label{text-align:center;}#mermaid-svg-nu7xympMqzSDo52P .node.clickable{cursor:pointer;}#mermaid-svg-nu7xympMqzSDo52P .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nu7xympMqzSDo52P .arrowheadPath{fill:#333333;}#mermaid-svg-nu7xympMqzSDo52P .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nu7xympMqzSDo52P .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nu7xympMqzSDo52P .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nu7xympMqzSDo52P .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nu7xympMqzSDo52P .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nu7xympMqzSDo52P .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nu7xympMqzSDo52P .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nu7xympMqzSDo52P .cluster text{fill:#333;}#mermaid-svg-nu7xympMqzSDo52P .cluster span{color:#333;}#mermaid-svg-nu7xympMqzSDo52P div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nu7xympMqzSDo52P .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nu7xympMqzSDo52P rect.text{fill:none;stroke-width:0;}#mermaid-svg-nu7xympMqzSDo52P .icon-shape,#mermaid-svg-nu7xympMqzSDo52P .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nu7xympMqzSDo52P .icon-shape p,#mermaid-svg-nu7xympMqzSDo52P .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nu7xympMqzSDo52P .icon-shape .label rect,#mermaid-svg-nu7xympMqzSDo52P .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nu7xympMqzSDo52P .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nu7xympMqzSDo52P .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nu7xympMqzSDo52P :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户接口层
Driver 驱动层
Metastore 元数据存储
执行引擎层
HDFS 存储层
CLI 命令行
JDBC/ODBC
Web UI
SQL Parser 解析器
Compiler 编译器
Optimizer 优化器
Executor 执行器
MySQL/Derby
MapReduce
Spark
Tez

各组件职责

(1)用户接口层(User Interface)

  • CLI:命令行接口,最常用。启动时会同时启动一个 Hive 副本
  • JDBC/ODBC:允许 Java/Python 等程序通过 JDBC 连接 Hive
  • Web UI:通过浏览器访问 Hive(较少使用)

(2)驱动层(Driver)

  • 解析器(SQL Parser):将 HQL 字符串转换为抽象语法树(AST),使用 ANTLR 完成词法语法分析
  • 编译器(Compiler):将 AST 编译生成逻辑执行计划
  • 优化器(Optimizer):对逻辑执行计划进行优化(如谓词下推、列裁剪)
  • 执行器(Executor):将优化后的逻辑执行计划转换成物理执行计划(MapReduce/Spark 作业)

(3)元数据存储(Metastore)

  • 存储表名、列信息、分区信息、表属性、数据所在 HDFS 路径等
  • 通常使用 MySQL 存储(生产环境),也支持 Derby(内嵌模式,仅用于测试)

(4)执行引擎层

  • 默认使用 MapReduce,也支持 Spark 和 Tez
  • 包含 * 的查询(如 SELECT * FROM tbl)不会生成 MapReduce 作业,直接读取文件

二、Hive 安装与部署

2.1 三种 Metastore 模式

Hive 的元数据存储(Metastore)有三种部署模式:
#mermaid-svg-w1OadyMje9HhmJm9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w1OadyMje9HhmJm9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w1OadyMje9HhmJm9 .error-icon{fill:#552222;}#mermaid-svg-w1OadyMje9HhmJm9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w1OadyMje9HhmJm9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w1OadyMje9HhmJm9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w1OadyMje9HhmJm9 .marker.cross{stroke:#333333;}#mermaid-svg-w1OadyMje9HhmJm9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w1OadyMje9HhmJm9 p{margin:0;}#mermaid-svg-w1OadyMje9HhmJm9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-w1OadyMje9HhmJm9 .cluster-label text{fill:#333;}#mermaid-svg-w1OadyMje9HhmJm9 .cluster-label span{color:#333;}#mermaid-svg-w1OadyMje9HhmJm9 .cluster-label span p{background-color:transparent;}#mermaid-svg-w1OadyMje9HhmJm9 .label text,#mermaid-svg-w1OadyMje9HhmJm9 span{fill:#333;color:#333;}#mermaid-svg-w1OadyMje9HhmJm9 .node rect,#mermaid-svg-w1OadyMje9HhmJm9 .node circle,#mermaid-svg-w1OadyMje9HhmJm9 .node ellipse,#mermaid-svg-w1OadyMje9HhmJm9 .node polygon,#mermaid-svg-w1OadyMje9HhmJm9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w1OadyMje9HhmJm9 .rough-node .label text,#mermaid-svg-w1OadyMje9HhmJm9 .node .label text,#mermaid-svg-w1OadyMje9HhmJm9 .image-shape .label,#mermaid-svg-w1OadyMje9HhmJm9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-w1OadyMje9HhmJm9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w1OadyMje9HhmJm9 .rough-node .label,#mermaid-svg-w1OadyMje9HhmJm9 .node .label,#mermaid-svg-w1OadyMje9HhmJm9 .image-shape .label,#mermaid-svg-w1OadyMje9HhmJm9 .icon-shape .label{text-align:center;}#mermaid-svg-w1OadyMje9HhmJm9 .node.clickable{cursor:pointer;}#mermaid-svg-w1OadyMje9HhmJm9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w1OadyMje9HhmJm9 .arrowheadPath{fill:#333333;}#mermaid-svg-w1OadyMje9HhmJm9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w1OadyMje9HhmJm9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w1OadyMje9HhmJm9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w1OadyMje9HhmJm9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w1OadyMje9HhmJm9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w1OadyMje9HhmJm9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w1OadyMje9HhmJm9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w1OadyMje9HhmJm9 .cluster text{fill:#333;}#mermaid-svg-w1OadyMje9HhmJm9 .cluster span{color:#333;}#mermaid-svg-w1OadyMje9HhmJm9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w1OadyMje9HhmJm9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w1OadyMje9HhmJm9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-w1OadyMje9HhmJm9 .icon-shape,#mermaid-svg-w1OadyMje9HhmJm9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w1OadyMje9HhmJm9 .icon-shape p,#mermaid-svg-w1OadyMje9HhmJm9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w1OadyMje9HhmJm9 .icon-shape .label rect,#mermaid-svg-w1OadyMje9HhmJm9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w1OadyMje9HhmJm9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w1OadyMje9HhmJm9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w1OadyMje9HhmJm9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 远程服务模式
Hive Client
Metastore Server
MySQL
直连数据库模式
Hive CLI
MySQL
内嵌Derby模式
Hive CLI
Derby DB

模式对比

模式 特点 适用场景
内嵌 Derby 单用户,数据存本地 单元测试(基本不用)
直连 MySQL 多用户,通过网络连接 小团队开发
远程服务 客户端/服务端分离,Thrift 协议 生产环境推荐

⚠️ 错误案例 1:Derby 模式多用户冲突

如果你在嵌入式 Derby 模式下尝试同时打开两个 Hive CLI 窗口,第二个窗口会报错:

复制代码
Caused by: ERROR XSDB6: Another instance of Derby may have already booted the database

原因 :Derby 内嵌模式只允许一个用户连接。

解决方案:切换到 MySQL 直连模式或远程服务模式。

2.2 MySQL 安装与配置

生产环境中,Metastore 通常使用 MySQL。以下是关键步骤:

bash 复制代码
# 1. 卸载系统自带的 mariadb-libs(与 MySQL 冲突)
rpm -qa | grep mariadb-libs
rpm -e --nodeps mariadb-libs

# 2. 安装 MySQL RPM 包(按顺序)
rpm -ivh mysql-community-common-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-compat-5.7.28-1.el7.x86_64.rpm

# 3. 修改 /etc/my.cnf 设置编码
# [client]
# default-character-set=utf8
# [mysql]
# default-character-set=utf8
# [mysqld]
# character_set_server=utf8

# 4. 初始化数据库
mysqld --initialize --user=mysql

# 5. 查看临时密码
grep 'temporary password' /var/log/mysqld.log

# 6. 启动并登录
systemctl start mysqld
mysql -uroot -p"临时密码"

# 7. 修改密码并授权远程登录
mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123456');
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;

2.3 直连数据库模式配置

核心配置文件 $HIVE_HOME/conf/hive-site.xml

xml 复制代码
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
    <!-- JDBC 连接 URL -->
    <property>
        <name>javax.jdo.option.ConnectionURL</name>
        <value>jdbc:mysql://node1:3306/hive?useSSL=false</value>
    </property>
    <!-- JDBC 驱动类 -->
    <property>
        <name>javax.jdo.option.ConnectionDriverName</name>
        <value>com.mysql.jdbc.Driver</value>
    </property>
    <!-- 数据库用户名 -->
    <property>
        <name>javax.jdo.option.ConnectionUserName</name>
        <value>root</value>
    </property>
    <!-- 数据库密码 -->
    <property>
        <name>javax.jdo.option.ConnectionPassword</name>
        <value>123456</value>
    </property>
    <!-- Hive 在 HDFS 的工作目录 -->
    <property>
        <name>hive.metastore.warehouse.dir</name>
        <value>/user/hive/warehouse</value>
    </property>
    <!-- 关闭元数据版本校验 -->
    <property>
        <name>hive.metastore.schema.verification</name>
        <value>false</value>
    </property>
    <!-- 关闭元数据事件通知授权 -->
    <property>
        <name>hive.metastore.event.db.notification.api.auth</name>
        <value>false</value>
    </property>
</configuration>

初始化元数据:

bash 复制代码
# 在 MySQL 中创建 hive 数据库
mysql> CREATE DATABASE hive;

# 初始化 Hive 元数据(会自动创建 74 张元数据表)
schematool -initSchema -dbType mysql -verbose

2.4 远程服务模式配置

生产环境推荐使用远程服务模式,实现客户端与服务端解耦:

服务端(node3)配置:与直连模式相同,额外启动 Metastore 服务

bash 复制代码
# 启动 Metastore 服务(默认端口 9083)
hive --service metastore &

# 或后台启动
nohup hive --service metastore > /dev/null 2>&1 &

客户端(node4)配置

xml 复制代码
<configuration>
    <!-- Hive 在 HDFS 的工作目录 -->
    <property>
        <name>hive.metastore.warehouse.dir</name>
        <value>/user/hive_remote/warehouse</value>
    </property>
    <!-- 指定 Metastore 服务地址 -->
    <property>
        <name>hive.metastore.uris</name>
        <value>thrift://node3:9083</value>
    </property>
    <!-- 关闭元数据版本校验 -->
    <property>
        <name>hive.metastore.schema.verification</name>
        <value>false</value>
    </property>
</configuration>

⚠️ 错误案例 2:日志 Jar 包冲突

启动 Hive 时如果报 ClassNotFoundException 或日志相关错误:

复制代码
Caused by: java.lang.NoClassDefFoundError: org/apache/logging/log4j/...

原因 :Hive 自带的 log4j-slf4j-impl-2.10.0.jar 与 Hadoop 的日志框架冲突。

解决方案:重命名该 jar 包使其不被加载:

bash 复制代码
mv $HIVE_HOME/lib/log4j-slf4j-impl-2.10.0.jar \
   $HIVE_HOME/lib/log4j-slf4j-impl-2.10.0.bak

三、Hive SQL 基础

3.1 数据库操作

sql 复制代码
-- 创建数据库
CREATE DATABASE IF NOT EXISTS hivedb1
COMMENT '我的第一个Hive数据库';

-- 创建数据库并指定 HDFS 存储位置
CREATE DATABASE hivedb2
LOCATION '/user/hive/custom/hivedb2';

-- 查看所有数据库
SHOW DATABASES;

-- 模糊匹配查询
SHOW DATABASES LIKE 'hivedb*';

-- 修改数据库属性
ALTER DATABASE hivedb1 SET DBPROPERTIES('author'='小爪');

-- 删除数据库(级联删除,会同时删除所有表)
DROP DATABASE IF EXISTS hivedb1 CASCADE;

3.2 Hive 数据类型

Hive 支持丰富的数据类型,分为基本类型和复杂类型两大类:

基本数据类型

类型 说明 示例
TINYINT 1字节有符号整数 127
SMALLINT 2字节有符号整数 32767
INT 4字节有符号整数 2147483647
BIGINT 8字节有符号整数 9223372036854775807
FLOAT 单精度浮点数 3.14
DOUBLE 双精度浮点数 3.1415926535
DECIMAL 精确小数 DECIMAL(10,2)
STRING 字符串 'hello hive'
VARCHAR(n) 变长字符串(v0.12+) VARCHAR(100)
CHAR(n) 定长字符串(v0.13+) CHAR(10)
BOOLEAN 布尔类型 TRUE / FALSE
TIMESTAMP 时间戳 '2021-11-18 13:24:43'
DATE 日期 '2021-11-18'
BINARY 字节数组 -

复杂数据类型

类型 说明 示例
ARRAY<T> 数组,元素类型相同 ARRAY<STRING> → 'lol','book','movie'
MAP<K,V> 键值对 MAP<STRING,STRING> → {'beijing':'xisanqi'}
STRUCT 结构体,可包含不同类型 STRUCT<name:STRING, age:INT>

3.3 创建表

完整建表语法

sql 复制代码
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
  [(col_name data_type [COMMENT col_comment], ...)]
  [COMMENT table_comment]
  [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
  [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
  [ROW FORMAT row_format]
  [STORED AS file_format]
  [LOCATION hdfs_path]
  [TBLPROPERTIES (property_name=property_value, ...)];

实战:创建包含复杂类型的表

sql 复制代码
-- 创建 person 表,包含 ARRAY 和 MAP 类型
CREATE TABLE person(
    id INT,
    name STRING,
    likes ARRAY<STRING>,           -- 爱好列表
    address MAP<STRING,STRING>      -- 地址信息
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','           -- 列分隔符
COLLECTION ITEMS TERMINATED BY '-' -- 数组/Map元素分隔符
MAP KEYS TERMINATED BY ':';        -- Map键值分隔符

-- 准备数据文件 person.txt:
-- 1,小明1,lol-book-movie,beijing:xisanqi-shanghai:pudong
-- 2,小明2,lol-book-movie,beijing:xisanqi-shanghai:pudong

-- 加载数据
LOAD DATA LOCAL INPATH '/root/data/person.txt' INTO TABLE person;

-- 查询验证
SELECT id, name, likes[0] AS first_like, address['beijing'] AS beijing_addr
FROM person;
-- 结果:
-- 1  小明1  lol  xisanqi
-- 2  小明2  lol  xisanqi

3.4 内部表与外部表

这是 Hive 中最重要的概念之一,很多生产事故都与此有关:

特性 内部表(MANAGED_TABLE) 外部表(EXTERNAL_TABLE)
数据管理 Hive 完全管理 用户自己管理
数据位置 默认在 /user/hive/warehouse 用户指定 LOCATION
DROP 行为 删除元数据 + 删除数据 只删除元数据,数据保留
适用场景 ETL 中间表、临时表 原始日志、共享数据

⚠️ 错误案例 3:误删内部表导致数据丢失

某数据分析师创建了一张内部表加载了 500GB 的原始日志数据,后来执行 DROP TABLE 想重建表结构,结果数据也被删除了。

原因 :内部表在 DROP 时会同时删除 HDFS 上的数据文件。

解决方案

  1. 原始数据表一定要用 CREATE EXTERNAL TABLE
  2. 如果已经创建了内部表,可以通过 ALTER TABLE tbl SET TBLPROPERTIES('EXTERNAL'='TRUE') 修改为外部表
sql 复制代码
-- 创建外部表
CREATE EXTERNAL TABLE access_log(
    ip STRING,
    log_time STRING,
    url STRING
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ' '
LOCATION '/user/data/access_logs';  -- 指定已有数据的 HDFS 路径

3.5 加载数据

LOAD DATA(推荐)

sql 复制代码
-- 从本地加载(数据会被上传到 HDFS)
LOAD DATA LOCAL INPATH '/root/data/person.txt' INTO TABLE person;

-- 从 HDFS 加载(数据会被移动到表目录)
LOAD DATA INPATH '/user/data/person.txt' INTO TABLE person;

-- 覆盖写入
LOAD DATA LOCAL INPATH '/root/data/person.txt' OVERWRITE INTO TABLE person;

INSERT 语句

sql 复制代码
-- 单条插入(会产生 MapReduce 作业,效率低)
INSERT INTO TABLE test VALUES(1, 18);

-- 从查询结果插入
INSERT INTO TABLE person_backup
SELECT * FROM person WHERE id > 5;

-- 多表插入(一次扫描,写入多张表)
FROM person
INSERT INTO TABLE person_man SELECT * WHERE gender = 'man'
INSERT INTO TABLE person_woman SELECT * WHERE gender = 'woman';

3.6 Hive 默认分隔符

Hive 的默认字段分隔符是 \001(即 ^A,ASCII 码为 1),这是一个不可见字符:

bash 复制代码
# 查看 Hive 表文件的实际内容
hdfs dfs -cat /user/hive_remote/warehouse/psn/000000_0
# 输出:1^A18  (肉眼无法分辨分隔符)

# 使用 cat -A 显示不可见字符
hdfs dfs -get /user/hive_remote/warehouse/psn/000000_0
cat -A 000000_0
# 输出:1^A18$

💡 这就是为什么建表时一定要指定 ROW FORMAT DELIMITED FIELDS TERMINATED BY ',',否则 Hive 使用默认的 ^A 分隔符,与常见的数据格式不兼容。


四、Hive 查询语句

4.1 基本查询

sql 复制代码
-- 全表查询
SELECT * FROM emp;

-- 指定列查询
SELECT empno, ename, sal FROM emp;

-- 列别名
SELECT ename AS name, sal AS salary FROM emp;

-- 算术运算
SELECT ename, sal, sal * 12 AS annual_salary FROM emp;

-- LIMIT 限制返回行数
SELECT * FROM emp LIMIT 10;

4.2 WHERE 条件过滤

sql 复制代码
-- 比较运算符:=, <>, <, >, <=, >=
SELECT * FROM emp WHERE sal > 3000;

-- BETWEEN ... AND
SELECT * FROM emp WHERE sal BETWEEN 2000 AND 5000;

-- IS NULL / IS NOT NULL
SELECT * FROM emp WHERE comm IS NULL;

-- IN / NOT IN
SELECT * FROM emp WHERE deptno IN (10, 20);

-- LIKE 模糊匹配
SELECT * FROM emp WHERE ename LIKE 'S%';  -- 以S开头
SELECT * FROM emp WHERE ename LIKE '_A%'; -- 第二个字母为A

4.3 聚合函数与分组

sql 复制代码
-- 常用聚合函数:COUNT, SUM, AVG, MIN, MAX
SELECT deptno, COUNT(*) AS cnt, AVG(sal) AS avg_sal
FROM emp
GROUP BY deptno;

-- HAVING 过滤分组结果
SELECT deptno, AVG(sal) AS avg_sal
FROM emp
GROUP BY deptno
HAVING AVG(sal) > 2500;

-- 注意:WHERE 在 GROUP BY 之前过滤行,HAVING 在 GROUP BY 之后过滤组
SELECT deptno, AVG(sal) AS avg_sal
FROM emp
WHERE sal > 1000           -- 先过滤行
GROUP BY deptno
HAVING AVG(sal) > 2500;    -- 再过滤组

4.4 JOIN 关联查询

sql 复制代码
-- INNER JOIN(内连接):只返回匹配的行
SELECT e.ename, d.dname
FROM emp e
JOIN dept d ON e.deptno = d.deptno;

-- LEFT JOIN(左外连接):返回左表所有行
SELECT e.ename, d.dname
FROM emp e
LEFT JOIN dept d ON e.deptno = d.deptno;

-- RIGHT JOIN(右外连接):返回右表所有行
SELECT e.ename, d.dname
FROM emp e
RIGHT JOIN dept d ON e.deptno = d.deptno;

-- FULL JOIN(全外连接):返回两表所有行
SELECT e.ename, d.dname
FROM emp e
FULL JOIN dept d ON e.deptno = d.deptno;

⚠️ 错误案例 4:笛卡尔积导致作业卡死

某同学写 SQL 时忘记写 JOIN 条件:

sql 复制代码
SELECT * FROM emp e, dept d;  -- 笛卡尔积!

如果 emp 有 1000 万行,dept 有 100 行,结果就是 10 亿行,MapReduce 作业直接跑崩。

解决方案

  1. 始终检查 JOIN 是否有 ON 条件
  2. 设置 hive.mapred.mode=strict 禁止不带条件的笛卡尔积查询

4.5 排序

Hive 中有四种排序方式,容易混淆:

排序方式 作用范围 特点
ORDER BY 全局排序 只有一个 Reduce,数据量大时极慢
SORT BY 每个 Reduce 内部排序 多个 Reduce,每个内部有序,全局不一定有序
DISTRIBUTE BY 控制 Map 输出分发到哪个 Reduce 通常配合 SORT BY 使用
CLUSTER BY DISTRIBUTE BY + SORT BY 的简写 当分区键和排序键相同时使用
sql 复制代码
-- ORDER BY:全局排序(慎重!数据量大时很慢)
SELECT * FROM emp ORDER BY sal DESC;

-- SORT BY:每个 Reducer 内部排序
SELECT * FROM emp SORT BY sal DESC;

-- DISTRIBUTE BY + SORT BY:先分区再排序
SELECT * FROM emp
DISTRIBUTE BY deptno   -- 按部门分区
SORT BY sal DESC;      -- 每个部门内按工资降序

-- CLUSTER BY:等价于 DISTRIBUTE BY + SORT BY(同字段)
SELECT * FROM emp CLUSTER BY deptno;

4.6 实战案例:基站掉话率分析

需求:从基站通话数据中找出掉话率最高的前 10 个基站。

sql 复制代码
-- 1. 创建原始数据表
CREATE TABLE jizhan(
    record_time STRING,
    imei INT,              -- 基站编号
    cell STRING,           -- 手机编号
    ph_num INT,
    call_num INT,
    drop_num INT,          -- 掉话秒数
    duration INT,          -- 通话持续总秒数
    drop_rate DOUBLE,
    net_type STRING,
    erl INT
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

-- 2. 加载数据(97万+条记录)
LOAD DATA LOCAL INPATH '/root/data/cdr_summ_imei_cell_info.csv'
INTO TABLE jizhan;

-- 3. 创建结果表
CREATE TABLE jizhan_result(
    imei STRING,
    drop_num INT,
    duration INT,
    drop_rate DOUBLE
);

-- 4. 计算掉话率并写入结果表
FROM jizhan
INSERT INTO jizhan_result
SELECT imei,
       SUM(drop_num) AS sdrop,
       SUM(duration) AS sdura,
       SUM(drop_num) / SUM(duration) AS drop_rate
GROUP BY imei
ORDER BY drop_rate DESC;

-- 5. 查看掉话率最高的前10个基站
SELECT * FROM jizhan_result LIMIT 10;

五、Hive 函数体系

5.1 函数分类总览

Hive 函数分为三大类:

类型 全称 特点 典型函数
UDF User-Defined Function 一进一出 round, upper, concat
UDAF User-Defined Aggregation Function 多进一出(聚合) count, sum, avg, max
UDTF User-Defined Table-Generating Function 一进多出(炸裂) explode, split

5.2 常用内置函数速查

数学函数

sql 复制代码
SELECT round(21.263, 2);    -- 21.26(四舍五入)
SELECT floor(21.9);          -- 21(向下取整)
SELECT ceil(21.1);           -- 22(向上取整)
SELECT rand();               -- 0~1 随机数
SELECT sqrt(16);             -- 4.0(平方根)
SELECT pow(2, 10);           -- 1024.0(幂运算)
SELECT abs(-10);             -- 10(绝对值)

字符串函数

sql 复制代码
SELECT length('hello');                    -- 5
SELECT reverse('abc');                     -- 'cba'
SELECT concat('hello', ' ', 'world');      -- 'hello world'
SELECT concat_ws('-', '2021', '11', '18'); -- '2021-11-18'
SELECT substr('hello world', 1, 5);        -- 'hello'
SELECT upper('hello');                     -- 'HELLO'
SELECT lower('HELLO');                     -- 'hello'
SELECT trim('  hello  ');                  -- 'hello'
SELECT lpad('abc', 10, '*');              -- '*******abc'
SELECT split('a,b,c', ',');               -- ['a','b','c']

日期函数

sql 复制代码
SELECT current_timestamp();                          -- 当前时间戳
SELECT unix_timestamp('2021-11-18 13:24:43');       -- 1637241883
SELECT from_unixtime(1637241883);                    -- '2021-11-18 13:24:43'
SELECT from_unixtime(1637241883, 'yyyy-MM-dd');      -- '2021-11-18'
SELECT datediff('2021-11-20', '2021-11-18');         -- 2(日期差)
SELECT date_add('2021-11-18', 7);                    -- '2021-11-25'
SELECT year('2021-11-18');                           -- 2021
SELECT month('2021-11-18');                          -- 11

条件函数

sql 复制代码
-- IF:条件判断
SELECT IF(1 > 0, 'yes', 'no');          -- 'yes'

-- COALESCE:返回第一个非 NULL 值
SELECT COALESCE(NULL, NULL, 'default');  -- 'default'

-- CASE WHEN:多条件判断
SELECT name,
       CASE WHEN age < 20 THEN '少年'
            WHEN age < 40 THEN '青年'
            WHEN age < 60 THEN '中年'
            ELSE '老年'
       END AS age_group
FROM person;

聚合函数(UDAF)

sql 复制代码
SELECT COUNT(*), COUNT(DISTINCT deptno) FROM emp;
SELECT SUM(sal), AVG(sal), MIN(sal), MAX(sal) FROM emp;
SELECT deptno, AVG(sal), STDDEV_POP(sal) FROM emp GROUP BY deptno;
SELECT COLLECT_SET(deptno) FROM emp;  -- 去重收集:[10,20,30]

表生成函数(UDTF)

sql 复制代码
-- explode:将数组拆分成多行
SELECT explode(split('hello world hive', ' '));
-- 结果:
-- hello
-- world
-- hive

-- explode 配合 Lateral View 使用
SELECT id, name, hobby
FROM person
LATERAL VIEW explode(likes) t AS hobby;
-- 结果:每个爱好一行

5.3 自定义 UDF 开发

当内置函数无法满足需求时,可以开发自定义函数。以下是一个手机号脱敏的 UDF 示例:

java 复制代码
package com.example.hive.udf;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

/**
 * 手机号脱敏 UDF
 * 13812345678 → 138****5678
 */
public class TuoMin extends UDF {
    public Text evaluate(final Text tt) {
        if (tt == null) {
            return null;
        }
        // 获取手机号码
        String phone = tt.toString();
        // 脱敏处理:保留前3位和后4位,中间用****替代
        String result = phone.substring(0, 3) + "****" + phone.substring(7);
        return new Text(result);
    }
}

部署和使用步骤:

bash 复制代码
# 1. 将项目打成 jar 包并上传到服务器
# 2. 在 Hive 中添加 jar
hive> ADD JAR /root/data/hive-udf.jar;

# 3. 创建临时函数
hive> CREATE TEMPORARY FUNCTION tuomin AS 'com.example.hive.udf.TuoMin';

# 4. 使用函数
hive> SELECT tuomin('13812345678') FROM dual;
-- 结果:138****5678

# 5. 删除临时函数
hive> DROP TEMPORARY FUNCTION tuomin;

UDF 开发注意事项

  1. 必须继承 org.apache.hadoop.hive.ql.exec.UDF
  2. 必须实现 evaluate() 方法,支持重载
  3. UDAF 需要继承 org.apache.hadoop.hive.ql.exec.UDAF,并实现内部类 UDAFEvaluator
  4. UDAF 的 Evaluator 需要实现 init(), iterate(), terminatePartial(), merge(), terminate() 五个方法

5.4 Hive 实现 WordCount

用 Hive SQL 实现经典的 WordCount:

sql 复制代码
-- 1. 创建原始数据表
CREATE TABLE words(line STRING);

-- 2. 加载数据
LOAD DATA LOCAL INPATH '/root/data/wc.txt' INTO TABLE words;
-- wc.txt 内容:
-- hello tom
-- andy joy
-- hello rose
-- hello joy

-- 3. WordCount 一条 SQL 搞定
SELECT word, COUNT(word) AS cnt
FROM (
    SELECT explode(split(line, ' ')) AS word
    FROM words
) tmp
GROUP BY word
ORDER BY cnt DESC;

-- 结果:
-- hello  4
-- joy    2
-- andy   2
-- tom    1
-- rose   1

六、Hive 参数与动态分区

6.1 Hive 参数配置

Hive 参数有三种设置方式(优先级从低到高):

方式 命令 作用范围
配置文件 hive-site.xml 全局永久
启动参数 hive --hiveconf key=value 当前会话
SET 命令 SET key=value; 当前会话
bash 复制代码
# 方式1:启动时设置
hive --hiveconf hive.cli.print.header=true

# 方式2:进入 CLI 后设置
hive> SET hive.cli.print.header=true;
hive> SET;  -- 查看所有参数

# 方式3:用户级初始化配置(~/.hiverc)
# 编辑 ~/.hiverc 文件,每行一个 SET 命令
# SET hive.cli.print.header=true;
# SET hive.exec.mode.local.auto=true;

6.2 动态分区

动态分区是 Hive 的一个重要特性,可以根据数据自动创建分区:

sql 复制代码
-- 开启动态分区(默认已开启)
SET hive.exec.dynamic.partition = true;

-- 设置动态分区模式为非严格模式
SET hive.exec.dynamic.partition.mode = nonstrict;

-- 创建原始数据表
CREATE TABLE person21(
    id INT,
    name STRING,
    age INT,
    gender STRING,
    likes ARRAY<STRING>,
    address MAP<STRING,STRING>
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':';

-- 创建分区表(按 age 和 gender 分区)
CREATE TABLE person22(
    id INT,
    name STRING,
    likes ARRAY<STRING>,
    address MAP<STRING,STRING>
)
PARTITIONED BY(age INT, gender STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':';

-- 动态分区插入(分区字段写在 SELECT 最后)
FROM person21
INSERT OVERWRITE TABLE person22 PARTITION(age, gender)
SELECT id, name, likes, address, age, gender;

-- 查看分区
SHOW PARTITIONS person22;
-- age=12/gender=boy
-- age=32/gender=man

动态分区相关参数

参数 默认值 说明
hive.exec.max.dynamic.partitions.pernode 100 每个节点最大动态分区数
hive.exec.max.dynamic.partitions 1000 所有节点最大动态分区总数
hive.exec.max.created.files 100000 所有 MR 作业最大创建文件数

七、Hive 分桶

7.1 分桶原理

分区是分目录存储,分桶是分文件存储。分桶通过对列值取哈希值取模,将数据分散到不同的文件中:
渲染错误: Mermaid 渲染失败: Parse error on line 2: ... A原始数据 --> B{hash(age) % 4} B --> -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

7.2 分桶实战

sql 复制代码
-- 创建分桶表(按 age 分 4 个桶)
CREATE TABLE psnbucket(
    id INT,
    name STRING,
    age INT
)
CLUSTERED BY (age) INTO 4 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

-- 从原始表导入数据
INSERT INTO TABLE psnbucket
SELECT id, name, age FROM psn31;

-- 查看 HDFS 上的分桶文件
-- hdfs dfs -ls /user/hive_remote/warehouse/psnbucket
-- 000000_0  (age=88,44)
-- 000001_0  (age=77,33)
-- 000002_0  (age=66,22)
-- 000003_0  (age=55,11)

分桶抽样查询

sql 复制代码
-- 语法:TABLESAMPLE(BUCKET x OUT OF y ON columns)
-- x:从第几个桶开始
-- y:必须是总桶数的倍数或因子

-- 总桶数=4,抽取第1和第3个桶(4/2=2个桶)
SELECT * FROM psnbucket TABLESAMPLE(BUCKET 1 OUT OF 2 ON age);

分区 vs 分桶

维度 分区(Partition) 分桶(Bucket)
存储方式 分目录 分文件
划分依据 字段值 字段哈希取模
数据粒度 粗粒度 细粒度
适用场景 按日期/地区等维度查询 数据抽样、JOIN 优化

八、Lateral View、视图与索引

8.1 Lateral View

Lateral View 用于和 UDTF 函数(如 explode)配合使用,解决"SELECT 中不能同时使用 UDTF 和普通列"的限制:

sql 复制代码
-- ❌ 错误写法:UDTF 不能和其他列一起 SELECT
SELECT id, name, explode(likes) FROM person;
-- FAILED: UDTF's are not supported outside the SELECT clause

-- ✅ 正确写法:使用 Lateral View
SELECT id, name, hobby, addr_key, addr_val
FROM person
LATERAL VIEW explode(likes) t1 AS hobby
LATERAL VIEW explode(address) t2 AS addr_key, addr_val;

8.2 Hive 视图

sql 复制代码
-- 创建视图
CREATE VIEW v_high_sal AS
SELECT * FROM emp WHERE sal > 3000;

-- 查询视图(和查表一样)
SELECT * FROM v_high_sal;

-- 删除视图
DROP VIEW IF EXISTS v_high_sal;

视图特点

  • 不支持物化视图(Hive 3.0+ 开始支持)
  • 只能查询,不能加载数据
  • 视图只是保存元数据,查询时才执行子查询
  • 支持迭代视图(视图嵌套视图)

8.3 Hive 索引(了解)

⚠️ 注意:索引在 Hive 3.0+ 版本中已废弃,不推荐使用。以下仅作了解。

sql 复制代码
-- 创建索引(Hive 2.x)
CREATE INDEX idx_name ON TABLE person2(name)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
WITH DEFERRED REBUILD;

-- 重建索引(必须执行才能生效)
ALTER INDEX idx_name ON person2 REBUILD;

-- 删除索引
DROP INDEX idx_name ON person2;

九、Hive 运行方式

9.1 命令行方式(CLI)

bash 复制代码
# 直接执行 SQL
hive -e "SELECT * FROM person"

# 静默模式(不显示 OK 和 Time taken)
hive -S -e "SELECT * FROM person"

# 将结果输出到文件
hive -e "SELECT * FROM person" > result.txt

# 执行 SQL 文件
hive -f /path/to/query.sql

# 初始化脚本(执行后进入交互模式)
hive -i init.sql

# 在 CLI 中执行 SQL 文件
hive> source /path/to/query.sql;

9.2 脚本运行方式(生产推荐)

bash 复制代码
#!/bin/bash
# hive_daily_etl.sh - 每日 ETL 脚本

# 定义变量
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)

# 执行 Hive SQL
hive -e "
SET hive.exec.dynamic.partition.mode=nonstrict;

-- 清洗数据并写入分区表
INSERT OVERWRITE TABLE dwd_user_behavior PARTITION(dt='${YESTERDAY}')
SELECT user_id, item_id, behavior_type, behavior_time
FROM ods_user_log
WHERE dt = '${YESTERDAY}'
  AND user_id IS NOT NULL;
"

# 检查执行结果
if [ $? -eq 0 ]; then
    echo "ETL 执行成功:${YESTERDAY}"
else
    echo "ETL 执行失败:${YESTERDAY}" >&2
    exit 1
fi

9.3 HDFS 交互

在 Hive CLI 中可以直接执行 HDFS 命令:

sql 复制代码
-- 查看 HDFS 目录
hive> dfs -ls /user/hive_remote/warehouse;

-- 查看文件内容
hive> dfs -cat /user/hive_remote/warehouse/person/000000_0;

-- 与 Linux 交互(以 ! 开头)
hive> !pwd;
hive> !ls /root;

十、总结与展望

10.1 核心知识回顾

本文从零开始系统讲解了 Hive 数据仓库的核心知识体系:

  1. Hive 本质:HQL → MapReduce 的翻译器,底层数据存 HDFS,计算靠 MR/Spark
  2. 三种 Metastore 模式:内嵌 Derby(测试)→ 直连 MySQL(开发)→ 远程服务(生产)
  3. 内部表 vs 外部表:DROP 内部表会删数据,外部表只删元数据------这是生产事故高发区
  4. 四种排序:ORDER BY(全局慢)→ SORT BY(Reduce内排序)→ DISTRIBUTE BY(分区)→ CLUSTER BY(分区+排序)
  5. 三大函数类型:UDF(一进一出)→ UDAF(多进一出)→ UDTF(一进多出)
  6. 分区与分桶:分区是分目录(粗粒度),分桶是分文件(细粒度)
  7. 动态分区 :自动根据数据值创建分区,需设置 nonstrict 模式

10.2 学习建议

  • 动手实践:Hive 是实践性很强的工具,建议搭建本地环境跟着敲一遍
  • 理解原理:不要只记语法,理解 HQL 如何转化为 MapReduce 作业
  • 关注性能:大数据场景下,一条 SQL 的写法差异可能导致执行时间差 100 倍
  • 多看官方文档https://cwiki.apache.org/confluence/display/Hive

10.3 参考链接

  1. Apache Hive 官方文档
  2. Hive Language Manual
  3. Hive 自定义函数开发指南
  4. Hadoop 官方文档
  5. Hive SQL 与 MySQL SQL 差异对比

下一篇预告

下一篇我们将进入 自然语言处理 领域,实战 文本分类项目------使用 TF-IDF 和机器学习算法对新闻文本进行自动分类。你将学到:

  • 中文文本分词(jieba)
  • TF-IDF 特征提取
  • 朴素贝叶斯与 SVM 分类器
  • 文本分类的评估指标(准确率、召回率、F1-Score)

敬请期待《Python大数据实战(六):文本分类------基于自然语言处理的新闻自动分类》!