Momenteel verzamelt bijna elk bedrijf ter wereld statistieken over gebruikersacties op een webbron. De motivatie is duidelijk: bedrijven willen weten hoe hun product/website wordt gebruikt en willen hun gebruikers beter begrijpen. Uiteraard zijn er een groot aantal tools op de markt om dit probleem op te lossen – van analysesystemen die data leveren in de vorm van dashboards en grafieken (bijvoorbeeld
Maar we hebben een probleem gevonden dat nog niet is opgelost. Zo geboren
Waarom zouden we onze eigen dienst ontwikkelen?
Het waren de jaren negentig, we overleefden zo goed als we konden. In 2019 hebben we de First Customer Data Platform API ontwikkeld kSense, waarmee gegevens uit verschillende bronnen konden worden samengevoegd (Facebook-advertenties, Stripe, Salesforce, Google Play, Google Analytics, enz.) voor gemakkelijkere gegevensanalyse, het identificeren van afhankelijkheden, enz. We hebben gemerkt dat veel gebruikers ons data-analyseplatform gebruiken, met name Google Analytics (hierna GA genoemd). We spraken met enkele gebruikers en kwamen erachter dat ze hun productanalysegegevens nodig hebben, die ze ontvangen via GA, maar
Ze installeerden een Segment javascript-pixel op hun webbron en hun gebruikersgedragsgegevens werden in een gespecificeerde database (bijvoorbeeld Postgres) geladen. Maar Segment heeft ook zijn minpunt: de prijs. Als een webbron bijvoorbeeld 90,000 MTU (maandelijks bijgehouden gebruikers) heeft, moet u ~ $ 1,000 per maand aan de kassier betalen. Er was ook een derde probleem: sommige browserextensies (zoals AdBlock) blokkeerden het verzamelen van analyses. http-verzoeken van de browser zijn verzonden naar de GA- en Segment-domeinen. Op basis van de wens van onze klanten hebben we een analysedienst gecreëerd die gratis een volledige set gegevens verzamelt (zonder steekproeven) en op onze eigen infrastructuur kan werken.
Hoe de dienst werkt
De dienst bestaat uit drie delen: een javascript-pixel (die we later hebben herschreven tot typoscript), een serverdeel geïmplementeerd in de GO-taal, en het was de bedoeling om Redshift en BigQuery te gebruiken als interne database (later voegden ze ondersteuning toe voor Postgres , ClickHouse en Sneeuwvlok).
De structuur van de evenementen GA en Segment besloten ongewijzigd te blijven. Het enige dat nodig was, was het dupliceren van alle gebeurtenissen van de webbron waarop de pixel is geïnstalleerd naar onze backend. Het blijkt dat dit gemakkelijk te doen is. De Javascript-pixel heeft de oorspronkelijke GA-bibliotheekmethode overschreven door een nieuwe die de gebeurtenis in ons systeem dupliceerde.
//'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);
});
});
}
Met de Segment-pixel is alles eenvoudiger, het heeft middleware-methoden en we hebben er een van gebruikt.
//'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.');
}
Naast het kopiëren van gebeurtenissen hebben we de mogelijkheid toegevoegd om willekeurige json te verzenden:
//Отправка событий с произвольным 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'
});
Laten we het vervolgens hebben over de serverkant. De backend moet http-verzoeken accepteren en deze vullen met aanvullende informatie, bijvoorbeeld geogegevens (bedankt
//входящий 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"
}
Arrays worden momenteel echter eenvoudigweg geconverteerd naar strings. niet alle relationele databases ondersteunen herhaalde velden. Het is ook mogelijk om veldnamen te wijzigen of te verwijderen met behulp van optionele toewijzingsregels. Hiermee kunt u indien nodig het gegevensschema wijzigen of het ene gegevenstype naar het andere casten. Als het json-veld bijvoorbeeld een tekenreeks met een tijdstempel (veld_3_sub_veld_1_sub_sub_veld_1 uit het bovenstaande voorbeeld), en om een veld in de database te maken met het tijdstempeltype, moet u een toewijzingsregel in de configuratie schrijven. Met andere woorden: het gegevenstype van het veld wordt eerst bepaald door de json-waarde en vervolgens wordt de typecast-regel (indien geconfigureerd) toegepast. We hebben vier hoofdgegevenstypen geïdentificeerd: STRING, FLOAT4, INT64 en TIMESTAMP. De mapping- en castingregels zien er als volgt uit:
rules:
- "/field_1/subfield_1 -> " #правило удаления поля
- "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля
- "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа
Algoritme voor het bepalen van het gegevenstype:
- converteer json-struct naar platte struct
- het gegevenstype van velden bepalen aan de hand van waarden
- het toepassen van mapping- en typecasting-regels
Vervolgens vanuit de binnenkomende json-structuur:
{
"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"
}
}
gegevensschema wordt verkregen:
"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
We dachten ook dat de gebruiker partities zou moeten kunnen instellen of gegevens in de database zou kunnen splitsen op basis van andere criteria, en implementeerden de mogelijkheid om de tabelnaam in te stellen als een constante of
tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'
De structuur van binnenkomende gebeurtenissen kan echter tijdens runtime veranderen. We hebben een algoritme geïmplementeerd om het verschil te controleren tussen de structuur van een bestaande tabel en de structuur van een binnenkomende gebeurtenis. Als er een verschil wordt gevonden, wordt de tabel bijgewerkt met nieuwe velden. Gebruik hiervoor de patch-SQL-query:
#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying
Architectuur
Waarom moet u gebeurtenissen naar het bestandssysteem schrijven, en ze niet alleen rechtstreeks naar de database schrijven? Databases presteren niet altijd goed met een groot aantal invoegingen (
Open Source en toekomstplannen
Op een gegeven moment werd de dienst een volwaardig product en besloten we deze in Open Source te zetten. Op dit moment zijn integraties met Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake geïmplementeerd. Alle integraties ondersteunen zowel batch- als streaminggegevenslaadmodi. Ondersteuning toegevoegd voor verzoeken via API.
Het huidige integratieschema ziet er als volgt uit:
Hoewel de dienst zelfstandig kan worden gebruikt (bijvoorbeeld met Docker), hebben wij dat ook
→
→
→
Wij zullen blij zijn als EventNative u helpt bij het oplossen van uw problemen!
Alleen geregistreerde gebruikers kunnen deelnemen aan het onderzoek.
Welk systeem voor het verzamelen van statistieken wordt in uw bedrijf gebruikt
-
48,0%Google Analytics12
-
4,0%Segment1
-
16,0%Anders (schrijf in de reacties) 4
-
32,0%Uw dienst geïmplementeerd8
25 gebruikers hebben gestemd. 6 gebruikers onthielden zich van stemming.
Bron: www.habr.com