【问题标题】:Hive, how to partition by a colum with null values, putting all nulls in one partitionHive,如何按具有空值的列进行分区,将所有空值放在一个分区中
【发布时间】:2022-01-03 21:56:21
【问题描述】:

我正在使用 Hive,IDE 是 Hue。我正在尝试为我的分区键选择不同的组合键。

我原表的定义如下:

CREATE External Table `my_hive_db`.`my_table`(
    `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_day` string
    )
    PARTITIONED BY ( 
      `date_year` string, 
      `date_month` 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://some/where/in/amazon/s3'; 

以上代码运行正常。但是当我使用 date_day 作为分区键创建一个新表时,该表是空的,我需要运行 MSCK 修复表。但是,我收到以下错误:

编译语句时出错:FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.ddl.DDLTask

分区键为date_year、date_month时,MSCK正常工作。

我收到错误的表的表定义如下:

CREATE External Table `my_hive_db`.`my_table`(
    `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://some/where/in/amazon/s3'; 

在此之后,以下查询为空:

Select * From `my_hive_db`.`my_table` Limit 10;

因此我运行了以下命令:

MSCK REPAIR TABLE `my_hive_db`.`my_table`;

我收到错误:编译语句时出错:FAILED:执行错误,从 org.apache.hadoop.hive.ql.ddl.DDLTask 返回代码 1

我检查了this link,因为这正是我遇到的错误,但使用提供的解决方案:

set hive.msck.path.validation=ignore;
MSCK REPAIR TABLE table_name;

我得到一个不同的错误:

处理语句时出错:无法在运行时修改 hive.msck.path.validation。它不在允许在运行时修改的参数列表中。

我认为我收到这些错误的原因是有超过 2 亿条 date_day 具有空值的记录。

有 31 个不同的 date-day not null 值。 我想用 32 个分区对我的表进行分区,每个分区都有一个不同的 date_day 字段值,并且所有空值都进入不同的分区。有没有办法这样做(按具有空值的列分区)?

如果这可以通过spark实现,我也愿意使用。

这是通过重新创建表来更改分区键的更大问题的一部分in this link in answer to my other question

感谢您的帮助。

【问题讨论】:

  • 无法在运行时修改 hive.msck.path.validation。 --> 您只需要更改配置并重新启动 hive 即可解决此问题。或者将该值添加到您可以在运行时修改的参数列表中。
  • 您似乎正在尝试重新分区现有表。分区是表位置下的文件夹,包含数据文件。您不能更改现有表上的分区架构。数据应根据分区组织在文件夹中。创建新表并从第一个表加载数据,请参阅 stackoverflow.com/a/53598283/2700344stackoverflow.com/a/68760607/2700344stackoverflow.com/a/68740919/2700344
  • 添加到leftjoin的评论。 Hive 是读取模式,它包含解释数据的定义。如果您更改如何读取数据的定义,它不会更改数据。它只是尝试读取您定义的数据。
  • 关于分区列中的空值:在插入时使用 NVL() 将它们替换为其他内容。数据文件中不存在分区列,它只是s3中的元数据+文件夹,看起来像key=value。如果在插入过程中 value 为 null,hive 会将此类记录放入 HIVE_DEFAULT_PARTITION 文件夹中。它会造成额外的混乱。所以用别的东西替换空值
  • Matt 我无法更改配置,因为它由数据湖团队管理。我正在使用该平台作为外部开发人员。有没有其他办法?

标签: apache-spark hadoop hive database-partitioning


【解决方案1】:

您似乎不明白 Hive 的分区是如何工作的。 Hive 将数据存储到 HDFS(或 S3,或其他一些分布式文件夹)上的文件中。 如果您创建一个名为my_schema.my_table 的非分区拼花表,您将看到在您的分布式存储中存储的文件夹中的文件

hive/warehouse/my_schema.db/my_table/part_00001.parquet
hive/warehouse/my_schema.db/my_table/part_00002.parquet
...

如果您创建一个按列p_col 分区的表,文件将如下所示

hive/warehouse/my_schema.db/my_table/p_col=value1/part_00001.parquet
hive/warehouse/my_schema.db/my_table/p_col=value1/part_00002.parquet
...
hive/warehouse/my_schema.db/my_table/p_col=value2/part_00001.parquet
hive/warehouse/my_schema.db/my_table/p_col=value2/part_00002.parquet
...

MSCK repair table 命令允许您在创建外部表时自动重新加载分区。

假设您在 s3 上有如下所示的文件夹:

hive/warehouse/my_schema.db/my_table/p_col=value1/part_00001.parquet
hive/warehouse/my_schema.db/my_table/p_col=value2/part_00001.parquet
hive/warehouse/my_schema.db/my_table/p_col=value3/part_00001.parquet

你创建一个外部表

CREATE External Table my_schema.my_table(
   ... some columns ...
)
PARTITIONED BY (p_col STRING)

表将被创建但为空,因为 Hive 尚未检测到分区。您运行 MSCK REPAIR TABLE my_schema.my_table,Hive 将识别出您的分区 p_col 与 s3 (/p_col=value1/) 上的分区方案匹配。

据我从your other question 了解到,您正试图通过这样做来更改表的分区方案

CREATE External Table my_schema.my_table(
   ... some columns ...
)
PARTITIONED BY (p_another_col STRING)

您收到一条错误消息,因为 p_another_col 与 s3 中使用的列 p_col 不匹配。 而且这个错误是完全正常的,因为你所做的没有意义。

the other question's answer 中所述,您需要使用不同的分区方案创建第一个表的副本。

你应该尝试这样的事情:

CREATE External Table my_hive_db.my_table_2(
    `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)

然后使用动态分区填充新表

INSERT OVERWRITE TABLE my_hive_db.my_table_2 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_1

【讨论】:

  • 谢谢 FurryMachine。前几天我尝试了您的解决方案,方法是创建一个带有新分区键的新表,并通过使用旧分区键从 table1 中 selectign 将数据插入其中。但是,该表包含 TB 的数据,它使生产仓库瘫痪超过 24 小时,导致其他作业失败。数据量大时,有没有其他更高效的解决方案?
  • 好吧,首先我建议您与贵公司的高级工程师讨论这个问题,然后再尝试任何危险的产品。你现在肯定引起了他们的注意。然后,一些建议:如果您的输入表按月分区并且您希望每天对表进行分区,您可以每个月运行一个查询,以使您的基础架构更加消化。但最重要的是,在全力以赴之前尝试对此进行 POC 并评估其影响。
  • 感谢 FurryMachine。你也有使用冰山分区键的经验吗?我试图了解它们与蜂巢有何不同:stackoverflow.com/questions/70211642/…
  • 不,我对 Iceberg 不是很熟悉,但我想说您可能正在寻找正确的方向,因为它旨在解决您似乎遇到的一些分区问题。你可能已经读过这个:iceberg.apache.org/#partitioning 和这个:developer.ibm.com/articles/…
猜你喜欢
  • 2019-05-25
  • 1970-01-01
  • 2014-11-11
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-20
相关资源
最近更新 更多