目前,世界上几乎每家公司都会收集有关网络资源上的用户操作的统计数据。 动机很明确——公司想知道他们的产品/网站是如何使用的,并更好地了解他们的用户。 当然,市场上有大量工具可以解决这个问题 - 来自以仪表板和图表形式提供数据的分析系统(例如,
但我们发现一个问题还没有解决。 就这样诞生了
我们为什么要开发自己的服务?
那是九十年代,我们尽力生存。 2019年,我们开发了第一个客户数据平台API 科感,它允许聚合来自不同来源(Facebook 广告、Stripe、Salesforce、Google play、Google Analytics 等)的数据,以便更方便地进行数据分析、识别依赖关系等。 我们注意到许多用户使用我们的数据分析平台,特别是Google Analytics(以下简称GA)。 我们与一些用户交谈,发现他们需要使用 GA 接收的产品分析数据,但是
他们在其 Web 资源上安装了 Segment javascript 像素,并将用户行为数据加载到指定的数据库(例如 Postgres)中。 但 Segment 也有其缺点——价格。 例如,如果某个 Web 资源有 90,000 MTU(每月跟踪用户),那么您每月需要向收银员支付约 1,000 美元。 还有第三个问题 - 某些浏览器扩展(例如 AdBlock)阻止了分析收集。 来自浏览器的 http 请求被发送到 GA 和 Segment 域。 根据客户的愿望,我们创建了一项分析服务,可以免费收集全套数据(无需采样),并且可以在我们自己的基础设施上运行。
服务如何运作
该服务由三部分组成:JavaScript Pixel(我们后来将其重写为 TypeScript)、用 GO 语言实现的服务器部分,并计划使用 Redshift 和 BigQuery 作为内部数据库(后来他们添加了对 Postgres 的支持) 、ClickHouse 和 Snowflake)。
事件 GA 和 Segment 的结构决定保持不变。 所需要做的就是将安装像素的网络资源中的所有事件复制到我们的后端。 事实证明,这很容易做到。 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 字段包含带有时间戳的字符串 (field_3_sub_field_1_sub_sub_field_1 从上面的例子),那么为了在数据库中创建时间戳类型的字段,需要在配置中编写映射规则。 换句话说,字段的数据类型首先由 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
建筑
为什么需要将事件写入文件系统,而不是直接写入数据库? 数据库并不总是在大量插入时表现出高性能(
开源和未来计划
在某种程度上,该服务变得像一个成熟的产品,我们决定将其开源。 目前,与 Postgres、ClickHouse、BigQuery、Redshift、S3、Snowflake 的集成已经实现。 所有集成都支持批处理和流数据加载模式。 添加了对通过 API 请求的支持。
当前的集成方案如下所示:
虽然服务可以独立使用(例如使用Docker),但我们也有
→
→
→
如果 EventNative 能够帮助您解决问题,我们将非常高兴!
只有注册用户才能参与调查。
贵公司使用什么统计系统
-
48,0%Google Analytics12
-
4,0%段 1
-
16,0%其他(写在评论里) 4
-
32,0%实施您的服务8
25 位用户投票。 6 名用户弃权。
来源: habr.com