Почему Hive предупреждает, что этот подзапрос вызовет декартово произведение? - PullRequest
0 голосов
/ 14 января 2019

Согласно документации Hive он поддерживает подзапросы NOT IN в предложении WHERE, при условии, что подзапрос является некоррелированным подзапросом (не ссылается на столбцы из основного запроса).

Однако, когда я пытаюсь выполнить приведенный ниже тривиальный запрос, я получаю сообщение об ошибке 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, работающий в кластере Amazon EMR.

Ответы [ 2 ]

0 голосов
/ 14 января 2019

У вас есть декартово объединение, потому что именно это и делает в этом случае Hive. Таблица vegetables очень мала (всего одна строка), и она транслируется для выполнения перекрестного соединения (наиболее вероятно, map-join, проверьте план). Hive сначала объединяет (сопоставляет) соединение, а затем применяет фильтр. Явный синтаксис левого соединения с фильтром, как сказал @VamsiPrabhala, заставит выполнять левое соединение, но в этом случае оно работает так же, потому что таблица очень мала и CROSS JOIN не умножает строки.

Выполните EXPLAIN по вашему запросу, и вы увидите, что именно происходит.

0 голосов
/ 14 января 2019

Не уверен, почему вы получите эту ошибку. Обходной путь - использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...