Редактор метрик
Создание метрик
При нажатии на кнопку Создать метрику или на кнопку Редактировать открывается редактор с пустыми полями или содержащими данные редактируемой метрики соответственно.
Рассмотрим создание метрики с нуля.
Откройте редактор:
В поле Выражение уже введено значение для наглядности.
Для того, чтобы создать собственную метрику, вам нужно заполнить следующие поля:
-
Название: наименование Вашей метрики. Обязательное для заполнения поле.
-
Описание: описание Вашей метрики - что она подсчитывает, каким образом и т.д. Опциональное поле.
-
Источник данных: выпадающий список, содержащий в себе таблицы базы данных, из которых берется информация для подсчёта метрики. В зависимости от выбранного источника данных список доступных полей, приведённый ниже будет изменяться. Обязательное для заполнения поле.
-
Выражение: SQL-выражение, по которому будет выполняться подсчёт метрики. В этом поле допустимо вводить арифметические знаки (
+,-,*,/), имена доступных полей из списка ниже, а также доступные агрегатные функции. Обязательное для заполнения поле.
Раскрывающийся блок Доступные поля отображает доступные для обращения поля, определённые текущим источником данных.
Раскрывающийся блок Доступные агрегатные функции отображает список доступных для вызова агрегатных функций. Этот список неизменяем.
Метрики стоит рассматривать как инкапсулированные SQL выражения, на которые в будущем применяются различные модификаторы, агрегации (в редакторе отчетов), фильтры при запросе отчетов и т.п.
На данной странице присутствуют два самых важных поля:
-
Источник данных
-
Выражение
Для понимания рассмотрим SQL метрику со страницы:
На изображении описано как интерпретировать создание метрики через редактор метрик. Источник в данном случае выступает в качестве таблицы из которой делается запрос, выражение же - это само тело запроса, между ключевыми словами SELECT и FROM.
Важно!
В запросе в качестве источника указан thread_state_source - это техническое название источника данных, на странице же они указаны в понятном пользователю варианте.
Все метрики интерпретируются таким образом, любые модификаторы на данной странице никак не влияют на общую структуру, поэтому стоит понять что на самом деле метрики по своей сущности являются инкапсулированным единичным запросом в базу данных.
Для написания метрик необходимо базовое понимание SQL, ознакомиться с основами можно в гайде. Секции с изменением схемы можно пропустить, т.к. конструктор аналитики не предполагает ее изменение, нас в основном интересует секция SQL Queries.
Помимо понимания SQL также необходимо знание схемы данных. Схема - это описание таблиц, колонок в них (например, типа данных), возможных значений.
Раскрывающийся блок Доступные поля отображает доступные для обращения поля, определённые текущим источником данных. Для источников, связанных с чатами (thread_source, thread_state_source, thread_message_source и т. п.), в список полей добавлено location (Размещение). Поле location можно использовать в выражениях метрик и для последующей группировки отчётов.
N.B.
В выражении метрики можно использовать любое поле из данного списка.
Созданная метрика в отчете:
N.B.
После создания метрики изменить источник уже нельзя, единственный вариант удалить метрику и создать заново.
N.B.
Дальнейший текст предполагает, что вы знакомы с базовыми SQL запросами и понимаете что такое агрегатные функции.
Далее рассмотрим смысловую нагрузку созданной метрики:
select sum(sign) from thread_state_source;
Мы видим источник данных thread_state_source, значит запрос будет направлен в таблицу, содержащую записи (строки), в которых отображено изменение состояний чатов. В данном случае на каждое состояние приходится по строке, в которой присутствуют колонки с названием состояния, его временные границы и т.п.
Далее рассмотрим выражение:
sum(sign)
Мы видим в нем агрегатную функцию sum и колонку источника sign.
sign - особенная колонка, она не связана с сущностью напрямую, как например, название состояния, но она помогает отделить старые строки от новых.
Описание из таблицы со страницы:
Вспомогательное поле, позволяющее отслеживать обновление строк в аналитической базе ClickHouse, при необходимости обновить строку, добавляется дубликат старой строки со знаком -1, за ним добавляется строка с новыми данными, но уже со знаком 1, в дальнейшем старые строки с разными знаками будут удалены силами СУБД
В метриках мы должны учитывать sign, если он присутствует в таблице. Также нельзя игнорировать наличие дубликатов строк со старыми данными.
В данном случае в выражении мы указываем, что нужно сложить значение колонки sign из каждой строки. Пусть на данный момент мы имеем следующие данные:
| id | ~ | sign | |
|---|---|---|---|
| 1 | ~ | 1 | Старая строка |
| 1 | ~ | -1 | Старая строка отменяющая значение |
| 1 | ~ | 1 | Новая строка |
Тогда при запросе нашей метрики мы сложим значения 1 + -1 + 1 и в итоге получим значение 1.
Когда это может быть полезно?
Например, нам нужно посчитать общее время всех состояний всех чатов. В таблице мы имеем следующие данные:
| id | started | ended | sign | |
|---|---|---|---|---|
| 1 | 10 | 20 | 1 | Старая строка для чата 1 |
| 1 | 10 | 20 | -1 | Старая строка для чата 1 отменяющая значение |
| 1 | 10 | 40 | 1 | Новая строка для чата 1 |
| 2 | 5 | 10 | 1 | Единственная строка для чата 2 |
Тогда выражение для подсчета будет выглядеть так:
sum((ended-started)*sign)
N.B.
Это только пример, в реальном кейсе нужно рассчитывать разницу между точками во времени, т.к. колонки stated и ended будут содержать значения типа DateTime. Тут же использованы обычные Int32 для облегчения понимания.
Рассмотрим вычисление построчно:
| id | started | ended | sum((ended-started)*sign) | |
|---|---|---|---|---|
| 1 | 10 | 20 | 1 | 10 |
| 1 | 10 | 20 | -1 | -10 |
| 1 | 10 | 40 | 1 | 30 |
| 2 | 5 | 10 | 1 | 5 |
В итоге, сложив значения 10 + -10 + 30 + 5, мы получим 35. Что является верным, т.к. строка 1 содержит старое значение, строка 2 отменяет его, а строка 3 содержит новое значение.
То есть, sign позволяет добавить знак к значению, и тогда при подсчете метрики старое неактуальное значение сложится с отменяющим его и мы получим 0, и в результат попадет только те значения, которые являются актуальными.
Важно!
Как сказано в описании колонки sign, в таблице может вообще не быть записей со знаком -1, т.к. ClickHouse периодически удаляет и отменяемую, и отменяющую строку, такое действие можно выполнить намеренно, выполнив OPTIMIZE table_name;, но не рекомендуется делать такое на продовых серверах.
Более подробно о sign можно прочитать в документации.
Чтение метрик
Важно отметить, что для чтения метрик также нужно базовое понимание того, как пишутся и рассчитываются SQL запросы, как применяются агрегатные функции и т.п.
Рассмотрим несколько сложных метрик, которые могут встретиться:
-
Обращений поступило в отдел
Источник:
thread_state_sourcesum(if(has(['offline_queue', 'queue'], states.state) AND (states.event != 'sys.unassign' or isNUll(states.event)) AND isNull(states.agent_id), sign, 0))Будет проще, если привести метрику к такому виду (далее рассматриваемые метрики всегда будут в таком виде):
sum( -- Агрегатная функция, складывающая значения строк if( -- Условная функция has(['offline_queue', 'queue'], states.state) -- Условие, является ли состояние чата offline_queue или queue AND (states.event != 'sys.unassign' or isNUll(states.event)) -- Условие, не является ли событие в строке sys.unassign или значение события Null AND isNull(states.agent_id), -- Условие, отсутсвует ли оператор в состоянии sign, -- Значение, если условие истинно 0 -- Значение, если условие ложно ) )В метрике нам встречается условная функция
if. Её логика проста:if(условие, значение если истина, значение если ложь).Также в метриках может встретиться другой ее вид - тернарный:
условие ? значение если истина : значение если ложь, например, как здесь:uniq(not hasAny(kinds, ['offline', 'missed']) ? id : null)То есть метрику можно интерпретировать так:
Если для строки выполняется условие: Состояние чата либо offline_queue, либо queue И событие чата ЛИБО не являеется sys.unassign, ЛИБО не назначен вовсе -- Либо здесь выступает как интерпритация оператора OR (ИЛИ) И оператор чата отсутствует Тогда возьми значние колонки sign Иначе возьми 0 Сложи все полученные значения -
Отвечено за 10 с. (В процентах)
round( -- Округли значение if( -- Условная функция sum( -- Условие states.state == 'queue' -- Состояние чата в строке queue and states.next_state == 'chatting' -- Следующее состояние чата в строке chatting and not has(kinds, 'offline') -- В типах чата нет offline, т.е. чат не является офлайновым and isNotNull(states.agent_id) -- В строке указан оператор состояния ) != 0, -- Проверяем есть ли вообще строки для обработки, чтобы избежать деления на 0 -- Выполни если истина sum( states.state == 'queue' -- Следующие 4 строки, включая текущую, копируют условие выше and states.next_state == 'chatting' and not has(kinds, 'offline') and isNotNull(states.agent_id) and dateDiff('second', states.started, states.ended) <= 10 -- Добавочное условие, что разница между концом и началом состояния в строке меньше либо равна 10 ? sign : 0 -- Если удовлетворяет условию, то возьмем sign, если нет, то 0 ) / sum( -- В данной строке присутствует математический оператор деления "/", мы буквально делим значение полученное суммой выше на значение полученное суммой ниже states.state == 'queue' -- Следующие 4 строки, включая текущую, копируют условие выше and states.next_state == 'chatting' and not has(kinds, 'offline') and isNotNull(states.agent_id) ? sign : 0 -- Если подходит условию, то возьмем sign, если нет, то 0 ), -- Выполни если ложь 0 ), 2 -- Округли значение, до второго знака после запятой )То есть метрику можно интерпретировать так:
Если количество строк, которые удовлетворяют условию: Состояние чата в строке queue И Следующее состояние чата в строке chatting И В типах чата нет offline, т.е. чат не является офлайновым И В строке указан оператор состояния Не равно нулю, тогда: (условие выше повторяется, поэтому введем для него всевдоним ГЛАВНОЕ_УСЛОВИЕ) Если для строки выполняется условие: ГЛАВНОЕ_УСЛОВИЕ И разница между концом и началом состояния в строке меньше либо равна 10 Тогда возьми значние колонки sign Иначе возьми 0 Сложи все полученные значения и запомни это как числитель Если для строки выполняется условие: ГЛАВНОЕ_УСЛОВИЕ Тогда возьми значние колонки sign Иначе возьми 0 Сложи все полученные значения и запомни это как знаменатель Подели числитель на знаменатель, возьми это как значение Если условие не выполняется возьми 0 Округли полученное значение до 2-х знаков после запятойТо есть, если подвести итог, всё, что мы делаем это:
-
Проверяем - есть ли строки для обработки, если нет - сразу возвращаем 0, чтобы избежать деления на 0
-
Считаем числитель по условию
-
Считаем знаменатель по условию
-
Делим числитель на знаменатель
-
Возвращаем округленное значение
-
N.B.
Все остальные метрики раскладываются точно также.
Переменные метрик
В конструкторе метрик при написании выражения есть возможность добавить некоторые переменные, значение которых будет подставлено в выражение, и тогда уже всё выражение с подставленной константой будет направлено в базу данных для вычисления.
Мы уже сталкивались с ними в разделе Параметры, в данной секции рассмотрим их конфигурацию.
Добавление переменных происходит при нажатии на соответствующую опцию в выпадающем меню.
N.B.
Ограничений по количеству переменных нет.
На данный момент существует два вида переменных:
-
Скалярные значения - представляют собой численную переменную, значение которой указывается по умолчанию и в будущем может быть изменено, что позволяет делать гибкие метрики. Например, "Ответ дан за N секунд", где N - является переменной.
Для скалярной переменной необходимо указать псевдоним для удобства операций над ней в будущем и стандартное значение, которое будет использоваться, если не указать другое значение при запросе отчета или в редакторе отчета

Добавление скалярной переменной Чтобы добавить переменную в метрику необходимо скопировать ее идентификатор
P0, нажав по нему левой кнопкой мыши, или ввести его в поле выражения самостоятельно.После сохранения метрики можно проверить, что наличие переменной теперь влияет на значение, а также появилась возможность изменить ее значение.
-
Опции аккаунт конфига - используются в тех случаях, когда вам необходимо получить некоторую информацию из конфигурации системы для использования её в подсчёте метрики. На данный момент по умолчанию доступна лишь одна опция:
max_chats_per_operator. Она, как и следует из названия, определяет максимальное количество чатов на оператора. В случае, если Вы хотели бы видеть в своём Редакторе метрик дополнительные опции account config, обратитесь в техническую поддержку.
Опция "Максимум чатов на операторе" Идентификатор переменных конфига отличается от идентификаторов скалярных переменных и в данном случае имеет вид
config.max_chats_per_operator.После сохранения отчета можно увидеть как переменная повлияла на значение, но не появилась возможность менять её значение, т.к. опции конфига - это системные переменные и их изменение происходит при изменении соответствующих опций.
Определение фильтров
В редакторе метрик присутствует возможность изменить логику фильтров, например, если метрика создана для источника "Записи о состояниях взаимодействий в процессе существования", то значение фильтра Период она использует для фильтрации по колонке states.started.
Если логика метрики предполагает, что фильтровать нужно по времени создания чата, тогда для фильтра Период будет использоваться колонка created.
Данное действие производится в секции Определение фильтров, в плейсхолдерах селекторов выводятся колонки, по которым стандартно происходит фильтрация.








