Şu anda dünyadaki hemen hemen her şirket, bir web kaynağındaki kullanıcı eylemlerine ilişkin istatistikler toplamaktadır. Motivasyon açık; şirketler ürünlerinin/web sitelerinin nasıl kullanıldığını bilmek ve kullanıcılarını daha iyi anlamak istiyor. Elbette piyasada bu sorunu çözmeye yönelik çok sayıda araç var; gösterge tabloları ve grafikler biçiminde veri sağlayan analitik sistemlerinden (örneğin,
Ancak henüz çözülmemiş bir sorun bulduk. Böylece doğdu
Neden kendi hizmetimizi geliştirmeliyiz?
Doksanlı yıllardı, elimizden geldiğince hayatta kaldık. 2019'da API Birinci Müşteri Veri Platformunu geliştirdik kSense, daha uygun veri analizi, bağımlılıkların belirlenmesi vb. için farklı kaynaklardan (Facebook reklamları, Stripe, Salesforce, Google play, Google Analytics vb.) veri toplamayı mümkün kıldı. Pek çok kullanıcının platformumuzu, özellikle de Google Analytics'i (bundan sonra GA olarak anılacaktır) veri analizi için kullandığını fark ettik. Bazı kullanıcılarla konuştuk ve ürünlerine ilişkin GA kullanarak aldıkları analiz verilerine ihtiyaç duyduklarını öğrendik, ancak
Web kaynaklarına bir Segment javascript pikseli yüklediler ve kullanıcılarının davranışlarına ilişkin veriler belirtilen veritabanına (örneğin Postgres) yüklendi. Ancak Segment'in bir dezavantajı da var: fiyat. Örneğin, bir web kaynağının 90,000 MTU'su (aylık izlenen kullanıcılar) varsa, o zaman kasiyere ayda ~1,000 $ ödemeniz gerekir. Ayrıca üçüncü bir sorun daha vardı; bazı tarayıcı uzantıları (AdBlock gibi) analizlerin toplanmasını engelliyordu çünkü... Tarayıcıdan gelen http istekleri GA ve Segment alanlarına gönderildi. Müşterilerimizin istekleri doğrultusunda eksiksiz veri seti toplayan (örnekleme yapmadan), ücretsiz ve kendi altyapımız üzerinde çalışabilen bir analitik hizmeti oluşturduk.
Hizmet nasıl çalışır?
Hizmet üç bölümden oluşur: bir javascript pikseli (daha sonra typescript'te yeniden yazdık), sunucu kısmı GO dilinde uygulandı ve Redshift ve BigQuery'nin şirket içi veritabanı olarak kullanılması planlandı (daha sonra destek eklendi) Postgres, ClickHouse ve Snowflake).
GA ve Segment olaylarının yapısının değiştirilmeden bırakılmasına karar verildi. Gereken tek şey, pikselin kurulu olduğu web kaynağındaki tüm olayları arka uçumuza kopyalamaktı. Görünüşe göre bunu yapmak zor değil. Javascript pikseli, orijinal GA kitaplık yöntemini yenisiyle geçersiz kıldı ve bu da olayı sistemimize kopyaladı.
//'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 pikseli ile her şey daha basit; ara yazılım yöntemleri var, biz de bunlardan birini kullandık.
//'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.');
}
Olayları kopyalamanın yanı sıra isteğe bağlı json gönderme özelliğini de ekledik:
//Отправка событий с произвольным 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'
});
Şimdi sunucu kısmından bahsedelim. Arka uç http isteklerini kabul etmeli, bunları coğrafi veriler gibi ek bilgilerle doldurmalıdır (teşekkürler)
//входящий 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"
}
Ancak diziler şu anda yalnızca dizelere dönüştürülüyor çünkü İlişkisel veritabanlarının tümü tekrarlanan alanları desteklemez. İsteğe bağlı eşleme kurallarını kullanarak alan adlarını değiştirmek veya silmek de mümkündür. Gerekirse veri şemasını değiştirmenize veya bir veri türünü diğerine dönüştürmenize olanak tanır. Örneğin, bir json alanı zaman damgasına sahip bir dize içeriyorsa (field_3_sub_field_1_sub_sub_field_1 yukarıdaki örnekten) sonra veritabanında zaman damgası tipinde bir alan oluşturmak için konfigürasyonda bir eşleme kuralı yazmanız gerekir. Yani alanın veri tipi öncelikle json değerine göre belirlenir ve ardından tip atama kuralı (eğer yapılandırılmışsa) uygulanır. 4 ana veri türü belirledik: STRING, FLOAT64, INT64 ve TIMESTAMP. Eşleme ve tür belirleme kuralları şuna benzer:
rules:
- "/field_1/subfield_1 -> " #правило удаления поля
- "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля
- "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа
Veri türünü belirlemek için algoritma:
- json yapısını düz yapıya dönüştürün
- Alanların veri tipinin değerlere göre belirlenmesi
- eşleme ve tür belirleme kurallarını uygulama
Sonra gelen json yapısından:
{
"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"
}
}
veri şeması elde edilecektir:
"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
Ayrıca kullanıcının veritabanındaki verileri başka kriterlere göre bölümleme veya bölme işlemi yapabilmesi gerektiğini düşündük ve tablo adını sabit veya bir değerle ayarlama yeteneğini uyguladık.
tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'
Ancak gelen olayların yapısı çalışma zamanında değişebilir. Mevcut bir tablonun yapısı ile gelen bir olayın yapısı arasındaki farkı kontrol etmek için bir algoritma uyguladık. Bir fark bulunursa tablo yeni alanlarla güncellenecektir. Bunu yapmak için yama SQL sorgusunu kullanın:
#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying
Mimari
Neden olayları doğrudan veritabanına yazmak yerine dosya sistemine yazmanız gerekiyor? Veritabanları çok sayıda eklemeyle uğraşırken her zaman iyi performans göstermez (
Açık Kaynak ve geleceğe yönelik planlar
Bir noktada hizmet tam teşekküllü bir ürün gibi görünmeye başladı ve biz de onu Açık Kaynak olarak yayınlamaya karar verdik. Şu anda Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake ile entegrasyonlar hayata geçirilmiştir. Tüm entegrasyonlar, veri yüklemenin hem toplu hem de akış modlarını destekler. API aracılığıyla istekler için destek eklendi.
Mevcut entegrasyon şeması şuna benzer:
Hizmet bağımsız olarak kullanılabilse de (örneğin Docker kullanarak), ayrıca
→
→
→
EventNative sorunlarınızı çözmeye yardımcı olursa seviniriz!
Ankete sadece kayıtlı kullanıcılar katılabilir.
Şirketinizde hangi istatistik toplama sistemi kullanılıyor?
-
%48,0Google Analytics12
-
%4,0Segment1
-
%16,0Başka (yorumlara yazın)4
-
%32,0Hizmetinizi uyguladı8
25 kullanıcı oy kullandı. 6 kişi çekimser kaldı.
Kaynak: habr.com