Работа с RQL-запросами

В данном разделе описано, как использовать язык запросов R-Vision SIEM для анализа событий и записей активных списков. Описано создание запросов, которые включают работу с проекциями, использование условий, управление выводом, сортировку и группировку результатов, а также заполнение данных. Также описывается использование фильтров и временных ограничений в поиске.

В данной статье при описании выражений приняты следующие обозначения:

  • Необязательные компоненты запросов заключается в квадратные скобки.

  • {expression} — выражение, то есть применение оператора, функция, идентификатор, литерал, арифметическое выражение или выражение в скобках.

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

Синтаксис запросов

RQL-запросы используются для поиска и извлечения информации о событиях безопасности и записях активных списков.

Работа с событиями в R-Vision осуществляется только в рамках определенного хранилища. Поэтому, в отличие от SQL, в запросах не требуется указывать таблицу базы данных в компоненте FROM <имя таблицы>.

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

В режиме базового поиска могут опускаться компонент SELECT * и оператор WHERE при указании условия:

Пример 1. Синтаксис базового поиска
[SELECT *] [{expression}] -- условие
[(INNER | LEFT) JOIN `active_list_name` [AS alias_name] ON {expression} [ENRICH target_field = source_field]]
[ORDER BY field_name [ASC | DESC] [WITH FILL [FROM {expression} TO {expression}] STEP {expression}]]
[LIMIT {m} [OFFSET {n}]]
Пример 2. Синтаксис продвинутого поиска
SELECT {expression} [AS alias_name][, {expression}]
[(INNER | LEFT | RIGHT | FULL) JOIN `active_list_name` [AS alias_name] ON {expression} [ENRICH target_field = source_field]]
[WHERE {expression}]
[GROUP BY field_name [HAVING {expression}]]
[ORDER BY field_name [ASC | DESC] [WITH FILL [FROM {expression} TO {expression}] STEP {expression}]]
[LIMIT {m} [OFFSET {n}]]
Таблица 1. Соответствие запросов SQL и RQL
Запрос в SQL Запрос в системе
SELECT tenantId FROM table
SELECT tenantId
SELECT tenantId FROM table WHERE length(tenantId) = 5
SELECT tenantId WHERE length(tenantId) = 5
SELECT tenantId, count(*) FROM table GROUP BY tenantId
SELECT tenantId, count(*) GROUP BY tenantId
SELECT * FROM table WHERE id = 'abcdef'
id = 'abcdef'

Фильтры в разделе Поиск и ограничения по времени применяются как дополнительные условия для запроса.

Работа с проекциями (оператор SELECT)

В R-Vision SIEM для каждого хранилища событий выбирается ref:EventModel.adoc[модель событий], а для активного списка — схема активного списка, которые определяют структуру данных. По умолчанию система возвращает результат со всеми полям текущей модели данных или схемы активного списка независимо от того, какие поля отображаются в списке. Поэтому, если в результат необходимо включить все поля, в базовом поиске компонент запроса SELECT * может опускаться.

Оператор SELECT используется при работе с проекциями, то есть для указания определенных полей, которые будут включены в результат запроса. Этот оператор часто используется в виджетах и метриках, которые создаются на дашбордах. Имена полей в запросе отделяются друг от друга запятыми.

Пример 3. Синтаксис
SELECT {expression}[, {expression}]
Не ставьте разделитель после последнего поля, включенного в запрос.

Оператор SELECT является обязательным при использовании оператора WHERE и группировке результатов.

Таблица 2. Соответствие запросов SQL и RQL при использовании проекций
Запрос в SQL Запрос в системе
SELECT tenantId, raw FROM table
SELECT tenantId, raw
SELECT tenantId, raw FROM table WHERE length(tenantId) = 5
SELECT tenantId, raw WHERE length(tenantId) = 5

Использование псевдонимов (оператор AS)

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

Пример 4. Синтаксис
SELECT {expression} AS alias_name

Пример использования псевдонима для функции

При создании виджета типа Таблица вводится запрос:

SELECT collectorId, count(*) AS cnt WHERE collectorId LIKE '%' GROUP BY collectorId

Здесь для функции count(*) задается псевдоним cnt, который можно указать в секции сопоставления полей.

Использование условий (оператор WHERE)

В базовом поиске при задании условия оператор WHERE в запросе опускается.

При использовании проекций оператор WHERE позволяет применять к указанному полю запрос с выборкой строк по определенному условию.

Пример 5. Синтаксис
SELECT {expression} WHERE {expression}

Пример выборки строк по условию

Пример 6. Запрос с оператором WHERE
SELECT tenantId WHERE length(tenantId) = 5

Этот запрос возвращает события с количеством символов в поле tenantId, равным 5.

Операторы сравнения

Оператор Значение

=

Равно

!=

Неравно

<

Меньше

<=

Меньше или равно

>

Больше

>=

Больше или равно

LIKE

Соответствует заданному шаблону

NOT LIKE

Не соответствует заданному шаблону

BETWEEN

Входит в диапазон. a BETWEEN b AND c равнозначно выражению a >= b AND a <= c.

NOT BETWEEN

Не входит в диапазон. a NOT BETWEEN b AND c равнозначно выражению a < b OR a > c.

Операторы работы с множествами (IN) и проверки на пустое значение

Оператор Значение

IN

Входит во множество

NOT IN

Не входит во множество

IS NULL

Значение является пустым (NULL)

IS NOT NULL

Значение не является пустым (NULL)

Поиск по подсетям с оператором IN

Для поиска данных по подсетям используйте оператор IN. Формат записи: %Сетевая маска%/%Префикс%.

Пример 7. Поиск по подсетям
sourceIp IN '::ffff:192.0.2.0/24'
sourceIp IN '2001:db8::/32'
deviceTranslatedAddress IN '203.0.113.0/24'

Комбинирование условий (операторы AND, OR, NOT)

Совмещение нескольких условий происходит с использованием операторов:

Оператор Значение

AND

Конъюнкция (И)

OR

Дизъюнкция (ИЛИ)

NOT

Логическое отрицание

Пример запроса с комбинированным условием

Рассмотрим запрос, возвращающий события, у которых значения в поле tenantId начинаются с символа n, а количество символов в поле raw превышает 10.

Пример 8. Запрос в SQL
SELECT * FROM table WHERE tenantId LIKE 'n%' AND length(raw) > 10
Пример 9. Запрос в системе
tenantId LIKE 'n%' AND length(raw) > 10

Работа с настраиваемыми полями универсальной модели

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

Пример 10. Синтаксис
{custom_field}:{custom_field_label} {expression}

Здесь:

  • {custom_field} — ключ значения настраиваемого поля, например: cn1, cs1, deviceCustomDate1, c6a1.

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

    • cs — LCString;

    • cn — UInt64;

    • c6a — IPv6;

    • deviceCustomDate — DateTime.

      Семейство полей рекомендуется использовать в случаях, когда требуется проверять условие {expression} по всем полям этого семейства.
  • {custom_field_label} — поле метаданных, хранящее метку, которая указывает на содержание и назначение связанного с ним поля {custom_field}. Эта метка играет роль названия для поля {custom-field} и позволяет интерпретировать хранящиеся в нем данные.

  • {custom_field_label} — поле метаданных, хранящее метку, которая указывает на содержание и назначение связанного с ним поля {custom_field}. Эта метка играет роль названия для поля {custom_field} и позволяет интерпретировать хранящиеся в нем данные.

    Примеры меток:

    • cn1Label — для поля cn1;

    • cs1Label — для поля cs1;

    • deviceCustomDate1Label — для поля deviceCustomDate1;

    • c6a1Label — для поля c6a1.

  • {expression} — выражение с условием поиска по полю значения, использующее операции сравнения (=, !=, <>, <, >, <=, >=) и/или операторы IN, LIKE, NOT LIKE.

  • Обращение к полю напрямую рекомендуется применять, если достоверно известно, какая информация хранится в этом поле, и требуется получить информацию строго из этого поля.

  • Обращение к полям посредством специального синтаксиса рекомендуется применять в случаях, когда оно позволяет упростить RQL-запрос. Например:

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

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

    В этих случаях представленный синтаксис позволяет заменить множественные условия с операторами AND и OR коротким RQL-запросом.

Примеры обращения к настраиваемым полям

Пример обращения к полю напрямую Допустим, имеется поток событий, у которых в поле cs1 хранится адрес электронной почты пользователя, совершившего подозрительное действие. Известно, что часть событий является тестовой и приходит от разных пользователей с одним и тем же электронным адресом test@example.com.

Требуется исключить из рассматриваемого потока тестовые события. Ниже представлен вариант соответствующего RQL-запроса с непосредственным обращением к полю cs1.

cs1 != "test@example.com"

Запрос выдаст события, поле cs1 которых не содержит значение test@example.com.

Пример обращения к полю по его ключу

Допустим, имеется поток событий от разных источников. Для событий от некоторых источников в поле cs1 хранится адрес электронной почты пользователя, совершившего подозрительное действие. В соответствующем поле метки cs1Label этих событий хранится значение email. Известно, что часть событий от этих источников является тестовой и приходит от разных пользователей с одним и тем же электронным адресом test@example.com.

Требуется получить поток событий, для которых указаны электронные адреса пользователей, и исключить из него тестовые события. Ниже представлен RQL-запрос, построенный на основе представленного ранее синтаксиса. Обращение к полю cs1 выполняется по его ключу.

cs1:email != "test@example.com"

Запрос выдаст события, для которых одновременно выполняются следующие условия:

  1. Поле cs1 не содержит значение test@example.com.

  2. Поле cs1Label содержит название email.

Представленный запрос эквивалентен следующему запросу:

cs1 != "test@example.com" AND cs1Label = "email"

Пример обращения к полю по его семейству

Допустим, имеется поток событий из разных источников. Для событий некоторых источников в полях семейства cs (например, cs1, cs2, cs3) хранится адрес электронной почты пользователя, совершившего подозрительное действие. В соответствующих полях меток (например, cs1Label, cs2Label, cs3Label) этих событий хранится значение email. Известно, что часть событий от этих источников является тестовой и приходит от разных пользователей с одним и тем же электронным адресом test@example.com.

Требуется получить поток событий, для которых указаны электронные адреса пользователей, и исключить из него тестовые события. Ниже представлен RQL-запрос, построенный на основе представленного ранее синтаксиса. Обращение к настраиваемым полям универсальной модели события выполняется по их семейству cs.

cs:email != "test@example.com"

Запрос выдаст события, для которых одновременно выполняются следующие условия:

  1. Ни одно из полей значений семейства cs не содержит значение test@example.com.

  2. Поле метки, соответствующее полю значений семейства cs, содержит название email.

Представленный запрос эквивалентен следующему запросу:

(cs1 != "test@example.com" AND cs1Label = "email") OR (cs2 != "test@example.com" AND cs2Label = "email") OR (cs3 != "test@example.com" AND cs3Label = "email") OR (cs4 != "test@example.com" AND cs4Label = "email") OR (cs5 != "test@example.com" AND cs5Label = "email") OR (cs6 != "test@example.com" AND cs6Label = "email")

Использование фильтров и ограничений по времени

После выполнения запроса в разделе Поиск можно отфильтровать возвращенные результаты с помощью кнопки Добавить фильтр. В окне добавления фильтра указывается поле, по которому проводится фильтрация, оператор сравнения и значение для сравнения.

Вместе с фильтрами удобно использовать функциональность ограничения запроса по времени. Это ограничение аналогично добавлению к запросу компонента, который ограничивает результаты запроса определенным временным интервалом.

Система воспринимает применяемые фильтры и ограничения по времени как дополнительные условия оператора WHERE, присоединяемые оператором AND. Переключатель Инвертировать (NOT) интерпретируется как оператор NOT.

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

Пример 1

Вы ввели в строке поиска запрос tenantId LIKE 'n%' AND length(raw) > 10. Затем добавили фильтр по полю originalTimestamp c оператором = и значением 05.05.2023б 05:00:00. Последовательность этих действий равнозначна следующему запросу в строке поиска:

tenantId LIKE 'n%' AND length(raw) > 10 AND originalTimestamp = '2023.05.05 05:00:00'

Пример 2

Вы хотите ограничить результат запроса tenantId LIKE 'n%' AND length(raw) > 10 датами 01.01.2023 и 12.12.2023. Для этого после выполнения запроса выберите значение Задать период в поле периода и укажите диапазон периода в полях справа. Эти действия аналогичны следующему запросу:

tenantId LIKE 'n%' AND length(raw) > 10 AND (timestamp >= 2023.01.01 AND timestamp <= 2023.12.12)

Таким образом, применение фильтров и ограничений по времени существенно упрощает создание поисковых запросов в системе.

Группировка (оператор GROUP BY)

Объединять результаты запроса по одному или нескольким полям можно с помощью оператора GROUP BY. С оператором GROUP BY могут применяться агрегатные функции: count(), sum(), avg(), max(), min().

Пример 11. Синтаксис
SELECT {expression} GROUP BY field_name
При использовании оператора GROUP BY необходимо указать, к какой проекции будет применяться объединение. Например, запрос вида GROUP BY tenantID воспринимается системой как SELECT * GROUP BY tenantID, и поэтому некорректен. Корректный запрос с указанной проекцией имеет вид SELECT tenantID GROUP BY tenantID.

Фильтрация результатов группировки (оператор HAVING)

Если требуется отфильтровать группы данных, полученные после объединения результатов, используйте оператор HAVING.

Пример 12. Синтаксис
SELECT {expression} GROUP BY field_name HAVING {expression}

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

SELECT tenantID, count(*) AS cnt GROUP BY tenantID HAVING cnt > 10

Этот запрос выбирает события, группируя их по tenantID, и возвращает только те группы, в которых количество событий больше 10.

Сортировка возвращаемых записей (оператор ORDER BY)

Результаты запроса можно сортировать по любому полю с помощью оператора ORDER BY.

Пример 13. Синтаксис
[SELECT {expression}] ORDER BY field_name [ASC | DESC]

Направление сортировки задается модификаторами:

  • ASC — по возрастанию;

  • DESC — по убыванию.

Примеры сортировки

Пример 14. Сортировка в базовом поиске
ORDER BY collectorId

Этот запрос выводит события с сортировкой по полю collectorId в порядке возрастания.

Пример 15. Использование сортировки с агрегатной функцией count()
SELECT tenantId, count(*) ORDER BY tenantId ASC

Этот запрос возвращает события, упорядоченные по возрастанию значения в поле tenantId и указанием количества событий в каждой группе.

Заполнение пропусков в списке возвращаемых результатов (модификатор WITH FILL)

Чтобы заполнить пропуски в списке возвращаемых результатов при сортировке и группировке записей, используйте модификатор WITH FILL. Пропуски заполняются значениями с указанным шагом в указанном промежутке, либо по умолчанию.

WITH FILL можно применять только после имени колонки в ORDER BY. Допускается использование нескольких WITH FILL для разных колонок.
Пример 16. Синтаксис продвинутого поиска
SELECT {expression} ORDER BY field_name WITH FILL [FROM {expression} TO {expression}] STEP {expression}]]
Для случая с несколькими полями ORDER BY field2 WITH FILL, field1 WITH FILL порядок заполнения будет соответствовать порядку полей в секции ORDER BY.

Здесь:

  • field_name — имя поля, по которому происходит сортировка.

  • FROM +{expression}+ — начальное значение интервала, который будет заполнен. Если не указано, будет использовано наименьшее значение в поле field_name.

  • TO +{expression}+ — конечное значение. Если не указано, будет использовано наибольшее значение в поле field_name.

  • STEP +{expression}+ — шаг, с которым будет заполняться интервал. Если не указан, используется значение 1.0 для числовых типов, и 1 секунда для метки времени.

Значение параметра {expression} должен принадлежать к одному из следующих типов:

  • числовой литерал (целое или дробное число);

  • метка времени;

  • арифметическая операция с числами, меткой времени, интервалом или функцией;

  • функция с возвращаемым значением в виде числа или метки времени.

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

Пример 17. Заполнение пропусков для временных интервалов
SELECT toStartOfHour(timestamp) as ts, sum(cnt) as sum_cnt GROUP BY ts HAVING sum_cnt > 0 ORDER BY ts WITH FILL FROM now() - INTERVAL 1 day TO now() STEP INTERVAL 1 hour

Данный запрос выполняет следующую последовательность операций:

  • SELECT toStartOfHour(timestamp) as ts, sum(cnt) as sum_cnt: выбираются значения поля timestamp, округленные до начала каждого часа, и вычисляется сумма поля cnt для каждой группы записей с одинаковым значением ts.

  • GROUP BY ts: результаты группируются по полю ts, которое представляет округленные значения.

  • HAVING sum_cnt > 0: применяется фильтрация, чтобы оставить только те группы записей, у которых сумма поля cnt больше нуля. Это означает, что в результирующем наборе будут только записи, для которых существуют записи с положительными значениями cnt внутри группы.

  • ORDER BY ts WITH FILL FROM now() - INTERVAL 1 day TO now() STEP INTERVAL 1 hour: результаты сортируются по полю ts. Здесь используется модификатор WITH FILL, который обеспечивает заполнение пропущенных интервалов с шагом в 1 час от текущего времени минус 1 день до текущего времени. То есть, если в исходных данных отсутствуют записи для определенных интервалов времени, то они будут включены в результирующий набор со значениями по умолчанию.

Пример 18. Заполнение пропусков для временных интервалов с фильтрацией
SELECT toStartOfHour(timestamp) as ts, sum(cnt) as sum_cnt GROUP BY ts HAVING sum_cnt > 0 AND ts >= now() - INTERVAL 1 day AND ts <= now() ORDER BY ts WITH FILL FROM now() - INTERVAL 1 day TO now() STEP INTERVAL 1 hour

Здесь выполняются те же самые операции, что и в первом запросе, но добавляется дополнительный фильтр в выражении HAVING и выражении AND. Этот фильтр ограничивает результаты только записями, у которых поле ts находится в интервале от текущего времени минус 1 день до текущего времени. Таким образом, данный запрос дополнительно фильтрует записи по временному интервалу перед применением сортировки и заполнением пропущенных интервалов.

В результате выполнения этого запроса будет получен отсортированный список, где каждая запись будет содержать округленное значение timestamp, сумму cnt для соответствующей группы записей, а также пропущенные интервалы времени со значениями по умолчанию, если таковые имеются. В результирующем наборе будут только записи, удовлетворяющие условиям фильтрации по сумме cnt и временному интервалу.

Работа с активными списками (операторы JOIN и ENRICH)

Данные можно обогащать и фильтровать через активные списки с помощью операторов JOIN и ENRICH:

  • В режиме базового поиска для фильтрации записей по данным активных списков используется оператор JOIN, который позволяет уточнить результаты запросов на основе совпадения данных без их обогащения. Оператор ENRICH используется в комбинации с JOIN и позволяет обогащать эти результаты данными из активных списков. Поддерживаются операции INNER JOIN и LEFT JOIN.

  • В режиме продвинутого поиска для объединения данных из активных списков с событиями из хранилища с целью обогащения информации используется оператор JOIN. Поддерживаются операции INNER JOIN, LEFT JOIN, RIGHT JOIN и FULL JOIN.

Работа с оператором JOIN в режиме базового поиска

Пример 19. Синтаксис
(INNER | LEFT) JOIN `{active_list_name}` [AS alias_name] ON {expression}

Здесь:

  • (INNER | LEFT) указывает на тип операции JOIN:

    • INNER JOIN отбирает строки при наличии совпадения данных между обеими таблицами.

    • LEFT JOIN отображает все строки из левой таблицы (хранилище событий), дополняя их совпадающими данными из правой таблицы (активный список), если таковые имеются. Применяется совместно с оператором ENRICH.

  • `{active_list_name}` обозначает имя активного списка, который используется в качестве правой таблицы для операции JOIN.

    Имя активного списка необходимо заключать в обратные апострофы.
  • AS alias_name предоставляет возможность задать псевдоним для активного списка, упрощая дальнейшее обращение к данным в запросе.

  • {expression} формулирует условие объединения, используя операции сравнения и логические операторы для определения совпадений данных между таблицами.

    При обращении к полям таблицы без указания ее названия система автоматически начинает поиск поля в хранилище событий. Если поле в хранилище событий не найдено, поиск поля продолжается в активном списке.

    Обращение к полю в записях событий может выполняться одним из следующих способов:

    • Указание только названия поля. Рекомендуется использовать данный способ, так как поиск полей по умолчанию начинается в "левой" таблице (хранилище событий).

    • Указание имени таблицы из БД ClickHouse и названия поля. Имя таблицы ClickHouse, связанной с хранилищем событий, необходимо заключать в обратные апострофы, например: `clickhouse_table_name`.field.

      Использование имени хранилища событий вместо имени ассоциированной с ним таблицы ClickHouse не допускается.

    Обращение к полю активного списка может выполняться одним из следующих способов:

    • Указание только названия поля. Данный способ допустим только в тех случаях, когда в записях событий отсутствует поле с таким же названием. В противном случае произойдет обращение к полю в записях событий.

    • Указание имени активного списка и названия поля. Имя активного списка необходимо заключать в обратные апострофы, например: `active_list_name`.field.

    • Указание псевдонима активного списка и названия поля. Псевдоним (alias) активного списка допускается задавать как с обратными апострофами, так и без них, например: `alias_name`.field или alias_name.field.

Пример использования INNER JOIN для фильтрации событий

Оператор INNER JOIN в разделе Поиск может быть использован для фильтрации записей, позволяя ограничить выборку событий на основе соответствия условиям, заданным для данных из активных списков. Этот механизм не обогащает данные событий новой информацией, но позволяет исключить из результата те события, которые не соответствуют заданным критериям.

Пример запроса ниже демонстрирует использование INNER JOIN для фильтрации событий по списку угроз threat_list, исключая из результатов все события, не соответствующие IP-адресам, занесенным в этот список. Цель запроса — идентифицировать потенциально вредоносную активность, происходящую с IP-адресов, указанных в списке угроз.

INNER JOIN `threat_list` ON sourceIp = `threat_list`.ip_address

Этот запрос исключит из результата все события, источник которых не совпадает с IP-адресами, указанными в активном списке threat_list. Таким образом, анализ будет сосредоточен исключительно на событиях, источник которых был заранее классифицирован как потенциальная угроза. Поскольку объединение данных не происходит, в результатах запроса отображаются только поля исходных событий, соответствующих условиям фильтрации.

Работа с оператором JOIN в режиме продвинутого поиска

Пример 20. Синтаксис
[SELECT {expression}] (INNER | LEFT | RIGHT | FULL) JOIN `{active_list_name}` [AS alias_name] ON {expression}

Здесь:

  • (INNER | LEFT | RIGHT | FULL) определяет тип операции JOIN, применяемой для объединения данных из левой таблицы (хранилища событий) и правой (активного списка):

    • INNER JOIN выбирает строки, где присутствует совпадение по заданным условиям в обеих таблицах.

    • LEFT JOIN отображает все строки из левой таблицы, дополняя их данными из правой таблицы при наличии совпадений.

    • RIGHT JOIN аналогичен LEFT JOIN, но выводит все строки из правой таблицы, дополняя их данными из левой таблицы при наличии совпадений.

    • FULL JOIN объединяет методы LEFT JOIN и RIGHT JOIN, показывая все строки из обеих таблиц.

  • `{active_list_name}` обозначает имя активного списка, который используется в качестве правой таблицы.

    Имя активного списка необходимо заключать в обратные апострофы.
  • [AS alias_name] позволяет назначить псевдоним активному списку, упрощая дальнейшую работу с запросом.

  • {expression} условие для объединения, которое может включать операции сравнения и логические операторы, для определения критериев совпадения данных между таблицами.

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

    • Указание только названия поля. Рекомендуется использовать данный способ, так как поиск полей по умолчанию начинается в "левой" таблице (хранилище событий).

    • Указание имени таблицы из БД ClickHouse и названия поля. Имя таблицы ClickHouse, связанной с хранилищем событий, необходимо заключать в обратные апострофы, например: `clickhouse_table_name`.field.

      Использование имени хранилища событий вместо имени ассоциированной с ним таблицы ClickHouse не допускается.

    Обращение к полю активного списка может выполняться одним из следующих способов:

    • Указание только названия поля. Данный способ допустим только в тех случаях, когда в записях событий отсутствует поле с таким же названием. В противном случае произойдет обращение к полю в записях событий.

    • Указание имени активного списка и названия поля. Имя активного списка необходимо заключать в обратные апострофы, например: `active_list_name`.field.

    • Указание псевдонима активного списка и названия поля. Псевдоним (alias) активного списка допускается задавать как с обратными апострофами, так и без них, например: `alias_name`.field или alias_name.field.

Примеры использования JOIN в продвинутом поиске

Пример 1. Использование INNER JOIN

Оператор INNER JOIN может быть использован для объединения данных о событиях с активными списками, что позволит идентифицировать события, исходящие с IP-адресов, внесенных в список блокировки.

Пример запроса ниже демонстрирует использование INNER JOIN для соединения данных событий с активным списком blacklist_ips по IP-адресу источника (sourceIp), с целью выявления событий с блокированными IP-адресами.

SELECT sourceIp, timestamp, action, ip_address
INNER JOIN `blacklist_ips` ON sourceIp = `blacklist_ips`.ip_address

Визуализация ожидаемого результата запроса:

event.sourceIp event.timestamp event.action blacklist_ips.ip_address

192.0.2.1

2022-07-01T12:00:00Z

Blocked

192.0.2.1

192.0.2.2

2022-07-02T12:00:00Z

Blocked

192.0.2.2

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

Пример 2. Использование LEFT JOIN

Оператор LEFT JOIN может быть использован для объединения данных о событиях входа в систему с информацией о пользователях из активного списка. Это позволяет получить расширенный контекст активности пользователей, включая отсутствие событий для определенных пользователей. В случаях, когда соответствующая запись в активном списке отсутствует, результатом объединения для данной записи события будут значения NULL в полях, предназначенных для данных из активного списка.

Пример запроса ниже демонстрирует использование LEFT JOIN для соединения событий с записями активного списка о пользователях user_info по идентификатору пользователя. Цель — включить в анализ всех пользователей, включая тех, по которым отсутствуют данные о событиях входа.

SELECT sourceIp, timestamp, ip_address, userName
LEFT JOIN `user_info` ON userId = `user_info`.user_id

Визуализация ожидаемого результата запроса:

event.sourceIp event.timestamp user_info.ip_address user_info.userName

192.0.2.1

2022-07-01T12:00:00Z

192.0.2.1

Sergey

192.0.2.2

2022-07-02T12:00:00Z

192.0.2.2

John

192.0.2.3

2022-07-03T12:00:00Z

NULL

NULL

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

Пример 3. Использование RIGHT JOIN

Оператор RIGHT JOIN может быть применен для объединения информации об устройствах из активного списка с данными о событиях, позволяя анализировать данные обо всех устройствах независимо от наличия связанных с ними событий. В случаях, когда соответствующая запись в хранилище отсутствует, результатом объединения для данной записи события будут значения NULL в полях, предназначенных для данных из хранилища.

Пример запроса ниже демонстрирует использование RIGHT JOIN для соединения информации об устройствах из активного списка device_info с данными о событиях на основе совпадения серийных номеров устройств (serial_number) с внешними идентификаторами устройств в событиях (deviceExternalId). Цель — предоставить полный обзор по всем устройствам, включая те, по которым отсутствуют события.

RIGHT JOIN `device_info` ON deviceExternalId = `device_info`.serial_number

Визуализация ожидаемого результата запроса:

event.deviceExternalId event.action device_info.serial_number device_info.device_name

12345

Alert

12345

DeviceA

NULL

NULL

67890

DeviceB

В этой таблице отображается информация об устройствах из активного списка device_info, дополненная данными о событиях из системы. Запись устройства DeviceB демонстрирует случай, когда для устройства нет зарегистрированных событий.

Пример 4. Использование FULL JOIN

Оператор FULL JOIN можно использовать для комплексного анализа данных, чтобы объединить информацию о событиях с данными из активных списков, не исключая записи без взаимных соответствий. Это обеспечивает возможность анализа, включая изучение как связанных, так и независимых данных событий и элементов активных списков.

Пример запроса ниже иллюстрирует использование FULL JOIN для объединения данных о событиях с информацией из активного списка network_segments на основе соответствия между IP-адресами устройств (deviceIp) и сегментами сети (segment_ip). Цель — предоставить полный обзор сетевой активности и конфигурации сети, включая события и сетевые сегменты, которые прямо не связаны.

FULL JOIN `network_segments` ON deviceIp = `network_segments`.segment_ip

Визуализация ожидаемого результата запроса:

event.deviceIp event.action network_segments.segment_ip network_segments.segment_name

198.51.100.1

Access_Granted

198.51.100.1

Office_Network

NULL

NULL

198.51.100.1

Data_Center

203.0.113.24

Unauthorized_Access

NULL

NULL

В этой таблице представлена информация, объединяющая события сетевой активности и конфигурацию сетевых сегментов. Запись для сегмента Data_Center показывает сетевой сегмент без зарегистрированных событий, тогда как запись для IP-адреса 203.0.113.24 демонстрирует событие, для которого нет соответствующего сегмента сети в активном списке.

Работа с оператором ENRICH

Оператор ENRICH дает возможность заменять или добавлять значения в полях событий на основе данных из соответствующих записей активного списка. Он используется в сочетании с оператором JOIN. ENRICH применяется только после того, как условие соединения, заданное в JOIN, будет выполнено.

Пример 21. Синтаксис
[SELECT {expression}]
(INNER | LEFT | RIGHT | FULL) JOIN `{active_list_name}` ON {join_condition}
ENRICH {target_field} = {source_field}

Здесь:

  • `{active_list_name}` — имя активного списка, данные из которого используются для обогащения.

    Имя активного списка необходимо заключать в обратные апострофы.
  • {join_condition} — условие соединения, определяющее правила поиска совпадений между данными событий и записями в активном списке.

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

    • Указание только названия поля. Рекомендуется использовать данный способ, так как поиск полей по умолчанию начинается в "левой" таблице (хранилище событий).

    • Указание имени таблицы из БД ClickHouse и названия поля. Имя таблицы ClickHouse, связанной с хранилищем событий, необходимо заключать в обратные апострофы, например: `clickhouse_table_name`.field.

      Использование имени хранилища событий вместо имени ассоциированной с ним таблицы ClickHouse не допускается.

    Обращение к полю активного списка может выполняться одним из следующих способов:

    • Указание только названия поля. Данный способ допустим только в тех случаях, когда в записях событий отсутствует поле с таким же названием. В противном случае произойдет обращение к полю в записях событий.

    • Указание имени активного списка и названия поля. Имя активного списка необходимо заключать в обратные апострофы, например: `active_list_name`.field.

    • Указание псевдонима активного списка и названия поля. Псевдоним (alias) активного списка допускается задавать как с обратными апострофами, так и без них, например: `alias_name`.field или alias_name.field.

  • {target_field} — поле в записях событий, для которого будет выполнено обогащение.

    Обращение к полю в записях событий может выполняться одним из следующих способов:

    • Указание только названия поля. Рекомендуется использовать данный способ, так как поиск полей по умолчанию начинается в "левой" таблице (хранилище событий).

    • Указание имени таблицы из БД ClickHouse и названия поля. Имя таблицы ClickHouse, связанной с хранилищем событий, необходимо заключать в обратные апострофы, например: `clickhouse_table_name`.field.

      Использование имени хранилища событий вместо имени ассоциированной с ним таблицы ClickHouse не допускается.

  • {source_field} — поле в активном списке, значения из которого используются для обогащения данных событий.

    Обращение к полю активного списка может выполняться одним из следующих способов:

    • Указание только названия поля. Данный способ допустим только в тех случаях, когда в записях событий отсутствует поле с таким же названием. В противном случае произойдет обращение к полю в записях событий.

    • Указание имени активного списка и названия поля. Имя активного списка необходимо заключать в обратные апострофы, например: `active_list_name`.field.

    • Указание псевдонима активного списка и названия поля. Псевдоним (alias) активного списка допускается задавать как с обратными апострофами, так и без них, например: `alias_name`.field или alias_name.field.

Оператор ENRICH позволяет обогащать данные событий из нескольких активных списков в рамках одного запроса. Для точного указания полей из конкретных активных списков следует использовать полное имя поля, включающее имя активного списка и имя поля, разделенные точкой.

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

Пример 1. Обогащение данных события значениями из одного активного списка

LEFT JOIN `user_info` ON userId = `user_info`.name
ENRICH id = `user_info`.age

В данном примере запрос обогащает значение поля id в записях событий значением поля age из активного списка user_info, если значение поля userId события совпадает с полем name в активном списке.

Пример 3. Использование INNER JOIN с ENRICH для обогащения событий

Применение запросов с INNER JOIN и ENRICH в разделе Поиск позволяет обогатить данные событий дополнительными данными из активных списков при условии точного совпадения между записями событий и данными активного списка. В отличие от LEFT JOIN, INNER JOIN выбирает только те записи, для которых существуют совпадающие данные в обеих таблицах, и далее ENRICH используется для обогащения этих данных.

Этот метод подходит для сценариев, где необходимо ограничить анализ событиями, которые имеют прямое соответствие в активных списках, и одновременно обогатить эти события дополнительной информацией из этих списков.
INNER JOIN `device_info` ON deviceId = `device_info`.device_id
ENRICH deviceType = `device_info`.type

Пример 3. Обращение к нескольким активным спискам

SELECT id
LEFT JOIN `admin_list` ON userId = `admin_list`.user_id
LEFT JOIN `security_events` ON eventCode = `security_events`.code
ENRICH adminName = `admin_list`.name, securityLevel = `security_events`.level

В данном примере запрос обогащает данные событий, используя информацию из двух разных активных списков — admin_list и security_events. Оператор ENRICH применяется для замены (или добавления, если такого поля нет) в записях событий: значения поля adminName на основании данных об имени администратора из списка admin_list и значения поля securityLevel на основании уровня безопасности из списка security_events. Оба обогащения основываются на совпадении условий: userId с user_id для списка администраторов и eventCode с code для событий.

Максимальное количество и пропуск возвращаемых записей (операторы LIMIT и OFFSET)

По умолчанию в списке результатов поискового запроса отображается 500 записей. Однако вы можете ограничить количество возвращаемых записей с помощью оператора LIMIT.

Пример 22. Синтаксис
LIMIT {m} [OFFSET {n}]

Например, чтобы ограничить выдачу двадцатью записями, используется запрос:

LIMIT 20

Также можно добавить команду OFFSET, которая указывает, сколько строк необходимо пропустить перед началом вывода. Это полезно, если вы хотите начать вывод данных с определенной строки. Например, чтобы пропустить первые 10 строк и вывести следующие 20, используется запрос:

LIMIT 20 OFFSET 10