В момента почти всяка компания в света събира статистика за действията на потребителите на уеб ресурс. Мотивацията е ясна – компаниите искат да знаят как се използва техният продукт/уебсайт и да разбират по-добре своите потребители. Разбира се, на пазара има голям брой инструменти за решаване на този проблем - от системи за анализ, които предоставят данни под формата на табла и графики (напр.
Но открихме проблем, който все още не е решен. Така се роди
Защо трябва да развиваме собствена услуга?
Беше деветдесетте години, оцеляхме както можахме. 2019 разработихме API First Customer Data Platform kSense, което направи възможно агрегирането на данни от различни източници (реклами във Facebook, Stripe, Salesforce, Google play, Google Analytics и др.) за по-удобен анализ на данни, идентифициране на зависимости и др. Забелязахме, че много потребители използват нашата платформа за анализ на данни, по-специално Google Analytics (наричана по-долу GA). Разговаряхме с някои потребители и разбрахме, че те се нуждаят от аналитични данни за своя продукт, които получават с помощта на GA, но
Те инсталираха Segment javascript пиксел на своя уеб ресурс и данните за поведението на техните потребители бяха заредени в посочената база данни (например Postgres). Но Segment има и своя недостатък - цената. Например, ако даден уеб ресурс има 90,000 1,000 MTU (месечно проследявани потребители), тогава трябва да плащате ~XNUMX $ на месец на касата. Имаше и трети проблем - някои разширения на браузъра (като AdBlock) блокираха събирането на анализи, защото... http заявките от браузъра бяха изпратени до домейните GA и Segment. Въз основа на желанията на нашите клиенти създадохме аналитична услуга, която събира пълен набор от данни (без извадка), безплатна е и може да работи върху нашата собствена инфраструктура.
Как работи услугата
Услугата се състои от три части: javascript пиксел (който по-късно пренаписахме на машинопис), сървърната част е внедрена на езика GO и беше планирано да се използват Redshift и BigQuery като вътрешна база данни (по-късно те добавиха поддръжка за Postgres, ClickHouse и Snowflake).
Беше решено структурата на събитията на GA и сегмента да остане непроменена. Всичко, което беше необходимо, беше да дублираме всички събития от уеб ресурса, където е инсталиран пикселът, в нашия бекенд. Както се оказа, това не е трудно да се направи. Пикселът на Javascript замени оригиналния метод на библиотеката на GA с нов, който дублира събитието в нашата система.
//'ga' - стандартное название переменной Google Analytics
if (window.ga) {
ga(tracker => {
var originalSendHitTask = tracker.get('sendHitTask');
tracker.set('sendHitTask', (model) => {
var payLoad = model.get('hitPayload');
//отправка оригинального события в GA
originalSendHitTask(model);
let jsonPayload = this.parseQuery(payLoad);
//отправка события в наш сервис
this.send3p('ga', jsonPayload);
});
});
}
Със Segment pixel всичко е по-просто; той има мидълуерни методи, един от които използвахме.
//'analytics' - стандартное название переменной Segment
if (window.analytics) {
if (window.analytics.addSourceMiddleware) {
window.analytics.addSourceMiddleware(chain => {
try {
//дублирование события в наш сервис
this.send3p('ajs', chain.payload);
} catch (e) {
LOG.warn('Failed to send an event', e)
}
//отправка оригинального события в Segment
chain.next(chain.payload);
});
} else {
LOG.warn("Invalid interceptor state. Analytics js initialized, but not completely");
}
} else {
LOG.warn('Analytics.js listener is not set.');
}
В допълнение към копирането на събития, добавихме възможност за изпращане на произволен json:
//Отправка событий с произвольным json объектом
eventN.track('product_page_view', {
product_id: '1e48fb70-ef12-4ea9-ab10-fd0b910c49ce',
product_price: 399.99,
price_currency: 'USD'
product_release_start: '2020-09-25T12:38:27.763000Z'
});
След това нека поговорим за сървърната част. Бекендът трябва да приема http заявки, да ги попълва с допълнителна информация, например географски данни (благодаря
//входящий json
{
"field_1": {
"sub_field_1": "text1",
"sub_field_2": 100
},
"field_2": "text2",
"field_3": {
"sub_field_1": {
"sub_sub_field_1": "2020-09-25T12:38:27.763000Z"
}
}
}
//результат
{
"field_1_sub_field_1": "text1",
"field_1_sub_field_2": 100,
"field_2": "text2",
"field_3_sub_field_1_sub_sub_field_1": "2020-09-25T12:38:27.763000Z"
}
Понастоящем обаче масивите просто се преобразуват в низове, защото Не всички релационни бази данни поддържат повтарящи се полета. Също така е възможно да промените имената на полетата или да ги изтриете, като използвате опционални правила за картографиране. Те ви позволяват да промените схемата на данните, ако е необходимо, или да конвертирате един тип данни в друг. Например, ако json поле съдържа низ с клеймо за време (поле_3_под_поле_1_под_под_поле_1 от примера по-горе), тогава, за да създадете поле в базата данни с тип timestamp, трябва да напишете правило за съпоставяне в конфигурацията. С други думи, типът данни на полето се определя първо от json стойността и след това се прилага правилото за преобразуване на типа (ако е конфигурирано). Идентифицирахме 4 основни типа данни: STRING, FLOAT64, INT64 и TIMESTAMP. Правилата за картографиране и преобразуване на типове изглеждат така:
rules:
- "/field_1/subfield_1 -> " #правило удаления поля
- "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля
- "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа
Алгоритъм за определяне на типа данни:
- конвертирайте json структура в плоска структура
- определяне на типа данни на полетата по стойности
- прилагане на правила за картографиране и преобразуване на типове
След това от входящата json структура:
{
"product_id": "1e48fb70-ef12-4ea9-ab10-fd0b910c49ce",
"product_price": 399.99,
"price_currency": "USD",
"product_type": "supplies",
"product_release_start": "2020-09-25T12:38:27.763000Z",
"images": {
"main": "picture1",
"sub": "picture2"
}
}
ще се получи схемата на данните:
"product_id" character varying,
"product_price" numeric (38,18),
"price_currency" character varying,
"product_type" character varying,
"product_release_start" timestamp,
"images_main" character varying,
"images_sub" character varying
Ние също решихме, че потребителят трябва да може да конфигурира разделяне или разделяне на данни в базата данни според други критерии и внедрихме възможността да зададем името на таблицата с константа или
tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'
Структурата на входящите събития обаче може да се промени по време на изпълнение. Внедрихме алгоритъм за проверка на разликата между структурата на съществуваща таблица и структурата на входящо събитие. Ако се установи разлика, таблицата ще бъде актуализирана с нови полета. За да направите това, използвайте SQL заявката за корекция:
#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying
архитектура
Защо трябва да записвате събития във файловата система, а не просто да ги записвате директно в базата данни? Базите данни не винаги се представят добре, когато работят с голям брой вмъквания (
Open Source и планове за бъдещето
В един момент услугата започна да изглежда като пълноценен продукт и решихме да я пуснем с отворен код. В момента са внедрени интеграции с Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. Всички интеграции поддържат както пакетен, така и поточен режим на зареждане на данни. Добавена е поддръжка за заявки чрез API.
Сегашната интеграционна схема изглежда така:
Въпреки че услугата може да се използва независимо (например с помощта на Docker), ние също имаме
→
→
→
Ще се радваме, ако EventNative помогне за разрешаването на вашите проблеми!
В анкетата могат да участват само регистрирани потребители.
Каква система за събиране на статистически данни се използва във вашата компания?
-
48,0%Google Analytics12
-
4,0%Сегмент1
-
16,0%Друг (пишете в коментарите)4
-
32,0%Внедри вашата услуга8
25 потребители гласуваха. 6 потребители се въздържаха.
Източник: www.habr.com