Hive — это система хранения данных на основе Hadoop, которая широко используется в крупных компаниях. Хранилище данных Meituan также построено на основе Hive, оно ежедневно выполняет около 10 000 вычислений Hive ETL и ежедневно отвечает за хранение и анализ сотен ГБ данных. Стабильность и производительность улья имеют решающее значение для нашего анализа данных.
В ходе нескольких обновлений Hive мы столкнулись с большими и маленькими проблемами. Благодаря консультациям с сообществом и нашим собственным усилиям, мы получили глубокое понимание процесса компиляции SQL в MapReduce в Hive при решении этих проблем. Понимание этого процесса не только помогает нам устранять некоторые ошибки Hive, но также помогает нам оптимизировать Hive SQL, улучшать наш контроль над Hive и иметь возможность настраивать некоторые необходимые функции.
Как MapReduce реализует базовые операции SQL
Прежде чем подробно объяснять компиляцию SQL в MapReduce, давайте рассмотрим принцип работы фреймворка MapReduce для реализации основных операций SQL.
Принцип реализации Join
select u.name, o.orderid from order o join user u on o.uid = u.uid;
Пометьте данные разных таблиц в выходном значении карты и оцените источник данных в соответствии с тегом на этапе сокращения. Процесс MapReduce выглядит следующим образом (здесь только для иллюстрации реализации самого простого соединения, есть и другие реализации)
Принцип реализации Group By
select rank, isonline, count(*) from city group by rank, isonline;
Объедините поля GroupBy в выходное значение ключа Map и используйте сортировку MapReduce, чтобы сохранить LastKey на этапе Reduce, чтобы различать разные ключи. Процесс MapReduce выглядит следующим образом (конечно, это только для иллюстрации процесса агрегации без Hash на стороне Reduce):
Принцип реализации Distinct
select dealid, count(distinct uid) num from order group by dealid;
При наличии только одного поля Distinct, если Hash GroupBy на этапе Map не учитывается, необходимо только объединить поле GroupBy и поле Distinct в выходной ключ Map, использовать сортировку MapReduce и использовать поле GroupBy в качестве ключа Reduce, и сохранить LastKey на этапе Reduce, т.е. можно сделать дедупликацию
Что делать, если имеется несколько полей Distinct, как в следующем SQL-запросе?
select dealid, count(distinct uid), count(distinct date) from order group by dealid;
Есть две реализации:
Если вы все еще следуете методу поля Distinct выше, то есть методу реализации, показанному на рисунке ниже, вы не можете сортировать по uid и дате соответственно, и вы не можете дедуплицировать через LastKey, и вам все равно нужно дедуплицировать в памяти через Hash на этапе сокращения.
Второй способ реализации может нумеровать все Distinct поля, и генерировать n строк данных для каждой строки данных, тогда те же самые поля будут сортироваться отдельно.На данный момент на этапе Reduce нужно записать только LastKey для удаления дубликатов.
В этой реализации хорошо используется сортировка MapReduce и экономится потребление памяти при дедупликации на этапе сокращения, но недостатком является то, что увеличивается объем перетасовываемых данных.
Следует отметить, что при генерации значения Reduce, за исключением строки, в которой первое поле Distinct должно сохранить значение значения, поля значений других строк данных Distinct могут быть пустыми.
Процесс преобразования SQL в MapReduce
Поняв, как MapReduce реализует основные операции SQL, давайте посмотрим, как Hive преобразует SQL в задачи MapReduce Весь процесс компиляции разбит на шесть этапов:
Antlr определяет правила грамматики SQL, завершает лексический анализ SQL, анализ грамматики и преобразует SQL в абстрактное синтаксическое дерево AST Tree
Пройдите по дереву AST и абстрагируйте базовую единицу запроса QueryBlock.
Пройдите QueryBlock и транслируйте его в дерево операций выполнения OperatorTree.
Оптимизатор логического уровня выполняет преобразование OperatorTree, объединяет ненужные ReduceSinkOperators и уменьшает количество перемешиваемых данных.
Обход OperatorTree и преобразование в задачи MapReduce
Оптимизатор физического уровня преобразует задачи MapReduce и генерирует окончательный план выполнения.
Лексический анализ SQL фазы 1, синтаксический анализ
Antlr
Hive использует Antlr для реализации лексического и синтаксического анализа SQL. Antlr — это инструмент распознавания языков, который можно использовать для создания доменных языков. Я не буду здесь подробно представлять Antlr, просто нужно понимать, что с помощью Antlr для построения конкретного языка нужно только написать файл грамматики, определить лексические и грамматические правила замены, а Antlr завершает процесс лексического анализа, синтаксического анализа, семантического анализа. анализ и генерация промежуточного кода.
Файл определения правил грамматики в Hive — это файл Hive.g до версии 0.10.По мере того, как правила грамматики становятся все более и более сложными, класс синтаксического анализа Java, сгенерированный правилами грамматики, может превышать максимальный верхний предел файла класса Java. В версии 0.11 Hive.g разделен на 5 файлов, 4 файла для лексических правил HiveLexer.g и грамматических правил SelectClauseParser.g, FromClauseParser.g, IdentifiersParser.g, HiveParser.g.
Абстрактное синтаксическое дерево Дерево AST
После лексического и грамматического разбора, если вам нужно продолжить обработку выражения, используйте абстрактное синтаксическое дерево Antlr, чтобы преобразовать входное предложение в абстрактное синтаксическое дерево во время синтаксического анализа, а затем выполните дальнейшие шаги при обходе синтаксического дерева.
Следующая грамматика является правилом грамматики SelectStatement в Hive SQL. Можно увидеть, что SelectStatement содержитselect, from, where, groupby, having, orderbyОговорка о равенстве
(В следующих правилах грамматики стрелка указывает на переписывание исходного оператора. После перезаписи будут добавлены некоторые специальные слова для обозначения конкретной грамматики, например TOK_QUERY для обозначения блока запроса)
Чтобы подробно объяснить процесс преобразования SQL в MapReduce, вот простой пример SQL, который содержит подзапрос и, наконец, записывает данные в таблицу.
FROM
(
SELECT
p.datekey datekey,
p.userid userid,
c.clienttype
FROM
detail.usersequence_client c
JOIN fact.orderpayment p ON p.orderid = c.orderid
JOIN dim.user du ON du.userid = p.userid
WHERE p.datekey = 20131118
) base
INSERT OVERWRITE TABLE `test`.`customer_kpi`
SELECT
base.datekey,
base.clienttype,
count(distinct base.userid) buyer_count
GROUP BY base.datekey, base.clienttype
SQL генерирует дерево AST
Код Antlr для синтаксического анализа Hive SQL выглядит следующим образом: HiveLexerX и HiveParser — это классы лексического синтаксического анализа и синтаксического анализа, автоматически генерируемые Antlr после компиляции файла грамматики Hive.g. В этих двух классах выполняется сложный синтаксический анализ.
HiveLexerX lexer = new HiveLexerX(new ANTLRNoCaseStringStream(command)); // 词法解析,忽略关键词的大小写
TokenRewriteStream tokens = new TokenRewriteStream(lexer);
if (ctx != null) {
ctx.setTokenRewriteStream(tokens);
}
HiveParser parser = new HiveParser(tokens); // 语法解析
parser.setTreeAdaptor(adaptor);
HiveParser.statement_return r = null;
try {
r = parser.statement(); // 转化为AST Tree
} catch (RecognitionException e) {
e.printStackTrace();
throw new ParseException(parser.errors);
}
Окончательное сгенерированное дерево AST показано в правой части рисунка ниже (сгенерировано с помощью Antlr Works, редактора для написания файлов грамматики, предоставленного Antlr).На рисунке развернуты только несколько узлов скелета, а не полностью расширен. Подзапрос 1/2, соответствующий частям 1/2 справа
Обратите внимание, что внутренний подзапрос также создает узел TOK_DESTINATION. Пожалуйста, ознакомьтесь с грамматическими правилами SelectStatement выше, этот узел является узлом, специально добавленным при переписывании грамматики. Причина в том, что все данные запроса в Hive будут сохранены во временных файлах HDFS.Будь то промежуточный подзапрос или окончательный результат запроса, оператор Insert в конечном итоге запишет данные в каталог HDFS, где находится таблица.
В частности, после расширения предложения from подзапроса памяти получается следующее дерево AST.Каждая таблица создает узел TOK_TABREF, а условие соединения создает узел "=". Другие части SQL аналогичны и подробно описываться не будут.
Базовый стандартный блок SQL Phase2 QueryBlock
Дерево AST по-прежнему очень сложное и недостаточно структурировано для прямого преобразования в программы MapReduce.Преобразование дерева AST в QueryBlock необходимо для дальнейшего абстрагирования и структурирования SQL.
QueryBlock
QueryBlock — это самая основная единица SQL, включающая три части: источник ввода, процесс вычисления и вывод. Проще говоря, QueryBlock — это подзапрос.
На следующем рисунке представлена диаграмма классов связанных с QueryBlock объектов в Hive, поясняющая несколько важных свойств на диаграмме.
QB#aliasToSubq (представляющий атрибут aliasToSubq класса QB) содержит объект QB подзапроса, а значение ключа aliasToSubq является псевдонимом подзапроса.
QB#qbp означает, что QBParseInfo хранит структуру дерева AST данной части операции в базовой единице SQL. Insert, выходных данных может быть несколько), значением является соответствующий узел ASTNode, узел TOK_DESTINATION. Остальные свойства HashMap класса QBParseInfo соответственно сохраняют соответствующую связь между выходом и узлами ASTNode каждой операции.
QBParseInfo#JoinExpr содержит узел TOK_JOIN. QB#QBJoinTree — это структура синтаксического дерева соединения.
QB#qbm сохраняет метаинформацию каждой входной таблицы, такую как путь к таблице в HDFS, формат файла для сохранения данных таблицы и т. д.
QBExpr Этот объект используется для представления операций Union.
Дерево AST генерирует QueryBlock
Процесс генерации дерева AST QueryBlock является рекурсивным процессом. Он проходит по дереву AST по порядку, сталкивается с различными узлами токена и сохраняет их в соответствующих атрибутах. В основном он включает следующие процессы:
TOK_QUERY => Создать объект QB, рекурсивно зациклить дочерние узлы
TOK_FROM => сохранить часть синтаксиса имени таблицы в объекте QB TOK_INSERT => зациклить рекурсивно дочерние узлы
TOK_DESTINATION => сохраняет синтаксическую часть цели вывода в свойстве nameToDest объекта QBParseInfo
TOK_SELECT => сохранить синтаксическую часть выражения запроса в destToAggregationExprs, TOK_WHERE => сохранить синтаксис части Where в свойстве destToWhereExpr объекта QBParseInfo
Окончательный образец SQL создает два объекта QB.Отношения между объектами QB следующие: QB1 — это внешний запрос, а QB2 — подзапрос.
Логический оператор Phase3 Оператор
Operator
Задача MapReduce, окончательно сгенерированная Hive, этап Map и этап Reduce состоят из OperatorTree. Логический оператор должен выполнить одну конкретную операцию на этапе сопоставления или на этапе сокращения.
Основные операторы включаютTableScanOperator,SelectOperator,FilterOperator,JoinOperator,GroupByOperator,ReduceSinkOperator
Из названия можно догадаться, какую функцию выполняет каждый оператор.TableScanOperatorДанные исходной входной таблицы из интерфейса Map платформы MapReduce контролируют количество строк данных в отсканированной таблице, а отметка предназначена для извлечения данных из исходной таблицы;JoinOperatorЗавершите операцию Присоединения;FilterOperatorзавершить операцию фильтрации;ReduceSinkOperatorСериализировать комбинацию полей на стороне карты в ключ/значение сокращения, ключ раздела, который может отображаться только на этапе карты, а также отмечает конец этапа карты в программе MapReduce, сгенерированной Hive.
Передача данных оператора между этапами Map Reduce является потоковым процессом. После того, как каждый оператор завершает операцию над строкой данных, он передает данные дочернему оператору для вычисления.
Основные свойства и методы класса Operator следующие:
RowSchema представляет поля вывода оператора.
InputObjInspector OutputObjInspector анализирует поля ввода и вывода
processOp получает данные, переданные родительским оператором, и передает обработанные данные дочернему оператору для обработки.
После обработки оператором каждой строки данных в Hive поля будут перенумерованы.colExprMap записывает соответствие имён каждого выражения до и после обработки текущим оператором, что используется для трассировки имён полей на следующем этапе логики оптимизация.
Поскольку программа Hive MapReduce является динамической программой, то есть неизвестно, какую операцию будет выполнять задание MapReduce, которая может быть Join или GroupBy, поэтому Operator сохраняет все параметры, необходимые во время выполнения, в OperatorDesc и OperatorDesc перед отправкой задачи Serialized в HDFS, чтение из HDFS и десериализация перед выполнением задачи MapReduce. Расположение OperatorTree этапа карты в HDFS:Job.getConf("hive.exec.plan") + "/map.xml"
QueryBlock генерирует дерево операторов
QueryBlock создает дерево операторов, просматривая атрибуты сохраненного синтаксиса объектов QB и QBParseInfo, созданных в предыдущем процессе, включая следующие шаги:
QB#aliasToSubq => есть подзапрос, рекурсивный вызов
Поскольку все соединения Join/GroupBy/OrderBy должны быть завершены на этапе сокращения, ReduceSinkOperator будет сгенерирован до того, как будет сгенерирован оператор соответствующей операции, а поля будут объединены и сериализованы в ключ/значение сокращения, ключ раздела.
Затем подробно проанализируйте процесс создания OperatorTree из примера SQL.
Предварительный обход объектов QB, созданных на предыдущем этапе
Сначала по дочернему QueryBlockQB2#aliasToTabs {du=dim.user, c=detail.usersequence_client, p=fact.orderpayment}Сгенерировать TableScanOperator
обход предварительного заказаQBParseInfo#joinExprгенерироватьQBJoinTree,своего родаQBJoinTreeтакже является древовидной структурой,QBJoinTreeСохраните ASTNode левой и правой таблиц и псевдоним этого запроса, и результирующее дерево запросов будет выглядеть следующим образом.
обход предварительного заказаQBJoinTree, сгенерировать сначалаdetail.usersequence_clientиfact.orderpaymentДерево операций соединения
На рисунке TS=TableScanOperator RS=ReduceSinkOperator JOIN=JoinOperator
Создайте дерево операций соединения между промежуточной таблицей и dim.user
Согласно QB2QBParseInfo#destToWhereExprСоздайте оператор фильтра. На этом обход QB2 завершен.На следующем рисунке SelectOperator будет судить, нужно ли анализировать поле в соответствии с некоторыми условиями в соответствии с некоторыми условиями.
На рисунке FIL=FilterOperator SEL=SelectOperator
Согласно QB1QBParseInfo#destToGroupbyгенерироватьReduceSinkOperator + GroupByOperator
На рисунке GBY=GroupByOperator GBY[12] — агрегация HASH, то есть операция агрегации выполняется в памяти через Hash
После завершения окончательного анализаFileSinkOperator, записать данные в HDFS
На рисунке FS=FileSinkOperator
Оптимизатор логического уровня Phase4
Большинство оптимизаторов логического уровня достигают цели сокращения заданий MapReduce и перемешивания объема данных путем преобразования OperatorTree и объединения операторов.
название
эффект
② Оптимизатор SimpleFetch
Оптимизация агрегированных запросов без выражений GroupBy
② MapJoinProcessor
MapJoin, требует подсказок в SQL, версия 0.11 больше не используется
② BucketMapJoinOptimizer
BucketMapJoin
② Группировать по оптимизатору
Агрегация на стороне карты
① Сокращение SinkDeDupplication
Объединить редукторы с одним и тем же ключом раздела/сортировки в линейном OperatorTree
① PredicatePushDown
предикат
① Оптимизатор корреляции
Воспользуйтесь преимуществами корреляции в запросах, объедините задания с зависимостями, HIVE-2206
ColumnPruner
обрезка полей
Оптимизаторы ① в таблице — это все одно задание, выполняющее как можно больше операций/слияний. ② Все, чтобы уменьшить количество данных в случайном порядке, и даже не делать Уменьшить
Оптимизатор CorrelationOptimizer очень сложен и может использовать корреляцию в запросе для объединения связанных заданий, см.Hive Correlation Optimizer
Для примера SQL есть два оптимизатора, которые оптимизируют его. Роли этих двух оптимизаторов описаны ниже, и добавлена роль оптимизатора ReduceSinkDeDupplication.
Оптимизатор PredicatePushDown
Утверждают, что ранний оптимизатор продвигает FilterOperator в OperatorTree до TableScanOperator.
Оптимизатор NonBlockingOpDeDupProc
Оптимизатор NonBlockingOpDeDupProc объединяет SEL-SEL или FIL-FIL в один оператор.
Оптимизатор ReduceSinkDeDupplication
ReduceSinkDeDupplication может объединить два RS, которые линейно связаны. По сути, CorrelationOptimizer — это надмножество ReduceSinkDeDuplication, которое может сочетать линейные и нелинейные операции RS, но ReduceSinkDeDuplication, реализованный Hive в первую очередь
Например, следующая инструкция SQL
from (select key, value from src group by key, value) s select s.key group by s.key;
После первых нескольких этапов будет сгенерировано следующее OperatorTree.Два дерева соединены и здесь не рисуются вместе.
В это время, после обхода OperatorTree, вы можете найти значение ключа и вывод PartitionKey двумя RS до и после, как показано ниже.
Оптимизатор ReduceSinkDeDuplication обнаруживает: 1. ключ pRS полностью содержит ключ cRS, и порядок сортировки является постоянным 2. ключ pRS PartitionKey полностью содержит ключ раздела cRS. Если условия оптимизации соблюдены, план выполнения будет оптимизирован.
ReduceSinkDeDupplication удаляет оператор между childRS и parentheRS и childRS, зарезервированный ключ RS — это поля ключа и значения, а PartitionKey — поле ключа. Объединенное дерево операторов выглядит следующим образом:
Процесс Phase5 OperatorTree, генерирующий MapReduce Job
Процесс конвертации OperatorTree в MapReduce Job делится на следующие этапы
Создать MoveTask для выходной таблицы
Обход в глубину вниз от одного из корневых узлов OperatorTree
ReduceSinkOperator отмечает границы Map/Reduce, границы между несколькими заданиями.
Пройдите через другие корневые узлы, столкнитесь с JoinOperator и объедините MapReduceTask
Создайте StatTask для обновления метаданных
Сократите отношение оператора между Map и Reduce
Создать MoveTask для выходной таблицы
На предыдущем шаге оператором OperatorTree был сгенерирован только один FileSinkOperator, а MoveTask был сгенерирован непосредственно для завершения перемещения окончательно сгенерированного временного файла HDFS в целевой каталог таблицы.
MoveTask[Stage-0]
Move Operator
начать движение
Сохраните все корневые узлы в OperatorTree в массиве toWalk и зациклите элементы в массиве (QB1 опущен, не показан)
Возьмите последний элемент TS[p] и поместите его в стек opStack{TS[p]}
Правило №1 TS% Создать объект MapReduceTask, определить MapWork
Обнаружено, что элементы в стеке соответствуют следующему правилу R1 (представленному здесь кодом Python)
"".join([t + "%" for t in opStack]) == "TS%"
генерироватьMapReduceTask[Stage-1]объект,MapReduceTask[Stage-1]объектMapWorkСвойство содержит ссылку на корневой узел оператора. Из-за отношения Parent Child между OperatorTree в настоящее время MapReduceTask[Stage-1] содержит все операторы с TS[p] в качестве корня.
Правило №2 TS%.*RS% Определить ReduceWork
Продолжайте обход подоператоров TS[p] и сохраняйте подоператоры в стеке opStack После того, как первый RS будет помещен в стек, то есть когда стек opStack = {TS[p], FIL[ 18], RS[4]}, то удовлетворяло бы следующему правилу R2
"".join([t + "%" for t in opStack]) == "TS%.*RS%"
В настоящее времяMapReduceTask[Stage-1]объектReduceWorkсохранение собственностиJOIN[5]цитаты
Правило №3 RS%.*RS% Создание нового объекта MapReduceTask и разделение MapReduceTask
Продолжить обход подоператора JOIN[5] и сохранить подоператор в стеке opStack.
Когда второй RS помещается в стек, то есть когда стекopStack = {TS[p], FIL[18], RS[4], JOIN[5], RS[6]}, то выполняется следующее правило R3
"".join([t + "%" for t in opStack]) == “RS%.*RS%” # 循环遍历opStack的每一个后缀数组
Теперь создайте новыйMapReduceTask[Stage-2]объект, изменяя OperatorTree сJOIN[5]иRS[6]вырезать между ними, и дляJOIN[5]Генерация дочернего оператораFS[19],RS[6]генерироватьTS[20],MapReduceTask[Stage-2]объектMapWorkсохранение собственностиTS[20]цитаты.
вновь сгенерированныйFS[19]Загрузите промежуточные данные и сохраните их во временных файлах HDFS.
Продолжить обход субоператора RS[6] и сохранить субоператор в стеке opStack
когдаopStack = {TS[p], FIL[18], RS[4], JOIN[5], RS[6], JOIN[8], SEL[10], GBY[12], RS[13]}, то выполняется правило R3
Сгенерировать таким же образомMapReduceTask[Stage-3]объект и вырезать OperatorTree из Stage-2 и Stage-3
Rule4 FS% соединяет MapReduceTask и MoveTask
После окончательного помещения всех дочерних операторов в стек,opStack = {TS[p], FIL[18], RS[4], JOIN[5], RS[6], JOIN[8], SEL[10], GBY[12], RS[13], GBY[14], SEL[15], FS[17]}Удовлетворить правилу R4
"".join([t + "%" for t in opStack]) == “FS%”
В это время будетMoveTaskиMapReduceTask[Stage-3]объединить и создатьStatsTask, изменить метаинформацию таблицы
Объединить этапы
На этом все не закончилось, остались еще два непройденных корневых узла
Очистите стек opStack и добавьте в стек второй элемент toWalk. найдуopStack = {TS[du]}Продолжайте удовлетворять R1 TS%, генерируйтеMapReduceTask[Stage-5]
Продолжайте движение вниз от TS[du], когдаopStack={TS[du], RS[7]}когда выполняется правило R2 TS%.*RS%
В это время будетJOIN[8]Сохранить какMapReduceTask[Stage-5]изReduceWorkКогда найдена связь между оператором, сохраненным в объекте карты, и объектом MapReduceWork.Map<Operator, MapReduceWork>найденный в объекте,JOIN[8]уже существует. В это время будетMapReduceTask[Stage-2]иMapReduceTask[Stage-5]Объединены в одну MapReduceTask
Аналогично из последнего корневого узлаTS[c]Начать обход, также объединить MapReduceTask
Разделить карту Уменьшить этап
Последний этап — вырезать OperatorTree в MapWork и ReduceWork с RS в качестве границы.
OperatorTree генерирует обзор MapReduceTask
Наконец, всего генерируются 3 MapReduceTasks, как показано ниже.
Оптимизатор физического уровня Phase6
Принцип работы каждого оптимизатора здесь подробно описываться не будет, но оптимизатор MapJoin будет представлен отдельно.
Принцип MapJoin
Проще говоря, MapJoin считывает небольшую таблицу в память на этапе Map и последовательно сканирует большую таблицу, чтобы завершить соединение.
На приведенном выше рисунке представлена схема Hive MapJoin из статьи инженера Facebook Лийина Танга, представляющего слайс, оптимизированный с помощью Join.Из рисунка видно, что MapJoin разделен на два этапа:
Через MapReduce Local Task считывайте небольшие таблицы в память, генерируйте HashTableFiles и загружайте их в Distributed Cache, где HashTableFiles будут сжаты
Задание MapReduce На этапе Map каждый Mapper считывает HashTableFiles из распределенного кэша в память, последовательно сканирует большую таблицу, напрямую объединяется на этапе Map и передает данные следующей задаче MapReduce.
Если одна из двух таблиц Join является временной таблицей, будет сгенерирована ConditionalTask, чтобы определить, использовать ли MapJoin во время работы.
Оптимизатор CommonJoinResolver
Оптимизатор CommonJoinResolver преобразует CommonJoin в MapJoin Процесс преобразования выглядит следующим образом:
Обход дерева задач в глубину
Найдите JoinOperator и оцените размер данных левой и правой таблиц.
Для маленькой таблицы + большой таблицы => MapJoinTask, для маленькой/большой таблицы + промежуточной таблицы => ConditionalTask
Просмотрите задачи MapReduce, созданные на предыдущем этапе, и найдите, чтоMapReduceTask[Stage-2],JOIN[8]Одна из таблиц является временной, сначала сделайте глубокую копию Stage-2 (поскольку исходный план выполнения необходимо сохранить как план резервного копирования, поэтому вот копия плана выполнения), сгенерируйте MapJoinOperator вместо JoinOperator, а затем сгенерируйте MapReduceLocalWork для чтения Generate HashTableFiles из небольших таблиц и загрузки их в DistributedCache.
Преобразованный план выполнения MapReduceTask показан на следующем рисунке.
Оптимизатор MapJoinResolver
Оптимизатор MapJoinResolver просматривает дерево задач и разбивает все задачи MapReduceTask с локальной работой на две задачи.
После обработки окончательного MapJoinResolver план выполнения показан на следующем рисунке.
Проектирование процесса компиляции Hive SQL
Из всего процесса компиляции SQL, упомянутого выше, видно, что дизайн процесса компиляции имеет несколько преимуществ, которые стоит изучать и изучать.
Использование программного обеспечения с открытым исходным кодом Antlr для определения правил грамматики значительно упрощает процесс компиляции и анализа лексики и грамматики, и требуется только поддерживать файл грамматики.
Общая идея очень ясна.Поэтапный дизайн упрощает поддержку всего кода процесса компиляции, что позволяет удобно переключать различные последующие оптимизаторы подключаемым способом.Например, последние функции Hive 0.13, векторизация и поддержка движка Tez подключаемые.
Каждый оператор выполняет только одну функцию, что упрощает всю программу MapReduce.