Šiuo metu beveik kiekviena pasaulio įmonė renka statistiką apie vartotojų veiksmus žiniatinklio šaltinyje. Motyvacija aiški – įmonės nori žinoti, kaip naudojamas jų produktas/svetainė ir geriau suprasti savo vartotojus. Žinoma, rinkoje yra daug įrankių šiai problemai išspręsti – iš analizės sistemų, kurios teikia duomenis prietaisų skydelių ir grafikų pavidalu (pvz.
Tačiau radome problemą, kuri dar nebuvo išspręsta. Taip gimė
Kodėl turėtume kurti savo paslaugą?
Buvo 2019 dešimtmetis, išgyvenome kaip galėjome. XNUMX m. sukūrėme API First Customer Data Platform kSense, kuri leido apibendrinti duomenis iš skirtingų šaltinių (Facebook reklamų, Stripe, Salesforce, Google play, Google Analytics ir kt.), kad būtų galima patogiau analizuoti duomenis, nustatyti priklausomybes ir pan. Pastebėjome, kad daugelis vartotojų naudoja mūsų platformą duomenų analizei, būtent Google Analytics (toliau GA). Kalbėjomės su kai kuriais naudotojais ir išsiaiškinome, kad jiems reikia produkto analizės duomenų, kuriuos jie gauna naudodami GA, bet
Jie įdiegė Segment JavaScript pikselį savo žiniatinklio šaltinyje ir duomenys apie jų vartotojų elgesį buvo įkelti į nurodytą duomenų bazę (pvz., Postgres). Tačiau Segmentas turi ir minusą – kainą. Pavyzdžiui, jei žiniatinklio resursas turi 90,000 1,000 MTU (mėnesio stebimi vartotojai), tuomet kasininkui reikia mokėti ~XNUMX XNUMX USD per mėnesį. Iškilo ir trečia problema – kai kurie naršyklės plėtiniai (pvz., AdBlock) blokavo analizės rinkimą, nes... http užklausos iš naršyklės buvo išsiųstos į GA ir Segment domenus. Atsižvelgdami į klientų pageidavimus, sukūrėme analitikos paslaugą, kuri renka visą duomenų rinkinį (be atrankos), yra nemokama ir gali dirbti savo infrastruktūroje.
Kaip paslauga veikia
Paslauga susideda iš trijų dalių: javascript pikselio (kurį vėliau perrašėme mašinraščiu), serverio dalis yra įdiegta GO kalba, taip pat buvo numatyta naudoti Redshift ir BigQuery kaip vidinę duomenų bazę (vėliau jie papildė palaikymą Postgres, ClickHouse ir Snowflake).
Buvo nuspręsta GA ir Segmento įvykių struktūrą palikti nepakeistą. Viskas, ko reikėjo, buvo dubliuoti visus įvykius iš žiniatinklio šaltinio, kuriame yra įdiegtas pikselis, į mūsų užpakalinę programą. Kaip paaiškėjo, tai padaryti nėra sunku. „Javascript“ pikselis pakeitė pradinį GA bibliotekos metodą nauju, kuris dubliavo įvykį mūsų sistemoje.
//'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);
});
});
}
Su Segment pikseliu viskas yra paprasčiau, jame yra tarpinės programinės įrangos metodų, iš kurių vieną naudojome.
//'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.');
}
Be įvykių kopijavimo, pridėjome galimybę siųsti savavališką 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'
});
Toliau pakalbėkime apie serverio dalį. Užpakalinė programa turėtų priimti http užklausas, užpildyti jas papildoma informacija, pavyzdžiui, geografiniais duomenimis (ačiū
//входящий 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"
}
Tačiau masyvai šiuo metu tiesiog konvertuojami į eilutes, nes Ne visos reliacinės duomenų bazės palaiko pasikartojančius laukus. Taip pat galima keisti laukų pavadinimus arba juos ištrinti naudojant pasirenkamas susiejimo taisykles. Jie leidžia keisti duomenų schemą, jei reikia, arba konvertuoti vieną duomenų tipą į kitą. Pavyzdžiui, jei json lauke yra eilutė su laiko žyma (field_3_sub_field_1_sub_sub_field_1 iš aukščiau pateikto pavyzdžio), tada norėdami duomenų bazėje sukurti lauką su laiko žymos tipu, konfigūracijoje turite parašyti susiejimo taisyklę. Kitaip tariant, lauko duomenų tipas pirmiausia nustatomas pagal json reikšmę, o tada taikoma tipo perdavimo taisyklė (jei sukonfigūruota). Mes nustatėme 4 pagrindinius duomenų tipus: STRING, FLOAT64, INT64 ir TIMESTAMP. Susiejimo ir tipo liejimo taisyklės atrodo taip:
rules:
- "/field_1/subfield_1 -> " #правило удаления поля
- "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля
- "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа
Duomenų tipo nustatymo algoritmas:
- konvertuoti json struktūrą į plokščią struktūrą
- pagal reikšmes nustatant laukų duomenų tipą
- taikant kartografavimo ir tipo liejimo taisykles
Tada iš gaunamos json struktūros:
{
"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"
}
}
bus gauta duomenų schema:
"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
Taip pat pagalvojome, kad vartotojas turi turėti galimybę sukonfigūruoti skaidymą arba dalyti duomenis duomenų bazėje pagal kitus kriterijus ir įdiegėme galimybę lentelės pavadinimą nustatyti su konstanta arba
tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'
Tačiau gaunamų įvykių struktūra gali pasikeisti vykdymo metu. Įdiegėme algoritmą, skirtą patikrinti esamos lentelės ir gaunamo įvykio struktūros skirtumą. Jei randamas skirtumas, lentelė bus atnaujinta naujais laukais. Norėdami tai padaryti, naudokite pataisos SQL užklausą:
#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying
Architektūra
Kodėl įvykius reikia įrašyti į failų sistemą, o ne tiesiog rašyti į duomenų bazę? Duomenų bazės ne visada gerai veikia, kai dirbama su daugybe įterpimų (
Atvirasis šaltinis ir ateities planai
Tam tikru momentu paslauga pradėjo atrodyti kaip visavertis produktas, ir mes nusprendėme ją išleisti į atvirąjį kodą. Šiuo metu įdiegtos integracijos su Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. Visos integracijos palaiko tiek paketinio, tiek srautinio duomenų įkėlimo režimus. Pridėtas užklausų per API palaikymas.
Dabartinė integravimo schema atrodo taip:
Nors paslauga gali būti naudojama savarankiškai (pavyzdžiui, naudojant Docker), mes taip pat turime
Mes džiaugsimės, jei EventNative padės išspręsti jūsų problemas!
Apklausoje gali dalyvauti tik registruoti vartotojai.
Kokia statistikos rinkimo sistema naudojama jūsų įmonėje?
-
48,0%Google Analytics 12
-
4,0%1 segmentas
-
16,0%Kitas (rašyk komentaruose)4
-
32,0%Įgyvendino jūsų paslaugą8
Balsavo 25 vartotojų. 6 vartotojai susilaikė.
Šaltinis: www.habr.com