Примеры использования

Перед запуском примеров необходимо получить YT-токен.

Запускать примеры нужно из-под Linux без аргументов.

Рекомендуется установить уровень логирования в INFO или DEBUG, тогда программы будут выводить ссылки на веб-интерфейс, где можно следить за выполнением операций.

Уровень логирования устанавливается с помощью переменной окружения такой командой (см. так же документацию):

export YT_LOG_LEVEL=INFO

Для продакшн-процессов рекомендуется сохранять наиболее полные DEBUG логи. В случае возникновения каких-либо проблем они помогут понять, что происходило.

Базовый уровень

Простой Map (TNode-версия)

Предположим, что существует таблица с логинами. Необходимо сделать таблицу с email-адресами, вычислив их из логина email = login + "@domain".

Для этого подойдёт простой маппер.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/simple_map_tnode.

 'yt/cpp/mapreduce/tutorial/simple_map_tnode/main.cpp'

Простой Map (Protobuf-версия)

Если известно, как устроена таблица, то может быть удобно воспользоваться форматом Protobuf, который:

  • несколько быстрее;
  • помогает избежать опечаток в названиях колонок и проверит работу с типами.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/simple_map_protobuf.

Простой Map с Protobuf и использованием лямбда-выражений в C++

Некоторые достаточно простые операции можно представить в виде лямбда-выражений C++ с пустым capture-list (т. е. не захватывающих переменных) с использованием библиотеки yt/cpp/mapreduce/library/lambda.

Предыдущий пример может быть переписан так (data.proto такой же):

(yt/cpp/mapreduce/examples/tutorial/simple_map_lambda)

Сортировка таблицы и простая операция Reduce

Чтобы по той же таблице посчитать статистику, сколько раз встречается то или иное имя, можно использовать операцию Reduce. Однако, Reduce можно запускать только на сортированных таблицах, поэтому таблицу нужно сначала отсортировать.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/simple_reduce_tnode.

Сложные типы и формат Protobuf (на примере Reduce)

В качестве примера рассмотрим таблицу с набором записей про ссылки, которые встречаются в веб-документах. Таблица содержит колонки:

  • DocTitle — имя документа;
  • Link — структура с полями:
    • Host — часть ссылки, содержащая хост;
    • Port— часть ссылки, содержащая порт;
    • Path— часть ссылки, содержащая путь;
  • OccurrenceCount — количество встречаний данной ссылки в документе.

Таблица отсортирована по колонке DocTitle. Необходимо собрать информацию о каждом документе в одну строку выходной таблицы.

Опишем protobuf-сообщения следующего вида:

TLinkEntry соответствует строке входной таблицы, TDoc — строке выходной.

Поля TDoc имеют следующую семантику:

  • Title — заголовок;
  • Links— список ссылок, упомянутых в документе;
  • OccurrenceCounts — список количества вхождений соответствующих ссылок (длина этого списка равна длине списка Links);
  • ExtraInfo — дополнительная информация, в данном случае включающая суммарное количество вхождений ссылок.

Внимание

(NYT.field_serialization_mode) в сообщениях TDoc и TLinkEntry. Эта опция по умолчанию равна PROTOBUF, то есть "сериализовать поле в виде последовательности байт". Выставленное нами значение YT означает, что соответствующее вложенное сообщение будет сопоставлено сложному типу в схеме таблицы. В TDoc для примера мы пометили поле ExtraInfo опцией (NYT.serialization_mode) = PROTOBUF(обратите внимание на тип соответствующего поля в выходной таблице).

Reducer пишется естественным образом.

Reduce с несколькими входными таблицами

Если кроме старой таблицы с пользователями, есть таблица, где записано, кто робот.

Следующая программа сделает таблицу, в которой останутся только пользователи-роботы.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/multiple_input_reduce_tnode.

Чтение файлов из операций

Предыдущую задачу можно решать и по-другому: загрузить таблицу с роботами прямо на машины, где будут запускаться операции, и считать её там целиком в yhash_set.

В таком случае можно не сортировать таблицу и использовать Map, а не Reduce. Этот способ используется, если таблица небольшая (до нескольких ГБ).

Входные таблицы те же, что и в предыдущем примере: с пользователями и роботами.

Следующая программа сделает таблицу, в которой останутся только пользователи-роботы.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/map_tnode_with_file.

Reduce с несколькими входными и несколькими выходными таблицами

Теперь необходимо сделать почти то же самое что и в предыдущем примере, но записать сразу 2 выходных таблицы: и с людьми и с роботами.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/multiple_input_multiple_output_reduce_tnode.

Reduce с несколькими входными и несколькими выходными таблицами (Protobuf-версия)

Чтобы сделать разные таблицы для людей и роботов, нужно переписать тот же самый reducer на protobuf. Таблица с людьми будет содержать поля login, email, name. Таблица с роботами будет содержать поля login и uid. Потребуется завести отдельные типы protobuf сообщений для этих таблиц.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/multiple_input_multiple_output_reduce_protobuf.

Чтение и запись таблиц

YTsaurus позволяет писать в таблицы и дописывать данные в них. По чтению таблиц тоже есть несколько режимов: можно читать как всю таблицу, так и отдельные диапазоны по номеру строки или ключу. См. также разделы про чтение и запись данных и таблицы.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/table_read_write_tnode.

Передача состояния в джоб

Иногда нужно написать операцию, которая принимает некоторые аргументы. Например, написать программу, которая отфильтрует исходную таблицу по имени пользователя.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/stateful_map_tnode.

Операция MapReduce (Protobuf-версия)

В YTsaurus есть слитная операция MapReduce, которая работает несколько быстрее нежели Map + Sort + Reduce. Чтобы по таблице с пользователями ещё раз посчитать статистику, сколько раз встречается то или иное имя, перед подсчётом нормализируем имена, приведя их к нижнему регистру. Это нужно, чтобы люди с именами АРКАДИЙ и Аркадий считались как одно.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/mapreduce_protobuf.

Операция MapReduce (версия с лямбда-выражениями)

Задача та же, что в предыдущем примере.

Этот пример лежит в yt/cpp/mapreduce/examples/tutorial/mapreduce_lambda.

Подготовка операции в классе джоба

Есть возможность настраивать параметры операции, перегружая метод IJob::PrepareOperation, подробности см. в разделе Описание.

Продвинутый уровень

Запуск нескольких операций параллельно

Для запуска нескольких операций параллельно существует класс TOperationTracker.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/operation_tracker.

Reduce с enable_key_guarantee=false

Предположим, нужно отфильтровать таблицу с URL по регулярным выражениям, которые лежат в отдельной таблице с хостами (т. е. для каждого хоста свое регулярное выражение). Задачу можно было бы решить Reduce по колонке host, но реальные данные часто устроены таким образом, что какие-то хосты имеют непропорционально много URL. В таблице с примером URL с хоста https://www.youtube.com занимают больше половины таблицы. Джоб, который будет обрабатывать такой хост, займёт непропорционально много времени (ключ https://www.youtube.com в такой ситуации называют ключом-монстром).

Но для решения задачи не нужно, чтобы все записи с одним хостом попадали на одну машину. Возможно распределить таблицу с URL между несколькими машинами: важно, чтобы вместе с URL обязательно был получен хост.

host1, url1
host1, url1
host1, url3
host1, url3
host1, url2
host1, url2
host1, url4
host1, url4
host1, url5
host1, url5
host2, url1
host2, url1
host2, url2
host2, url2
host3, url1
host3, url1
host1, data1
host1, data1
host2, data1
host2, data1
host3, data1
host3, data1
host1, data1
host1, data1
host1, url1
host1, url1
host1, url3
host1, url3
host1, url2
host1, url2
host1, url4
host1, url4
host2, url1
host2, url1
host2, url2
host2, url2
host3, url1
host3, url1
host2, data1
host2, data1
host3, data1
host3, data1
Table 1
Table 1
Table 2
Table 2
Job 1
Job 1
Job 2
Job 2
Job 3
Job 3
Reduce
Reduce

Layer 1
host1, url1
host1, url1
host1, url3
host1, url3
host1, url2
host1, url2
host1, url4
host1, url4
host1, url5
host1, url5
host2, url1
host2, url1
host2, url2
host2, url2
host3, url1
host3, url1
host1, data1
host1, data1
host2, data1
host2, data1
host3, data1
host3, data1
host1, data1
host1, data1
host1, url1
host1, url1
host1, url2
host1, url2
host2, url1
host2, url1
host2, url2
host2, url2
host3, url1
host3, url1
host2, data1
host2, data1
host3, data1
host3, data1
Table 1
Table 1
Table 2
Table 2
Job 1
Job 1
Job 3
Job 3
Job 4
Job 4
host1, data1
host1, data1
host1, url3
host1, url3
host1, url4
host1, url4
Job 2
Job 2
Урлы с одного хоста теперь обрабатываются несколькими джобами
Урлы с одного хоста теперь обрабатываются несколькими джобами
Эту таблицу отмечаем как foreign
Эту таблицу отмечаем как foreign

Reduce

enable_key_guarantee=false

Пример лежит в yt/cpp/mapreduce/examples/tutorial/join_reduce_tnode.

Пакетные запросы

Есть возможность исполнять «лёгкие» запросы (создать/удалить таблицу, проверить её существование и т.д. ) пачками. Этот способ стоит использовать, если нужно выполнить большое количество однотипных операций. Пакетные (batch) запросы помогут заметно сэкономить время.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/batch_request.

Доставка дампа таблицы в джоб в виде файла

В YTsaurus в джоб можно доставлять файлы (как, например, описано ранее). Менее известной возможностью является доставка дампа таблицы в джоб. Это может быть удобно, если джобу требуется словарь, хранящийся в небольшой (едининичные гигабайты) таблице. Однако не стоит использовать этот подход для загрузки больших таблиц — если размер таблицы несколько десятков гигабайт, такая таблица не поместится на одном узле кластера, на котором запускаются джобы.

Пример лежит в yt/cpp/mapreduce/examples/tutorial/pass_table_as_file.

Запись и получение job statistics

Во время работы операция накапливает множество статистик (читайте документацию).

Пример на простой Map со сбором статистик: yt/cpp/mapreduce/examples/tutorial/job_statistics:

Базовая работа с динамическими таблицами

YTsaurus поддерживает динамические таблицы. Wrapper С++ предоставляет возможность совершать базовые операции с такими таблицами.

Внимание

В отличие от других примеров, для запуска этого примера придётся совершить некоторые дополнительные действия:

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

Пример лежит в yt/cpp/mapreduce/examples/tutorial/dyntable_get_insert.

Следующая