【问题标题】:Why does Hive warn that this subquery would cause a Cartesian product?为什么 Hive 会警告此子查询会导致笛卡尔积?
【发布时间】:2019-06-07 23:18:07
【问题描述】:

根据 Hive 的 documentation,它支持 WHERE 子句中的 NOT IN 子查询,前提是子查询是不相关的子查询(不引用主查询中的列)。

但是,当我尝试运行下面的简单查询时,我收到错误 FAILED: SemanticException Cartesian products are disabled for safety reasons.

-- sample data
CREATE TEMPORARY TABLE foods (name STRING);
CREATE TEMPORARY TABLE vegetables (name STRING);

INSERT INTO foods VALUES ('steak'), ('eggs'), ('celery'), ('onion'), ('carrot');
INSERT INTO vegetables VALUES ('celery'), ('onion'), ('carrot');

-- the problematic query
SELECT *
FROM foods
WHERE foods.name NOT IN (SELECT vegetables.name FROM vegetables)

请注意,如果我使用 IN 子句而不是 NOT IN 子句,它实际上可以正常工作,这令人困惑,因为在任何一种情况下查询评估结构都应该相同。

是否有解决此问题的方法,或者是否有其他方法可以根据查询中的值是否存在于另一个表中来过滤它们?

这是 Hive 2.3.4 btw,在 Amazon EMR 集群上运行。

【问题讨论】:

    标签: join hive hiveql cross-join notin


    【解决方案1】:

    不知道为什么你会得到这个错误。一种解决方法是使用not exists

    SELECT f.*
    FROM foods f
    WHERE NOT EXISTS (SELECT 1 
                      FROM vegetables v
                      WHERE v.name = f.name)
    

    left join

    SELECT f.*
    FROM foods f 
    LEFT JOIN vegetables v ON v.name = f.name
    WHERE v.name is NULL
    

    【讨论】:

    • 谢谢!我实际上使用NOT EXISTS 子查询得到了同样的错误,但是基于连接的方法现在有效。如果 Hive 开发团队中的任何一个可以参与进来,我会很感兴趣——这几乎感觉像是一个错误(或其他非常不直观的东西。)
    【解决方案2】:

    你得到了笛卡尔连接,因为这是 Hive 在这种情况下所做的。 vegetables 表非常小(只有一行),它正在被广播以执行交叉(很可能是映射连接,检查计划)连接。 Hive 首先交叉(映射)连接,然后应用过滤器。 @VamsiPrabhala 所说的带有过滤器的显式左连接语法将强制执行左连接,但在这种情况下它的工作原理相同,因为表非常小并且 CROSS JOIN 不会乘以行。

    对您的查询执行 EXPLAIN,您将看到到底发生了什么。

    【讨论】:

      猜你喜欢
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-15
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多