MapReduce внутри, снаружи или сбоку от параллельных СУБД

         

Синтаксис, семантика и особенности реализации SQL/MapReduce


Обсудим, как вызываются SQL/MapReduce-функции, как они определяются, и как обрабатываются SQL-запросы с вызовами таких функций.

Синтаксис вызова SQL/MapReduce-функции

Вызов SQL/MapReduce-функции может присутствовать только в качестве элемента списка ссылок на таблицы раздела FROM SQL-запроса. Синтаксис вызова показан на рис. 3.

SELECT ... FROM function_name( ON table-or-query [PARTITION BY expr, ...] [ORDER BY expr, ...] [clausename(arg, ...) ...] ) ...

Рис. 3. Синтаксис вызова SQL/MapReduce-функции

В разделе ON, который является единственным обязательным разделом вызова, указывается любой допустимый SQL/MapReduce-запрос (SQL-запрос, вызов SQL/MapReduce-функции или просто имя таблицы). Во время формирования плана запроса, содержащего вызов SQL/MapReduce-функции, схемой входной таблицы этого вызова считается схема результата запроса, указанного в разделе ON.

Раздел PARTITION BY указывается только в вызовах SQL/MapReduce-функций над разделами (аналоге функции Reduce исходной модели MapReduce, см. ниже). В этом случае в разделе PARTITION BY указывается список выражений, на основе значений которых производится разделение таблицы, специфицированной в разделе ON. При наличии раздела PARTITION BY в вызове может содержаться и раздел ORDER BY, указывающий на потребность в сортировке входных данных до реального вызова функции. Наконец, вслед за разделом ORDER BY можно указать произвольное число дополнительных разделов со специальными аргументами. Имена этих разделов и значения аргументов передаются в SQL/MapReduce-функцию при ее инициализации.

Модель выполнения SQL/MapReduce-функций

В среде SQL/MapReduce используется модель выполнения функций, являющаяся обобщением модели MapReduce. Функция SQL/MapReduce может быть либо функцией над строками (row function), либо функцией над разделами (partition function). Функции первого типа является аналогами функций Map классической модели MapReduce, а функции второго типа – аналогами функций Reduce. Поскольку, как отмечалось ранее, в разделе ON вызова SQL/MapReduce-функции может содержаться вызов другой SQL/MapReduce-функции, в среде SQL/MapReduce допускается любое число и любой порядок вызовов функций Map и Reduce, а не только жесткая последовательность Map-Reduce, допускаемая классической моделью.


При выполнении функции над строками каждая строка входной таблицы обрабатывается ровно одним экземпляром этой функции. С точки зрения семантики каждая строка обрабатывается независимо, поэтому входная таблица может разделяться по экземплярам функции произвольным образом, что обеспечивает возможности параллелизма и масштабирования. Для каждой строки входной таблицы функция над строками может не производить ни одной строки, а может произвести несколько строк.
При выполнении функции над разделами каждая группа строк, образованная на основе спецификации раздела PARTITION BY вызова функции, обрабатывается ровно одним экземпляром этой функции, и этот экземпляр получает все группу целиком. Если в вызове функции содержится раздел ORDER BY, то экземпляры функции получают разделы в уже упорядоченном виде. С точки зрения семантики каждая строка обрабатывается независимо, что обеспечивает возможности параллелизма на уровне разделов. Для каждого входного раздела функция над строками может не производить ни одной строки, а может произвести несколько строк.
Реализация SQL/MapReduce-функций
Как отмечалось в предыдущем пункте, для реализации SQL/MapReduce-функций можно использовать разные языки, но все они являются объектно-ориентированными. Каждая SQL/MapReduce-функция реализуется в виде отдельного класса, и при выработке плана выполнения SQL-запроса, содержащего вызовы таких функций, для каждого вызова образуется объект соответствующего класса с обращением к его методу-конструктору (инициализатору функции). Это обеспечивает настройку функции и получение требуемого описания ее результирующей таблицы.
Более точно, взаимодействие оптимизатора запросов с инициализатором функции производится через специальный объект, называемый контрактом времени выполнения (Runtime Contract). Анализируя вызов функции, оптимизатор выявляет имена и типы данных столбцов входной таблицы, а также имена и значения разделов дополнительных параметров и соответствующим образом заполняет некоторые поля объекта-контракта, который затем передается инициализатору функции. Инициализатор завершает подготовку контракта путем заполнения его дополнительных полей, содержащих, в частности, информацию о схеме результирующей таблицы, и обращается к методу complete объекта-контракта. На основе готового контракта продолжается выработка плана выполнения запроса, и этот контракт соблюдается при последующем выполнении SQL/MapReduce-функции всеми ее экземплярами.


Наиболее важными методами интерфейсов классов для функций над строками и разделами являются методы OperateOnSomeRows и OperateOnPartition. При обращении к этим методам (реальном выполнении соответствующей функции) в качестве аргументов передаются итератор над строками, для обработки которых вызывается функция, и объект emitter, с помощью вызовов которого возвращаются результирующие строки.
Чтобы можно было начать использовать некоторую SQL/MapReduce-функцию, ее нужно инсталлировать. Для этого используется общий механизм инсталляции файлов, реализованный в nCluster. Этот механизм реплицирует файл во всех рабочих узлах системы. Далее проверяется, что этот файл содержит SQL/MapReduce-функцию, а также выясняются ее статические свойства: является ли она функцией на строками или же над разделами, содержит ли она вызовы комбинатора и т.д.
Таким образом в этих двух системах обеспечивается возможность развитого анализа данных поблизости от самих данных. Разработчики серверных аналитических приложений несколько ограничиваются моделью MapReduce (в большей степени в Greenplum Database, в меньшей – в nCluster), но зато пользовательский процедурный код хорошо распараллеливается по данным в массивно-параллельной среде.

Содержание раздела