TL;DR

  • 场景:离线数仓 ODS 层落地,Hive 外部表承接日志,按天分区管理,JSON 字段按需解析与展开
  • 结论:ODS 保持”贴源 + 分区 + 外部表”,JSON 解析优先 json_tuple 批量取字段,展开用 explode + lateral view
  • 产出:ODS 建表模板、分区增删 SQL、按天装载脚本骨架、JSON 单值/数组/展开查询范式

整体结构

ODS层

ODS的定义

ODS是一种面向操作层的数据存储,专注于支持企业的日常运营。它通常整合了来自不同数据源(如ERP、CRM、销售系统等)的数据,通过清洗、转换后存储,以便快速查询和使用。ODS不以历史数据分析为主要目的,而是以操作和事务处理为核心。

ODS的特性

  • 实时性或近实时性:ODS中的数据通常是实时或近实时的,能够快速反映业务系统中的最新状态,支持企业的及时决策。
  • 数据整合:ODS整合来自多个源系统的数据,提供统一视图。它会通过ETL(提取、转换、加载)工具对数据进行处理。
  • 非历史性:ODS数据的生命周期相对较短,通常只保存当前或最近的数据,不会长期存储历史数据。
  • 面向操作:ODS的设计重点在于支持操作和事务处理,例如快速查询当前的客户订单状态,而不是复杂的分析或建模。

ODS的架构

ODS通常包含以下主要部分:

  • 数据输入层:从事务系统中提取原始数据(可能来自不同的数据源)。使用ETL工具对数据进行初步清洗和转换。
  • 数据存储层:存储经过整合的数据,通常以面向主题的形式组织。数据存储可以是关系型数据库(如MySQL、PostgreSQL)或其他支持快速查询的数据库。
  • 数据访问层:为操作型应用提供快速查询接口。可能支持API、SQL查询或直接集成到企业应用中。

创建ODS层

use ods;
create external table ods.ods_start_log(
  `str` string
) comment '用户启动日志信息'
partitioned by (`dt` string)
location '/user/data/logs/start';

加载ODS层数据

#!/bin/bash
APP=ods
source /etc/profile
# 可以输入日期;如果未输入日期取昨天的时间
if [ -n "$1" ]
then
do_date=$1
else
do_date=`date -d "-1 day" +%F`
fi
# 定义要执行的SQL
sql="
alter table "$APP".ods_start_log add partition(dt='$do_date');
"
hive -e "$sql"

JSON数据处理

数据文件中每行必须要是一个完整的JSON字符串,一个JSON串不能穿越多行,Hive处理JSON数据总体来说有三个办法:

  1. 使用内建的函数get_json_object,json_tuple
  2. 使用自定义的UDF
  3. 第三方的SerDe

内建函数

get_json_object(string json_string, string path)

  • 返回值:String
  • 说明:解析JSON字符串json_string,返回path指定的内容,如果输入的JSON字符串无效,那么返回NULL,函数每次只返回一个数据项。

json_tuple(jsonStr, k1, k2…)

  • 返回值:所有的输入参数,输出参数都是String
  • 说明:参数为一组 k1,k2等等和JSON的字符串,返回值的元组,该方法比get_json_object高效,因此可以在一次调用中输入多个键

explode

使用explode将Hive一行中复杂的array或map结构拆分成多行。

JSON数据的处理示例

-- get 单层值
SELECT
  username, age, sex,
  get_json_object(json, "$.id") id,
  get_json_object(json, "$.ids") ids,
  get_json_object(json, "$.total_number") num
FROM jsont1;
-- 使用 json_tuple 一次处理多个字段
SELECT
  json_tuple(json, 'id', 'ids', 'total_number')
FROM jsont1;
-- 使用 explode + lateral view
SELECT username, age, sex, id, ids, num
FROM jsont1
lateral view json_tuple(json, 'id', 'ids', 'total_number') t1
AS id, ids, num;

with tmp AS (
SELECT username, age, sex, id, ids, num
FROM jsont1
lateral view json_tuple(json, 'id', 'ids', 'total_number') t1 AS id, ids, num)
SELECT username, age, sex, id, ids1, num
FROM tmp
lateral view explode(split(regexp_replace(ids, "\\[|\\]", ""), ",")) t1 AS ids1;

错误速查

症状根因定位修复
分区加了但查不到数据分区目录不存在或目录下无数据;只 add partition 不等于导入数据show partitions ods_start_log; 查看分区;检查 HDFS先把数据落到对应分区目录
LOCATION ‘/user/data/logs/start’ 下没有数据或权限报错HDFS 路径未创建/权限不足hdfs dfs -ls /user/data/logs/start创建目录并授权:hdfs dfs -mkdir -p …;hdfs dfs -chmod/-chown …
外部表删表后数据还在external table 元数据与数据分离desc formatted 看 Table Type明确外部表语义:删表不删 HDFS 文件
JSON 解析结果全是 NULLJSON 字符串不合法;路径写错抽样 select json from jsont1 limit 5;保证每行是完整 JSON 串且无多余字符