在ElasticSearch上索引聚合数据的最佳方法是什么?

时间:2017-08-24 13:37:10

标签: elasticsearch

我有用户和我的用户有活动。每个事件都作为事件的类型和日期发生。

例如

{
  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日之间登录了两次以上

我知道我可以使用聚合,但查询变得复杂,性能下降了数百万个事件。

我想知道是否有更好的方法来索引/查询这些数据?

1 个答案:

答案 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]如果您还需要以不同的方式访问数据,您可以考虑索引到两个索引,例如两个"视图"关于数据。基本上除非你拥有无限的资源或小数据集,或者你并不关心性能,否则你应该努力避免使用嵌套字段。