Sky 是一个用于灵活、高性能的分析行为数据的开源数据库。 包括一些点击流和日志数据,使用 Sky 分析比传统方法 比如 SQL 数据库或者是 Hadoop 速度要快几个数量级。Sky 通过优化数据的组织、更快的查询执行。在一般的硬件上每个CPU核每秒钟可处理几百万的事件。
sky 是一个用于跟踪随着时间变化的局部瞬时的哈希状态的数据库,这些哈希之所以是部分瞬态的,是因为哈希的个别属性可以将其持久化,或者只保存这些值一段世间。用这些数据结构来追踪用户行为特别有用。
举个栗子,你想知道哪些用户在用你的网站。首先,你想监测一些用户的属性,比如他们的性别,地址等等。这些属性叫做永久属性。这些属性将在第一次就被持久化,直到属性发生变化。 接下来你想记录一些关于用户动作的属性,比如访问你的主页,往购物车里添加商品,结账等等。这些属性叫瞬时属性,它们的值只会在某一时刻存在。
每一次当你更新一个或多个属性的值的时候叫做一次事件(event)。这事件将作为一个相关联的时间戳,它们都将为每一个hash组合成一个时间轴。 在sky里也可以把hash当成一个对象。因为这些事件都将为每一个用户组织成一个单一的时间轴。sky将在这些数据上查询的非常快。
sky 是由表组成的,这些表里只有对象的集合。而这些对象将遵循一个用属性限定的特设的模式。 这些属性可以被设置成永久的或者是瞬时的,而且有个数据类型与之联系。。现在支持五个数据类型string, integer, float, boolean, & factor
factor的工作方式和string差不多,除了当属性的可能值为有限个的时候(枚举?),他表现的更有效率。分类的数据比如性别,状态,活动名称的时候,它的效率很高。
The Query System
因为sky存储的是非关系数据,所以sql是没有用的。于是sky有一种简单的查询语言,由一些基本的原语组成。比如:queries, selections & conditions 。sky通过http api 用RESTful JSON架构,所以我们将用json格式展示查询出来的数据
Query: query原语是所有查询的根。他包括一系列的steps(无论是conditions还是selections)。查询引擎通过像数据库的光标顺序迭代每一个对象的每一个事件来工作。在每一个事件中,所有在query的steps都将被执行。 如果你想打破一个timelines为sessions。你可以用 sessionIdleTime
指定两个临近的事件的秒数,来勾画出一个session。
Selections:
Selections是一个简单的样本,可以来描述query引擎怎么执行的,selection可以指定一个可选的名字,可选的域,和一个或多个fields。fields将会被命名(name),而且会有一个expression,使用以下函数之一count(), sum(field), min(field), max(field).
举个栗子,查询出表中所有事件的数量
<!-- lang: sql -->
{
"steps":[
{
"type":"selection",
"fields":[
{"name":"count", "expression":"count()"}
]
}
]
}
运行会得出一下(如果有381293个事件): {"count":381293}
。。待续
多纬度查询: 更加复杂的查询包括每个不同对象的一个纬度。比如设想你想看看由性别(gender)和国家(country)来划分的事件(event)的数目。我们可以写一个selection:“mystats”
<!-- lang: python -->
{
"steps":[
{"type":"selection", "name":"myStats", "dimensions":["gender","country"], "fields":[
{"name":"count", "expression":"count()"}
]}
]
}
查出来的结果将是
<!-- lang: python -->
{
"myStats":{
"gender":{
"male":{
"country":{
"US":{
"count":19382
},
"Mexico":{
"count":10302
}
}
},
"female":{
"country":{
"US":{
"count":20183
},
"England":{
"count":3023
}
}
}
}
}
}
Conditions 基本的聚集没有什么意思,所以我们有了条件查询(conditions),条件查询就像一个迷你的查询,只有在你给的表达式的结果为true的时候才会执行。条件查询也是一种将查询系统的光标前移的方法,只需使用 within
属性。另一个非常有用的特性是条件查询可以相互嵌套。 举个栗子,输出行为(action)为结账(checkout)的行为总数。并累加所有结账的总价格
<!-- lang: python -->
{
"steps":[
{"type":"condition", "expression":"action == 'checkout'", "steps":[
{"type":"selection", "fields":[
{"name":"count", "expression":"count()"},
{"name":"total", "expression":"sum(purchaseAmount)"}
]}
]}
]
}
输出结果将是: {"count":128712, "total":2910232.23}
漏斗分析
sky查询的真正厉害的是在你联合嵌套各个原语的时候。栗子,我们将使用 within 属性,它可以指定一个范围。再这些范围的step内的condition必须为true才会执行。比如将一个within定为[0,1]意思是这个条件必须为true在当前事件(event)或者下一个事件(event)。[1,1]的意思就是条件必须是true在下一个事件(event)。 使用嵌套的条件查询时,只有父条件查询执行了,嵌套在其中的子条件查询才会有机会执行,我们就可以用联合嵌套查询来执行一个漏斗分析。继续举栗子。我们想跟踪分析那些首先访问网站主页,然后访问定价页面,最后访问登录页面的用户的人数。而且需要计算出每一步的用户人数。 我们将列出(“0”,“1”,“2”)每一步的人数,最后,我们想划分一下用户登录后首先的行动(action)是什么,所以写了最后的那个查询。
<!-- lang: python -->
{
"sessionIdleTime":7200,
"steps":[
{"type":"condition", "expression":"action == '/index.html'", "steps":[
{"type":"selection","name":"0","fields":[{"name":"count","expression":"count()"}]},
{"type":"condition", "expression":"action == '/pricing.html'", "within":[1,1], "steps":[
{"type":"selection","name":"1","fields":[{"name":"count","expression":"count()"}]},
{"type":"condition", "expression":"action == '/signup.html'", "within":[1,1], "steps":[
{"type":"selection","name":"2","fields":[{"name":"count","expression":"count()"}]},
{"type":"condition", "expression":"true", "within":[1,1], "steps":[
{"type":"selection","name":"3","dimensions":["action"],"fields":[{"name":"count","expression":"count()"}]}
]}
]}
]}
]}
]
}
查询结果的格式很好,可以清楚的知悉我们的漏斗分析结果。
<!-- lang: python -->
{
"0":{"count":10292},
"1":{"count":7382},
"2":{"count":2731},
"3":{
"/welcome.html":{"count":726},
"/contact_us.html":{"count":529},
"/index.html":{"count":128}
}
}
上面结果的意思是:
- 10,292名用户进入了首页
- 其中的7,382名用户之后通过点击进入了定价页面
- 其中的2,731名用户之后进入了登录页面。
- 最后只有726名用户真正的登录成功,进入欢迎页面。 而529名用户去了联系我们页面,128名用户返回了主页。
- 我们还可以推断出哪些没有进行下一步的用户一定是退出了网站。这意味着1,348名用户离开了网站(2731-(726+529+128)).