Hive如何对含null值的字段分区,将所有null值归入同一独立分区
问题根因
- 你新定义的按date_day分区的外部表与原年月分区表共用了同一个S3存储路径,该路径下只有
date_year=xxx/date_month=xxx格式的目录,不存在date_day=xxx格式的分区目录,导致MSCK REPAIR无法识别匹配分区,最终查询无结果、MSCK执行报错 hive.msck.path.validation参数无法在运行时修改,是因为集群管理员未将该参数加入允许用户动态修改的参数白名单,普通用户无权限调整
实现方案
你需要的32个分区(31个非null date_day对应分区 + 1个null值专属分区)可以通过以下两种方案实现,核心是将原始数据按date_day字段重新组织存储路径,适配按天分区的表结构。
方案1:Hive原生实现
无需修改集群配置,操作步骤如下:
- 保留你原本可以正常查询的年月分区原始表,作为数据源
- 新建按date_day分区的目标外部表,注意存储路径要和原始表路径完全独立,不能共用:
CREATE External Table `my_hive_db`.`my_table_day_part`( `col_id` bigint, `result_section__col2` string, `result_section_col3` string , `result_section_col4` string, `result_section_col5` string, `result_section_col6__label` string, `result_section_col7__label_id` bigint , `result_section_text` string , `result_section_unit` string, `result_section_col` string , `result_section_title` string, `result_section_title_id` bigint, `col13` string, `timestamp` bigint, `date_year` string, `date_month` string ) PARTITIONED BY (`date_day` string) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' LOCATION 's3a://your/new/path/for/day/partition/'; -- 新的独立路径
- 开启动态分区配置,从原始表读取数据写入目标表,自动处理null值分区:
-- 开启动态分区 set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; -- 自定义null值对应的分区名,方便后续识别 set hive.exec.default.partition.name=day_null; -- 写入数据,null的date_day会自动归入day_null分区 INSERT OVERWRITE TABLE `my_hive_db`.`my_table_day_part` PARTITION(date_day) SELECT col_id, result_section__col2, result_section_col3, result_section_col4, result_section_col5, result_section_col6__label, result_section_col7__label_id, result_section_text, result_section_unit, result_section_col, result_section_title, result_section_title_id, col13, `timestamp`, date_year, date_month, date_day FROM `my_hive_db`.`my_table`; -- 你最早的可正常查询的年月分区表
写入完成后即可直接查询数据,总共会生成32个分区。
方案2:Spark实现方案
适合超大数据量场景,执行效率更高:
import org.apache.spark.sql.functions._ // 读取原始年月分区表数据 val originalDF = spark.table("my_hive_db.my_table") // 将date_day字段的null值替换为自定义的分区标识 val processedDF = originalDF .withColumn("date_day", when(col("date_day").isNull, lit("day_null")).otherwise(col("date_day"))) // 按date_day分区写入数据,自动生成对应目录结构 processedDF.write .partitionBy("date_day") .format("parquet") .mode("overwrite") .option("path", "s3a://your/new/path/for/day/partition/") // 新的独立存储路径 .saveAsTable("my_hive_db.my_table_day_part")
写入完成后即可直接查询目标表,分区会自动同步到Hive元数据。
内容的提问来源于stack exchange,提问作者E. Erfan
相关产品推荐
相关产品推荐

