【问题标题】:How to drop rows from partitioned hive table?如何从分区的配置单元表中删除行?
【发布时间】:2021-04-30 01:08:08
【问题描述】:

我需要从已分区的 Hive 表中删除特定行。这些要删除的行符合某些条件,因此不能为了这样做而删除整个分区。假设表Table 有三列:partner、date 和source_key,并由date 和source_key 分区。

已知不支持删除或更新 hive (See How to delete and update a record in Hive) 中的特定记录集的操作。

在this solution 之后,我成功执行了以下查询,以便保留仅匹配某些给定条件的记录,例如:属于date 的某个给定范围,具有source_key='heaven' 和专栏partner<>'angel'...

创建表Table的临时空副本。

CREATE TABLE IF NOT EXISTS tmpTable LIKE Table;

用当前行填充它。

INSERT OVERWRITE TABLE tmpTable
PARTITION (date,source_key)
SELECT * FROM Table
WHERE
date >= '2020-05-01' AND date < '2020-11-30' AND
source_key = 'heaven';

删除目标分区。

ALTER TABLE Table DROP IF EXISTS
PARTITION (source_key = 'heaven' , date >= '2020-05-01' , date < '2020-11-30' );

将已编辑的分区插入到目标表中。 (由于语法错误,无法插入 OVERWRITE)

INSERT INTO Table
PARTITION (source_key,date)
SELECT * FROM tmpTable
WHERE
partner <> 'angel';

删除临时表。

DROP TABLE IF EXISTS tmpTable;

查询运行良好。因为表 Table 是托管的,所以当分区被删除时,hdfs 文件应该被删除,但是有些地方是错误的(可能在最后一个 INSERT INTO 语句中),因为在执行所有这些查询之后目标表 Table 保持在给定的日期范围内所有带有partner = 'angel' 和带有 的记录基本上保持不变。

错在哪里?什么不见​​了?对于这样的 Hive 表,如何准确删除符合特定条件的特定行?

【问题讨论】:

  • 为什么分区规格不同:PARTITION (date,source_key) 和 PARTITION (source_key,date)?您不需要临时表。表分区可以直接从自身中选择覆盖。
  • 根据stackoverflow.com/questions/33230686/… 无法选择并插入到同一个表中。不过我还没试过。
  • 这不是它在 Hive 中的工作方式。首先,执行select,结果存储在temp目录中,如果没有异常,则将结果移动到目标表目录(select和write不是并发的)。 (当然该表不在 ACID 模式下)。在 ACID 模式下,无法进行 OVERWRITE。按照我的描述,在非 ACID 表中的 INSERT OVERWRITE 可以正常工作。这个问题是关于不同的会话。只需尝试一下,您就会看到它是如何工作的。

标签: hive hdfs delete-row hadoop-partitioning table-partitioning


【解决方案1】:

可以直接从自身选择 + WHERE 过滤器覆盖表分区。该方案非常简单,您不需要任何临时表。如果您不确定会发生什么,请制作备份表。

  1. 如果要删除整个分区(而不是覆盖),请执行

    ALTER TABLE TableName DROP IF EXISTS
    PARTITION (<partition spec to be dropped>); --check partition spec to be dropped carefully
    

如果没有要删除的分区,请跳过此步骤。

  1. 用过滤的行覆盖其他分区:

    set hive.exec.dynamic.partition=true;
    set hive.exec.dynamic.partition.mode=nonstrict;
    set hive.allow.move.on.s3=true; --If you are on Qubole/S3
    
    insert overwrite table TableName partition (date, source_key ) --partition spec should match table DDL
    select * from TableName 
     where <condition> --condition should be True for rows which NOT be deleted
    

您的代码相当混乱,因为您使用 LIKE 创建了临时表,但使用了不同的分区规范并选择了 *(与原始表中的列顺序相同)。列的顺序必须完全匹配,分区列是最后的,也是相同的顺序。

【讨论】:

  • 我会试试这个。但是,如果表很大并且只删除很少的注册,这将非常昂贵(因为它覆盖了整个表)并且&lt;condition&gt; 语句会很复杂。我想我可以在partition(...) 子句中设置要覆盖的分区,对吧?那么我只需要为这些分区声明&lt;condition&gt;,而不是覆盖整个表,比如parititon(source_key,date&gt;min_date, date&lt;max_date) ...这样行吗?
  • Insert overwrite ...select 将仅覆盖 select 返回的数据集中存在的分区,所有其他分区将保持覆盖前的状态,只需写入正确的 WHERE 并检查 select 返回的内容。跨度>
  • 您可以像这样使用静态分区覆盖:parititon(source_key='some_key', date='some_date')。在 drop 分区中可以使用 >
  • 好的,如stackoverflow.com/a/55758889/9106179 中所示:Insert overwrite table partition select ,,, 仅覆盖 select 返回的数据集中存在的分区。我要试试这个,让你知道结果如何......
  • 这个查询确实有效,但在某些情况下由于内存错误而失败:info=[Error: Failure while running task:java.lang.RuntimeException: java.lang.OutOfMemoryError: Java heap space,因此查询应该改进,有什么建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-13
  • 1970-01-01
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
  • 2020-01-23
  • 1970-01-01
相关资源
最近更新 更多