Не можешь победить — автоматизируй. Упрощаем рутину в аналитических задачах
Автоматизация — краеугольный камень современной аналитики, и речь здесь не только о том, чтобы оптимально настроить масштабные базовые процессы вроде CI/CD. Точечное внедрение инструментов и фреймворков, исходя из конкретной задачи, могут дать ощутимый быстрый эффект как минимум на уровне экономии времени. И стать предпосылками к более крупным оптимизациям.
Одним из наших локальных кейсов автоматизации в Сравни делимся под катом. Рассказываем, как наладили регулярный процесс сверки данных из десятков таблиц силами одного специалиста, с помощью уже имеющихся в компании инструментов — low code-платформы и мессенджера.
По итогу автоматизации остались довольны и аналитики, и аккаунт-менеджеры: теперь вместо недели рабочего времени задача сверки данных из таблиц занимает несколько часов (с перспективой дальнейшего ускорения).
Привет, Хабр! Я Никита, аналитик данных в Сравни. Занимаюсь оптимизацией и автоматизацией процессов аналитики, выстраиваю взаимодействие между бизнесом и аналитикой в различных командах. Сегодня расскажу, как мы наладили и автоматизировали один из важных процессов: сэкономили массу времени на выполнении рутинных операций по сверке данных из таблиц и уменьшили риски потери денег для компании.
Давайте сопоставим данные — их и наши
В команде «Образования» мы работаем над сервисом сравнения и выбора различных образовательных курсов, то есть выступаем агрегатором в EdTech. Например, если пользователь не знает, какой курс по аналитике данных выбрать, он может зайти к нам на сайт, посмотреть список таких курсов и выбрать наиболее подходящий.
Мы работаем с партнерами по модели CPA. То есть пользователь попадает на наш сайт, совершает какое-то целевое действие, например, клик, и за это мы получаем комиссию от партнера.
Чтобы точно отслеживать целевые действия, необходима трекинговая система, которая будет их записывать. Мы используем TUNE (бывш. HasOffers). Cистему нужно настроить на нашей стороне и на стороне партнера. У нас ее настроить легко, а вот у партнеров — увы, не всегда, поскольку события записываются на их бэкенде, и сами партнеры должны передавать их в трекинговую систему. Не у всех партнеров есть такие технические возможности — для этого требуется определенное количество разработчиков. Поэтому есть риск, что те или иные конверсии не попадут в трекинговую систему.
Чтобы компании избежать потери денег из-за некорректного подсчета конверсий, пришлось организовать процесс сверки — в первом приближении вручную, поэтому довольно трудоёмко. Ежемесячно партнер присылал нам выгрузку со всеми транзакциями из своей трекинговой системы (как правило, это CRM-системы); наши аккаунт-менеджеры просили аналитиков сделать выгрузку со всеми операциями из нашей системы. Менеджеры сверяли выгрузки и искали различия. При их обнаружении шли к партнеру обсудить вопросы по той или иной транзакции. И просили аналитиков загрузить её к нам в базу данных.
Партнеров у нас десятки. Как несложно догадаться, рутинный процесс отнимал массу времени и нервов у наших аккаунтов и аналитиков.
Мы решили это изменить — с помощью «подручных средств» организовали несложный процесс автоматизации. И теперь ежемесячная задача, занимавшая у менеджеров неделю рабочего времени, сократилась до нескольких часов работы.
Автоматизация
Основная трудность в этом кейсе даже не техническая, а управленческая. Важно было договориться с каждым партнером, чтобы они регулярно присылали нам корректную таблицу со всеми операциями. Изначально я допустил фатальную ошибку, сказав, что можно отправлять нам таблицы любого формата: «для партнера будет менее трудоемко, а я их всё равно обработаю». Это в разы замедлило мою работу: между таблицами партнеров были существенные отличия, все их требовалось провести в единый формат.
С технической точки зрения я выстроил процесс таким образом: получаем от каждого партнера гугл-таблицу, загружаем ее к нам в базу данных, а далее делаем проверку, которая будет выделять различия в транзакциях и предоставлять менеджеру уже готовый файл.
Рассмотрим подробнее каждый этап.
Сперва нам нужно было загрузить в базу данных Snowflake десятки гугл-таблиц от наших партнеров. В качестве инструмента для этого масштабного ETL-процесса мы выбрали low code платформу n8n, которая до этого уже применялась в компании. Лично мне она понравилась за счет простоты использования, удобного UI и внушительного списка интеграций с другими инструментами.
Платформа позволяет загружать данные инкрементально, то есть добавлять только новые данные, без полного сканирования и перезаписи таблицы. Плюс преобразовывать данные прямо на этапе их заливки.
В целом функциональность n8n полностью соответствовала нашей задаче и покрывала основные потребности.
Так выглядит флоу по загрузке данных. К сожалению, из-за количества нод (117) не получилось все уместить на одной картинке
Начали мы с базовой стандартизации данных — наиболее коварной части всего процесса. Я провёл встречу и написал документацию для наших менеджеров, чтобы они могли доступно объяснить партнерам правила оформления таблиц с данными. При разработке этого ТЗ постарался учесть все корнер-кейсы, которые могли встречаться в таблицах. Тем не менее, человеческий фактор никто не отменял, поэтому иногда в выгрузках я вижу страшные вещи. Например, дату в соответствующий столбец вставляют буквально прописью. Вместо 10.09.2024 аналитик видит «десятое сентября» — представьте его лицо в этот момент!
Когда такое происходит, возникает ошибка при записи в Snowflake, поскольку тип данных не соответствует ожидаемому. И здесь очень помогает система алертов, которую можно настроить в n8n. При возникновении ошибки мне в мессенджер прилетает вот такое сообщение:
Сама же стандартизация ака обработка данных в n8n легко выполняется через python-код. Вот пример такого кода:
from datetime import datetime
#Переименовываем столбцы
for item in _input.all():
item.json['COURSE_NAME'] = item.json.pop('Название курса')
for item in _input.all():
item.json['LEAD_DT'] = item.json.pop('Дата заявки')
#функция, которая заменяет пропуски в выручке на 0
def revenue(data):
if not data:
return '0'
else:
return data
#Применяем функцию
for item in _input.all():
item.json['SCHOOL_REVENUE_VAT'] = revenue(item.json['SCHOOL_REVENUE_VAT'])
for item in _input.all():
item.json['SRAVNI_REVENUE_VAT'] = revenue(item.json['SRAVNI_REVENUE_VAT'])
#Функция для обработки даты
def remove_time_from_date(date_time_str):
if not date_time_str:
return date_time_str
current_year = datetime.now().year
#Перебираем форматы дат
formats = ['%d.%m.%Y %H:%M:%S', '%Y-%m-%d %H:%M:%S', '%d.%m.%Y %H:%M', '%d.%m.%Y', '%d.%m', '%d-%m-%Y', '%d.%m.%Y, %H:%M']
for fmt in formats:
try:
#Пробуем распарсить дату
date_time_obj = datetime.strptime(date_time_str, fmt)
#Если формат без года, добавляем текущий год
if fmt == '%d.%m':
date_time_obj = date_time_obj.replace(year=current_year)
#Возвращаем дату в формате 'YYYY-MM-DD'
return date_time_obj.strftime('%Y-%m-%d')
except ValueError:
#Если текущий формат не сработал, продолжаем проверку
continue
#Если ни один формат не подошел, возвращаем исходную строку
return date_time_str
#Применяем функцию для форматирования даты
for item in _input.all():
item.json['LEAD_DT'] = remove_time_from_date(item.json['LEAD_DT'])
for item in _input.all():
item.json['SALE_DT'] = remove_time_from_date(item.json['SALE_DT'])
#Прописываем тип курса
for item in _input.all():
item.json['POSTBACK_TYPE'] = 'Платный'
#Прописываем модель оплаты
for item in _input.all():
item.json['MODEL'] = 'CPS'
return _input.all()
В n8n есть особенность: при чтении таблицы программа конвертирует таблицу в JSON. Поэтому в коде мы работаем с JSON«ами, хотя данные, на самом деле, представлены в табличном виде.
После того, как загрузили все данные, можем начинать процесс сверки между двумя источниками.
ETL-процесс из n8n к нам в Snowflake работает на ежедневной основе, чтобы как можно скорее автоматически анализировать поступившие данные. Дату последней проверки при наличии новых данных мы записываем в специальную таблицу с логами, чтобы python-скрипт не проверял одно и тоже каждый день.
Сама проверка заключается в том, что мы берем id транзакции из нашей базы и сравниваем его с id транзакции партнера; если они различаются, это записывается в специальную эксель-таблицу, которую бот по API отправляет в мессенджер. Более того, если мы видим, что в нашей базе нет какого-либо id транзакции, то скрипт автоматически записывает его к нам в трекинговую систему. Это позволяет видеть все потерянные транзакции в наших отчётах, например, на чартах в SuperSet.
Вот так выглядят логи проверки:
В итоге сообщение с проверкой выглядит следующим образом:
После получения такого файлика менеджерам остается лишь направить его партнеру со словами: «Где транзакции, Лебовски?».
Построение этого несложного flow помогло сэкономить массу времени и нервов нашим аккаунт-менеджерам, высвободив их ресурс для более полезных бизнес-задач.
Весь процесс можно представить в виде такой схемы:
В дальнейшем мы планируем усовершенствовать процесс. Получать данные чаще (еженедельно, а не ежемесячно) и визуализировать их через BI-инструменты. Это позволит нашим сейлзам и PO принимать решения на основе еще более актуальных данных.
Автоматизация, которая у нас в итоге получилась, опирается на специфику работы стрима «Образование»). В других направлениях (страхование, кредиты, остальное) технические и организационные детали реализации могут отличаться, с учётом специфики взаимодействия с партнерами. Но где угодно, далеко не только в задаче сопоставления данных из внутренних и внешних источников, могут пригодиться два ключевых принципа из кейса выше.
Во-первых, вместо решения отдельно взятой задачи («взаимодействие с конкретным партнером») попробовать решить сразу класс таких задач («взаимодействие со всеми партнерами»).
Во-вторых, выжимать больше из уже имеющихся инструментов.
***
На вопросы о нашем кейсе будем рады ответить в комментариях. Также делитесь своими примерами автоматизации рутинных процессов в аналитике: уверены, почти в каждой компании есть свои подобные подходы и лайфхаки, будет интересно о них узнать!