【问题标题】:Hive DML transactions (Update/Delete) not working for subqueriesHive DML 事务(更新/删除)不适用于子查询
【发布时间】:2017-03-16 21:12:40
【问题描述】:

我知道 Hive/Hadoop 不适用于更新/删除,但我的要求是根据表 person21 的数据更新表 person20。随着 Hive 与 ORC 的进步,它支持 ACID,但看起来还不成熟。

$ hive --version 

Hive 1.1.0-cdh5.6.0

以下是我为测试更新逻辑而执行的详细步骤。

CREATE TABLE person20(
  persid int,
  lastname string,
  firstname string)
CLUSTERED BY (
  persid)
INTO 1 BUCKETS
ROW FORMAT SERDE
  'org.apache.hadoop.hive.ql.io.orc.OrcSerde'
STORED AS INPUTFORMAT
  'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat'
OUTPUTFORMAT
  'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'
LOCATION
  'hdfs://hostname.com:8020/user/hive/warehouse/person20'
TBLPROPERTIES (
  'COLUMN_STATS_ACCURATE'='true',
  'numFiles'='3',
  'numRows'='2',
  'rawDataSize'='348',
  'totalSize'='1730',
  'transactional'='true',
  'transient_lastDdlTime'='1489668385')

插入语句:

INSERT INTO TABLE person20 VALUES (0,'PP','B'),(2,'X','Y');

选择语句:

set hive.cli.print.header=true;

select * from person20;

persid lastname  firstname
2       X       Y
0       PP      B

我有另一个表是 person20 的副本,即 person21:

CREATE TABLE person21(
  persid int,
  lastname string,
  firstname string)
ROW FORMAT SERDE
  'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
STORED AS INPUTFORMAT
  'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  'hdfs://hostname.com:8020/user/hive/warehouse/person21'
TBLPROPERTIES (
  'COLUMN_STATS_ACCURATE'='true',
  'numFiles'='1',
  'numRows'='2',
  'rawDataSize'='11',
  'totalSize'='13',
  'transient_lastDdlTime'='1489668344')

插入语句:

INSERT INTO TABLE person20 VALUES (0,'SS','B'),(2,'X','Y');

选择语句:

select * from person21;

persid lastname firstname
2       X1       Y
0       SS       B

我想实现 MERGE 逻辑:

Merge into  person20 p20 USING person21 p21
ON (p20.persid=p21.persid)
WHEN MATCHED THEN
UPDATE set p20.lastname=p21.lastname
  • 但 Merge 不适用于我的 HIVE Hive 1.1.0-cdh5.6.0 版本。 这将从 Hive 2.2 开始提供。

其他选项是相关子查询更新:-

hive -e "set hive.auto.convert.join.noconditionaltask.size = 10000000; set hive.support.concurrency = true; set hive.enforce.bucketing = true; set hive.exec.dynamic.partition.mode = nonstrict; set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; set hive.compactor.initiator.on = true;
set hive.compactor.worker.threads = 1 ; UPDATE person20 SET lastname = (select lastname from person21 where person21.lastname=person20.lastname);" 
  • 此语句给出以下错误:-

使用配置初始化日志记录 jar:文件:/usr/lib/hive/lib/hive-common-1.1.0-cdh5.6.0.jar!/hive-log4j.properties NoViableAltException(224@[400:1: priorityEqualExpression : ( (left= priorityBitwiseOrExpression -> $left) ( ( KW_NOT priorityEqualNegatableOperator notExpr= 优先级位或表达式 ) -> ^( KW_NOT ^( precedenceEqualNegatableOperator $precedenceEqualExpression $notExpr) ) | (precedenceEqualOperator equalExpr=precedenceBitwiseOrExpression ) -> ^(precedenceEqualOperator $precedenceEqualExpression $equalExpr) | ( KW_NOT KW_IN LPAREN KW_SELECT )=> ( KW_NOT KW_IN subQueryExpression ) -> ^( KW_NOT ^( TOK_SUBQUERY_EXPR ^( TOK_SUBQUERY_OP KW_IN ) subQueryExpression $precedenceEqualExpression) ) | ( KW_NOT KW_IN 表达式) -> ^( KW_NOT ^( TOK_FUNCTION KW_IN $precedenceEqualExpression 表达式 ) ) | ( KW_IN LPAREN KW_SELECT )=> ( KW_IN subQueryExpression ) -> ^( TOK_SUBQUERY_EXPR ^( TOK_SUBQUERY_OP KW_IN ) subQueryExpression $precedenceEqualExpression) | ( KW_IN 表达式 ) -> ^( TOK_FUNCTION KW_IN $precedenceEqualExpression 表达式 ) | ( KW_NOT KW_BETWEEN (min= priorityBitwiseOrExpression ) KW_AND (max= 优先级位或表达式 ) ) -> ^( TOK_FUNCTION 标识符[“之间”] KW_TRUE $left $min $max) | ( KW_BETWEEN (分钟= priorityBitwiseOrExpression ) KW_AND (max= 优先级位或表达式 ) ) -> ^( TOK_FUNCTION 标识符[“之间”] KW_FALSE $left $min $max) )* | (KW_EXISTS LPAREN KW_SELECT )=> ( KW_EXISTS subQueryExpression ) -> ^( TOK_SUBQUERY_EXPR ^( TOK_SUBQUERY_OP KW_EXISTS ) subQueryExpression ) );]) 在 org.antlr.runtime.DFA.noViableAlt(DFA.java:158) 在 org.antlr.runtime.DFA.predict(DFA.java:116) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceEqualExpression(HiveParser_IdentifiersParser.java:8651) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceNotExpression(HiveParser_IdentifiersParser.java:9673) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceAndExpression(HiveParser_IdentifiersParser.java:9792) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceOrExpression(HiveParser_IdentifiersParser.java:9951) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.expression(HiveParser_IdentifiersParser.java:6567) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.atomExpression(HiveParser_IdentifiersParser.java:6791) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceFieldExpression(HiveParser_IdentifiersParser.java:6862) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceUnaryPrefixExpression(HiveParser_IdentifiersParser.java:7247) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceUnarySuffixExpression(HiveParser_IdentifiersParser.java:7307) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceBitwiseXorExpression(HiveParser_IdentifiersParser.java:7491) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedenceStarExpression(HiveParser_IdentifiersParser.java:7651) 在 org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.precedencePlusExpression(HiveParser_IdentifiersParser.java:7811) 在 org.apache.hadoop.hive.ql.parse.HiveParser.precedencePlusExpression(HiveParser.java:44550) 在 org.apache.hadoop.hive.ql.parse.HiveParser.columnAssignmentClause(HiveParser.java:44206) 在 org.apache.hadoop.hive.ql.parse.HiveParser.setColumnsClause(HiveParser.java:44271) 在 org.apache.hadoop.hive.ql.parse.HiveParser.updateStatement(HiveParser.java:44417) 在 org.apache.hadoop.hive.ql.parse.HiveParser.execStatement(HiveParser.java:1616) 在 org.apache.hadoop.hive.ql.parse.HiveParser.statement(HiveParser.java:1062) 在 org.apache.hadoop.hive.ql.parse.ParseDriver.parse(ParseDriver.java:201) 在 org.apache.hadoop.hive.ql.parse.ParseDriver.parse(ParseDriver.java:166) 在 org.apache.hadoop.hive.ql.Driver.compile(Driver.java:404) 在 org.apache.hadoop.hive.ql.Driver.compile(Driver.java:305) 在 org.apache.hadoop.hive.ql.Driver.compileInternal(Driver.java:1119) 在 org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1167) 在 org.apache.hadoop.hive.ql.Driver.run(Driver.java:1055) 在 org.apache.hadoop.hive.ql.Driver.run(Driver.java:1045) 在 org.apache.hadoop.hive.cli.CliDriver.processLocalCmd(CliDriver.java:207) 在 org.apache.hadoop.hive.cli.CliDriver.processCmd(CliDriver.java:159) 在 org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:370) 在 org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:305) 在 org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java:702) 在 org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:675) 在 org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:615) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.apache.hadoop.util.RunJar.run(RunJar.java:221) 在 org.apache.hadoop.util.RunJar.main(RunJar.java:136) FAILED: ParseException line 1:33 无法识别“选择”附近的输入 表达式规范中的“姓氏”“来自”

我认为它不支持子查询。同样的语句也适用于常量。

hive -e "set hive.auto.convert.join.noconditionaltask.size = 10000000; set hive.support.concurrency = true; set hive.enforce.bucketing = true; set hive.exec.dynamic.partition.mode = nonstrict; set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; set hive.compactor.initiator.on = true;
set hive.compactor.worker.threads = 1 ; UPDATE person20 SET lastname = 'PP' WHERE  persid = 0;"

--该语句成功更新记录。

能否请您帮助我找到在 HIVE 中执行 DML/Merge 操作的最佳策略。

【问题讨论】:

  • 旁注:即使 Hive 确实支持 UPDATE 的相关子查询,我很确定您的子查询不会给您预期的结果,引用:select lastname from person21 where person21.lastname=person20.lastname

标签: hadoop merge hive dml


【解决方案1】:

你可以通过蛮力做到这一点:

  • 重新创建表 person20 但不是 ACID,以虚拟列名称分区,并为“虚拟”使用单个分区
  • 填充person20person21
  • 使用与person20 完全相同的结构和相同的“虚拟”分区创建工作表tmpperson20
  • INSERT INTO tmpperson20 PARTITION (dummy='dummy') SELECT p20.persid, p21.lastname, ... FROM person20 p20 JOIN person21 p21 ON p20.persid=p21.persid
  • INSERT INTO tmpperson20 PARTITION (dummy='dummy') SELECT * FROM person20 p20 WHERE NOT EXISTS (select p21.persid FROM person21 p21 WHERE p20.persid=p21.persid)
  • ALTER TABLE person20 DROP PARTITION (dummy='dummy')
  • ALTER TABLE person20 EXCHANGE PARTITION (dummy='dummy') WITH tmpperson20
  • 现在你可以放弃tmpperson20

但是,由于分桶,使用 ACID 表可能会更棘手。


您也可以尝试使用在游标上迭代并在循环中应用单个 UPDATE 的过程语言。大量更新效率很低...

HPL/SQL 实用程序随 Hive 2.x 一起提供,可能安装在 Hive 1.x 之上,但我从未有机会尝试它。而且甲骨文方言在 Hive 上感觉很奇怪......!

或者您可以在循环中使用 JDBC ResultSetPreparedStatement 开发一些自定义 Java 代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-16
    • 2014-07-25
    • 1970-01-01
    • 2021-02-19
    • 2013-04-08
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多