Не можешь победить — автоматизируй. Упрощаем рутину в аналитических задачах

c6f36b1e936c263e1f80177b919ebe01.jpg

Автоматизация — краеугольный камень современной аналитики, и речь здесь не только о том, чтобы оптимально настроить масштабные базовые процессы вроде CI/CD. Точечное внедрение инструментов и фреймворков, исходя из конкретной задачи, могут дать ощутимый быстрый эффект как минимум на уровне экономии времени. И стать предпосылками к более крупным оптимизациям.

Одним из наших локальных кейсов автоматизации в Сравни делимся под катом. Рассказываем, как наладили регулярный процесс сверки данных из десятков таблиц силами одного специалиста, с помощью уже имеющихся в компании инструментов — low code-платформы и мессенджера.

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

Привет, Хабр! Я Никита, аналитик данных в Сравни. Занимаюсь оптимизацией и автоматизацией процессов аналитики, выстраиваю взаимодействие между бизнесом и аналитикой в различных командах. Сегодня расскажу, как мы наладили и автоматизировали один из важных процессов: сэкономили массу времени на выполнении рутинных операций по сверке данных из таблиц и уменьшили риски потери денег для компании. 

Давайте сопоставим данные — их и наши

В команде «Образования» мы работаем над сервисом сравнения и выбора различных образовательных курсов, то есть выступаем агрегатором в EdTech. Например, если пользователь не знает, какой курс по аналитике данных выбрать, он может зайти к нам на сайт, посмотреть список таких курсов и выбрать наиболее подходящий.

Мы работаем с партнерами по модели CPA. То есть пользователь попадает на наш сайт, совершает какое-то целевое действие, например, клик, и за это мы получаем комиссию от партнера. 

Чтобы точно отслеживать целевые действия, необходима трекинговая система, которая будет их записывать. Мы используем TUNE (бывш. HasOffers). Cистему нужно настроить на нашей стороне и на стороне партнера. У нас ее настроить легко, а вот у партнеров — увы, не всегда, поскольку события записываются на их бэкенде, и сами партнеры должны передавать их в трекинговую систему. Не у всех партнеров есть такие технические возможности — для этого требуется определенное количество разработчиков. Поэтому есть риск, что те или иные конверсии не попадут в трекинговую систему. 

Чтобы компании избежать потери денег из-за некорректного подсчета конверсий, пришлось организовать процесс сверки — в первом приближении вручную, поэтому довольно трудоёмко. Ежемесячно партнер присылал нам выгрузку со всеми транзакциями из своей трекинговой системы (как правило, это CRM-системы); наши аккаунт-менеджеры просили аналитиков сделать выгрузку со всеми операциями из нашей системы. Менеджеры сверяли выгрузки и искали различия. При их обнаружении шли к партнеру обсудить вопросы по той или иной транзакции. И просили аналитиков загрузить её к нам в базу данных.

Партнеров у нас десятки. Как несложно догадаться, рутинный процесс отнимал массу времени и нервов у наших аккаунтов и аналитиков. 

Мы решили это изменить — с помощью «подручных средств» организовали несложный процесс автоматизации. И теперь ежемесячная задача, занимавшая у менеджеров неделю рабочего времени, сократилась до нескольких часов работы.

Автоматизация

Основная трудность в этом кейсе даже не техническая, а управленческая. Важно было договориться с каждым партнером, чтобы они регулярно присылали нам корректную таблицу со всеми операциями. Изначально я допустил фатальную ошибку, сказав, что можно отправлять нам таблицы любого формата: «для партнера будет менее трудоемко, а я их всё равно обработаю». Это в разы замедлило мою работу: между таблицами партнеров были существенные отличия, все их требовалось провести в единый формат. 

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

Рассмотрим подробнее каждый этап.

Сперва нам нужно было загрузить в базу данных Snowflake десятки гугл-таблиц от наших партнеров. В качестве инструмента для этого масштабного ETL-процесса мы выбрали low code платформу n8n, которая до этого уже применялась в компании. Лично мне она понравилась за счет простоты использования, удобного UI и внушительного списка интеграций с другими инструментами.

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

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

Так выглядит флоу по загрузке данных. К сожалению, из-за количества нод (117) не получилось все уместить на одной картинке

Так выглядит флоу по загрузке данных. К сожалению, из-за количества нод (117) не получилось все уместить на одной картинке

Начали мы с базовой стандартизации данных — наиболее коварной части всего процесса. Я провёл встречу и написал документацию для наших менеджеров, чтобы они могли доступно объяснить партнерам правила оформления таблиц с данными. При разработке этого ТЗ постарался учесть все корнер-кейсы, которые могли встречаться в таблицах. Тем не менее, человеческий фактор никто не отменял, поэтому иногда в выгрузках я вижу страшные вещи. Например, дату в соответствующий столбец вставляют буквально прописью. Вместо 10.09.2024 аналитик видит «десятое сентября» — представьте его лицо в этот момент!

Когда такое происходит, возникает ошибка при записи в Snowflake, поскольку тип данных не соответствует ожидаемому. И здесь очень помогает система алертов, которую можно настроить в n8n. При возникновении ошибки мне в мессенджер прилетает вот такое сообщение:

52ffd731b3e1c11260f7cef615642cc7.jpg

Сама же стандартизация ака обработка данных в 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.

Вот так выглядят логи проверки:  

89a94ac660898dbcf0543b6fcb44d194.png

В итоге сообщение с проверкой выглядит следующим образом:  

6f9eae10ac3e5848def281659ef1bfdb.png

После получения такого файлика менеджерам остается лишь направить его партнеру со словами: «Где транзакции, Лебовски?».

Построение этого несложного flow помогло сэкономить массу времени и нервов нашим аккаунт-менеджерам, высвободив их ресурс для более полезных бизнес-задач. 

Весь процесс можно представить в виде такой схемы:

1a9a2793dea3b0b4f04d6addbab42b92.jpg

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

Автоматизация, которая у нас в итоге получилась, опирается на специфику работы стрима «Образование»). В других направлениях (страхование, кредиты, остальное) технические и организационные детали реализации могут отличаться, с учётом специфики взаимодействия с партнерами. Но где угодно, далеко не только в задаче сопоставления данных из внутренних и внешних источников, могут пригодиться два ключевых принципа из кейса выше. 

Во-первых, вместо решения отдельно взятой задачи («взаимодействие с конкретным партнером») попробовать решить сразу класс таких задач («взаимодействие со всеми партнерами»).

Во-вторых, выжимать больше из уже имеющихся инструментов.

***

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

© Habrahabr.ru