我有用户和我的用户有活动。每个事件都作为事件的类型和日期发生。
例如
{
id: 1,
name: john,
events: [{
type: 'logged_in'
date: "01/01/2016
},{
type: 'logged_in'
date: "02/01/2016
}{
type: 'added_email'
date: "02/05/2016
}]
}
现在的问题是,我希望能够在特定时间范围内查询已完成特定事件N次的用户
例如:哪些用户在1月1日16日到1月20日之间登录了两次以上
我知道我可以使用聚合,但查询变得复杂,性能下降了数百万个事件。
我想知道是否有更好的方法来索引/查询这些数据?
答案 0 :(得分:1)
表示此数据的显而易见的方法是使用嵌套映射:
"id": {"type": "integer"},
"name": {"type": "keyword"},
"events": {
"type": "nested",
"properties": {
"type": {"type": "keyword"},
"date": {"type": "date"}
}
我认为当你提到性能问题时,这就是你所说的(嵌套查询和聚合很慢)。对于您正在谈论的那种分析,我不认为您可以避免使用聚合,但我会'#34;扁平化"要避免使用嵌套字段[1]的数据,而是每个记录一个文档,如下所示:
"id": {"type": "integer"},
"name": {"type": "keyword"},
"event_type": {"type": "keyword"},
"date": {"type": "date"}
然后进行如下聚合:
{
"query": {"bool": {
"filter": [
{"match": {"event_type": "logged_in"}},
{"range": {"date": {"gte": "2016-01-01", "lt": "2017-01-20"}}}
}
"aggs": {
"terms": {
"field": "name",
"size": 50
}
}
您还可以在索引中汇总一些数据,以防您知道自己永远不需要更细粒度的分析。例如:
"name": {"type": "keyword"},
"event_type": {"type": "keyword"},
"event_count": {"type": "integer"},
"date_bucket": {"type": "date"}
其中date_bucket
代表日期存储桶的开头(如果你只关心整整几个月,那么1月的每个事件都会进入" 2017-01-01")的记录。您可以使用脚本更新时使用upsert来更新event_count(如果已存在),或者创建新文档(如果它不存在)。然后,您可以在event_count
聚合内使用terms
上的和聚合。如果您事先知道自己关心的粒度,那么这才有意义。
[1]如果您还需要以不同的方式访问数据,您可以考虑索引到两个索引,例如两个"视图"关于数据。基本上除非你拥有无限的资源或小数据集,或者你并不关心性能,否则你应该努力避免使用嵌套字段。