我正在努力整理一个查询,需要一些帮助。文档很简单,只是记录了用户的登录时间
{
"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"}
提前致谢。
最佳答案
首先,提前抱歉。这将是一个很长的答案。
使用 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”(空值,我们可以称之为“-无限”)<=时间戳<“TO”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
这是因为您将所有时间戳存储在一个索引中,并且它将在您的所有文档上运行。我假设您只想玩最后一个时间戳。您可以执行以下操作之一:
- 使用桶路径。
我正在考虑对时间戳字段进行最大聚合,为其创建一个bucket_path,并在该bucket_path上运行date_range聚合。这可能是背部疼痛。如果您有问题,请为此创建另一个问题。
- 将“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 #或者您想要的值,例如“no”
。在其他情况下 "is_active": 1 #或者您想要的值,例如 'yes'
2b。在 Logstash 中运行一个脚本来解析信息。这将要求您:
- 使用 Ruby 脚本
- 通过后端的套接字发送信息
希望这对您有帮助! :D
关于Elasticsearch 日期聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57573293/