Nuntempe, preskaŭ ĉiuj kompanioj en la mondo kolektas statistikojn pri uzant-agoj en interreta rimedo. La instigo estas klara - kompanioj volas scii kiel ilia produkto/retejo estas uzata kaj pli bone kompreni siajn uzantojn. Kompreneble, ekzistas granda nombro da iloj sur la merkato por solvi ĉi tiun problemon - de analizaj sistemoj, kiuj provizas datumojn en formo de paneloj kaj grafikaĵoj (ekzemple
Sed ni trovis problemon, kiu ankoraŭ ne estis solvita. Tiel naskiĝis
Kial ni devus disvolvi nian propran servon?
Estis la naŭdekaj, ni pluvivis kiel eble plej bone. 2019, ni evoluigis la API Unua Klienta Datuma Platformo kSense, kiu ebligis kunigi datumojn de malsamaj fontoj (Facebook-reklamoj, Stripe, Salesforce, Google play, Google Analytics, ktp.) por pli oportuna analizo de datumoj, identigi dependecojn ktp. Ni rimarkis, ke multaj uzantoj uzas nian platformon por analizo de datumoj specife Google Analytics (ĉi-poste GA). Ni parolis kun kelkaj uzantoj kaj eksciis, ke ili bezonas la analizajn datumojn por sia produkto, kiun ili ricevas uzante GA, sed
Ili instalis Segment-javascript-pikselon sur sia retejo-rimedo kaj datumoj pri la konduto de siaj uzantoj estis ŝarĝitaj en la specifitan datumbazon (ekzemple Postgres). Sed Segmento ankaŭ havas sian malavantaĝon - la prezon. Ekzemple, se interreta rimedo havas 90,000 MTU (monate spuritajn uzantojn), tiam vi devas pagi ~1,000 $ monate al la kasisto. Estis ankaŭ tria problemo - kelkaj retumiloj (kiel AdBlock) blokis la kolekton de analizoj ĉar... http-petoj de la retumilo estis senditaj al la domajnoj GA kaj Segment. Surbaze de la deziroj de niaj klientoj, ni kreis analitikan servon, kiu kolektas kompletan aron da datumoj (sen specimeno), estas senpaga kaj povas funkcii per nia propra infrastrukturo.
Kiel funkcias la servo
La servo konsistas el tri partoj: ĵavaskripto-pikselo (kiun ni poste reverkis per tajpskribo), la servila parto estas efektivigita en la GO-lingvo, kaj estis planite uzi Redshift kaj BigQuery kiel endoman datumbazon (poste ili aldonis subtenon por Postgres, ClickHouse kaj Snowflake).
Estis decidite lasi la strukturon de la GA kaj Segment-okazaĵoj senŝanĝa. Ĉio, kio estis bezonata, estis duobligi ĉiujn eventojn de la interreta rimedo kie la pikselo estas instalita al nia backend. Kiel ĝi rezultas, ĉi tio ne estas malfacile fari. La Javascript-pikselo superregis la originan GA-bibliotekan metodon per nova, kiu duobligis la eventon en nian sistemon.
//'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);
});
});
}
Kun la Segment-pikselo ĉio estas pli simpla; ĝi havas mezvarmetodojn, unu el kiuj ni uzis.
//'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.');
}
Krom kopii eventojn, ni aldonis la kapablon sendi arbitran 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'
});
Poste, ni parolu pri la servila parto. La backend devas akcepti http-petojn, plenigi ilin per pliaj informoj, ekzemple geodatenoj (dankon
//входящий 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"
}
Tamen, tabeloj estas nuntempe simple konvertitaj al ŝnuroj ĉar Ne ĉiuj rilataj datumbazoj subtenas ripetajn kampojn. Eblas ankaŭ ŝanĝi kamponomojn aŭ forigi ilin uzante laŭvolajn mapajn regulojn. Ili permesas vin ŝanĝi la datumskemon se necese aŭ konverti unu datumtipo al alia. Ekzemple, se json-kampo enhavas ĉenon kun tempomarko (kampo_3_sub_kampo_1_sub_sub_kampo_1 de la supra ekzemplo), tiam por krei kampon en la datumbazo kun la tempomarko-tipo, vi devas skribi mapan regulon en la agordo. Alivorte, la datumtipo de la kampo unue estas determinita per la json-valoro, kaj tiam la tipa casting-regulo (se agordita) estas aplikata. Ni identigis 4 ĉefajn datumtipojn: STRING, FLOAT64, INT64 kaj TIMESTAMP. La reguloj pri mapado kaj tajpado aspektas jene:
rules:
- "/field_1/subfield_1 -> " #правило удаления поля
- "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля
- "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа
Algoritmo por determini la datumtipo:
- konverti json-strukturon al plata strukturo
- determinante la datumspecon de kampoj per valoroj
- aplikante mapajn kaj tajpajn regulojn
Tiam de la envenanta json-strukturo:
{
"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"
}
}
la datumskemo estos akirita:
"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
Ni ankaŭ pensis, ke la uzanto devus povi agordi dispartigon aŭ dividi datumojn en la datumbazo laŭ aliaj kriterioj kaj efektivigis la kapablon agordi la tabelnomon per konstanta aŭ
tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'
Tamen, la strukturo de envenantaj eventoj povas ŝanĝiĝi ĉe rultempo. Ni efektivigis algoritmon por kontroli la diferencon inter la strukturo de ekzistanta tabelo kaj la strukturo de envenanta evento. Se oni trovas diferencon, la tabelo estos ĝisdatigita kun novaj kampoj. Por fari tion, uzu la flikan SQL-demandon:
#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying
arkitekturo
Kial vi bezonas skribi eventojn al la dosiersistemo, kaj ne nur skribi ilin rekte al la datumbazo? Datumbazoj ne ĉiam funkcias bone kiam traktas grandajn nombrojn da enigaĵoj (
Malferma Kodo kaj planoj por la estonteco
Iam, la servo komencis aspekti kiel plentaŭga produkto kaj ni decidis liberigi ĝin al Malferma Fonto. Nuntempe, integriĝoj kun Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake estis efektivigitaj. Ĉiuj integriĝoj subtenas ambaŭ batajn kaj fluajn reĝimojn de datumŝarĝado. Aldonita subteno por petoj per API.
La nuna integriga skemo aspektas jene:
Kvankam la servo povas esti uzata sendepende (ekzemple uzante Docker), ni ankaŭ havas
→
→
→
Ni ĝojos, se EventNative helpos solvi viajn problemojn!
Nur registritaj uzantoj povas partopreni la enketon.
Kia statistika kolektosistemo estas uzata en via kompanio?
-
48,0%Google Analytics12
-
4,0%Segmento 1
-
16,0%Alia (skribi en la komentoj)4
-
32,0%Efektivigis vian servon8
25 uzantoj voĉdonis. 6 uzantoj sindetenis.
fonto: www.habr.com