Движки таблиц Executable и ExecutablePool
Движки таблиц Executable и ExecutablePool позволяют задать таблицу, строки которой генерируются скриптом, который вы пишете (путём вывода строк в stdout). Исполняемый скрипт хранится в каталоге users_scripts и может читать данные из любого источника.
- Таблицы
Executable: скрипт выполняется при каждом запросе - Таблицы
ExecutablePool: поддерживается пул долгоживущих процессов, и для чтения процессы берутся из этого пула
Дополнительно вы можете указать один или несколько входных запросов, результаты которых будут передаваться в stdin для чтения скриптом.
Создание таблицы Executable
Движку таблицы Executable требуются два параметра: имя скрипта и формат входящих данных. При необходимости можно передать один или несколько входных запросов:
Ниже приведены соответствующие параметры для таблицы Executable:
send_chunk_header- Description: Отправлять количество строк в каждом чанке перед отправкой чанка на обработку. Этот параметр позволяет писать скрипты более эффективно, заранее выделяя необходимые ресурсы
- Default value: false
command_termination_timeout- Description: Таймаут завершения команды в секундах
- Default value: 10
command_read_timeout- Description: Таймаут чтения данных из stdout команды в миллисекундах
- Default value: 10000
command_write_timeout- Description: Таймаут записи данных в stdin команды в миллисекундах
- Default value: 10000
Рассмотрим пример. Следующий скрипт на Python называется my_script.py и сохранён в папке user_scripts. Он считывает число i и выводит i случайных строк, при этом каждая строка предваряется числом, отделённым символом табуляции:
Таблица my_executable_table ниже создаётся на основе вывода my_script.py, который будет генерировать 10 случайных строк каждый раз, когда вы выполняете SELECT из my_executable_table:
Создание таблицы завершается немедленно и не запускает скрипт. Выполнение запроса к my_executable_table приводит к запуску скрипта:
Передача результатов запроса в скрипт
Пользователи веб‑сайта Hacker News оставляют комментарии. В Python есть набор инструментов для обработки естественного языка (nltk) с SentimentIntensityAnalyzer для определения, являются ли комментарии положительными, отрицательными или нейтральными, — в том числе для присвоения значения от -1 (очень негативный комментарий) до 1 (очень позитивный комментарий). Давайте создадим таблицу Executable, которая вычисляет тональность комментариев Hacker News с помощью nltk.
В этом примере используется таблица hackernews, описанная здесь. Таблица hackernews включает столбец id типа UInt64 и столбец типа String с именем comment. Начнём с определения таблицы Executable:
Некоторые комментарии о таблице sentiment:
- Файл
sentiment.pyсохранён в каталогеuser_scripts(каталог по умолчанию для настройкиuser_scripts_path) - Формат
TabSeparatedозначает, что наш Python-скрипт должен генерировать строки сырых данных, содержащие значения, разделённые символом табуляции - Запрос выбирает два столбца из
hackernews. Python-скрипту потребуется извлекать значения этих столбцов из входящих строк
Ниже приведено определение sentiment.py:
Несколько комментариев к нашему Python-скрипту:
- Чтобы это работало, вам нужно выполнить
nltk.downloader.download('vader_lexicon'). Это можно было бы поместить в сам скрипт, но тогда загрузка выполнялась бы при каждом выполнении запроса к таблицеsentiment, что неэффективно - Каждое значение
rowбудет строкой в результирующем наборе запросаSELECT id, comment FROM hackernews WHERE id > 0 AND comment != '' LIMIT 20 - Входящая строка имеет табличный формат (значения разделены табуляцией), поэтому мы извлекаем
idиcomment, используя Python-функциюsplit - Результат
polarity_scores— это JSON-объект с несколькими значениями. Мы решили просто взять значениеcompoundиз этого JSON-объекта - Напомним, что таблица
sentimentв ClickHouse использует форматTabSeparatedи содержит два столбца, поэтому наша функцияprintразделяет эти столбцы символом табуляции
Каждый раз, когда вы пишете запрос, выбирающий строки из таблицы sentiment, выполняется запрос SELECT id, comment FROM hackernews WHERE id > 0 AND comment != '' LIMIT 20, а его результат передаётся в sentiment.py. Давайте протестируем это:
Ответ будет выглядеть следующим образом:
Создание таблицы ExecutablePool
Синтаксис ExecutablePool похож на Executable, но у таблицы ExecutablePool есть несколько параметров, характерных именно для нее:
pool_size- Описание: Размер пула процессов. Если размер равен 0, ограничения по размеру отсутствуют.
- Значение по умолчанию: 16
max_command_execution_time- Описание: Максимальное время выполнения команды в секундах.
- Значение по умолчанию: 10
Мы можем легко преобразовать таблицу sentiment, показанную выше, для использования ExecutablePool вместо Executable:
ClickHouse будет по требованию поддерживать в работе 4 процесса, когда клиент выполняет запрос к таблице sentiment_pooled.