Elasticsearch日期汇总

时间:2019-08-20 12:07:08

标签: elasticsearch

我正在努力整理一个查询,可能需要一些帮助。这些文件非常简单,仅记录用户的登录时间

{
"timestamp":"2019-01-01 13:14:15",
"username":"theuser"
}

我希望使用以下规则基于今天(例如10天前)的偏移量进行计数。

  • 最近一次登录是在10天之前的任何用户都被视为“无效用户”
  • 任何在10天前首次登录的用户都被视为“新用户”
  • 其他任何人都被视为“活动用户”。

我可以使用此功能获得每个用户的首次和最新登录信息(我发现也可以通过top_hits聚合来完成此操作)

GET mytest/_search?filter_path=**.buckets
{
    "aggs" : {
        "username_grouping" : {
            "terms" : {
                "field" : "username"
            },
            "aggs" : {
                "first_login" : {
                    "min": { "field" : "timestamp" }
                },
                "latest_login" : {
                    "max": { "field" : "timestamp" }
                }
            }
        }
    }
}

我当时想将其用作日期范围汇总的来源,但无法正常工作。

是否可以在一个查询中,如果不能,则可以在单独的查询中计算“非活动用户”和“新用户”的数量?

以下是一些示例数据,假设今天是2019年8月20日,且偏移量为10天,则每种类型的用户的计数都为1

PUT _template/mytest-index-template
{
  "index_patterns": [ "mytest" ],
  "mappings": {
    "properties": {
      "timestamp": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" },
      "username": { "type": "keyword" }
    }
  }
}

POST /mytest/_bulk
{"index":{}}
{"timestamp":"2019-01-01 13:14:15","username":"olduser"}
{"index":{}}
{"timestamp":"2019-01-20 18:55:05","username":"olduser"}
{"index":{}}
{"timestamp":"2019-01-31 09:33:19","username":"olduser"}
{"index":{}}
{"timestamp":"2019-08-16 08:02:43","username":"newuser"}
{"index":{}}
{"timestamp":"2019-08-18 07:31:34","username":"newuser"}
{"index":{}}
{"timestamp":"2019-03-01 09:02:54","username":"activeuser"}
{"index":{}}
{"timestamp":"2019-08-14 07:34:22","username":"activeuser"}
{"index":{}}
{"timestamp":"2019-08-19 06:09:08","username":"activeuser"}

谢谢。

2 个答案:

答案 0 :(得分:2)

首先,对不起。这将是一个很长的答案。

如何使用Date Range Aggregation

您可以将“ from”和“ to”设置为特定字段并“标记”它们。这将帮助您确定谁是老用户和新用户。

我可以这样思考:

{
"aggs": {
    "range": {
        "date_range": {
            "field": "timestamp",
            "ranges": [
                { "to": "now-10/d", "key": "old_user" }, #If they have more than 10 days inactive.
                { "from": "now-10d/d", "to": "now/d", "key": "active_user" } #Ig they have at least logged in in the last 10 days.
            ],
            "keyed": true
        }
    }
}

第一个对象可以理解为:“所有带有'timestamp'字段且相差10天或更多天的文档都将是old_users”。在数学中表示为:

“ from”(空值,可以称为'-infinite')<=时间戳<10天前的

第二个对象可以理解为:“所有带有'timestamp'字段且相差10天或更短时间的文档都将是active_users。在数学中表示为:

“ FROM”是10天前的<=时间戳<现在是“ TO”

好的,我们已经弄清楚了如何“标记”您的用户。但是,如果您像这样运行查询,您将在结果中找到类似的内容:

user1: old_user
user1: old_user
user1: active_user
user2: old_user
user2: old_user
user2: active_user
user2: old_user
user3: old_user
user3: active_user

这是因为所有时间戳都存储在一个索引中,并且可以在所有文档上运行。我假设您只想播放最后一个时间戳。您可以执行以下操作之一:

  1. 玩铲斗路径。

我正在考虑在时间戳字段上进行最大聚合,为它创建一个bucket_path,并在该bucket_path上运行date_range聚合。这可能是背部疼痛。如果您有问题,请为此提出另一个问题。

  1. 将字段“ is_active”添加到您的文档中。您可以通过两种方式做到这一点:

2a。每次用户登录时,请在您的后端代码中添加一个脚本来进行比较。像这样:

#You get the user_value from your back-end code
{
    "query":{
        "match": {
            "username": user_value
        }
    },
    "_source": "timestamp" #This will only bring the field timestamp
    "size": 1 #This will only bring back one doc
    "sort":[
        { "timestamp" : {"order" : "desc"}} #This will sort the timestamsps descending
    ]
}

在后端获取结果。如果您获得的时间戳记早于10天,请在即将成为索引的文档中添加值"is_active": 0 #Or a value you want like 'no'。在其他情况下,"is_active": 1 #Or a value you want like 'yes'

2b。在logstash中运行脚本以解析信息。这将要求您:

  • 玩Ruby脚本
  • 通过套接字从后端发送信息

希望这会有所帮助! :D

答案 1 :(得分:1)

感谢凯文,我想我有一个可行的解决方案。无需使用最大日期和最小日期,只需获取登录计数并使用基数汇总即可获得用户数量。我想要的最终数字只是查询返回的三个值的差异。

GET mytest/_search?filter_path=aggregations.username_groups.buckets.key,aggregations.username_groups.buckets.username_counts.value,aggregations.active_and_inactive_and_new.value
{
  "size": 0,
  "aggs": {
    "active_and_inactive_and_new": {
      "cardinality": {
        "field": "username"
      }
    },
    "username_groups": {
      "range": {
        "field": "timestamp",
        "ranges": [
          {
            "to": "now-10d/d",
            "key": "active_and_inactive"
          },
          {
            "from": "now-10d/d",
            "key": "active_and_new"
          }
        ]
      },
      "aggs": {
        "username_counts": {
          "cardinality": {
            "field": "username"
          }
        }
      }
    }
  }
}