如何解决具有期限和日期范围的汇总
我是ElasticSearch的新手,我正在尝试进行汇总,但似乎无法正确处理。
我在ElasticSearch索引中有一些数据,如下所示:
{
"customerId": "example_customer","request": {
"referer": "https://example.org",}
"@timestamp": "2020-09-29T14:14:00.000Z"
}
我的映射:
{
"mappings": {
"properties": {
"customerId": { "type": "keyword" },"request": {
"properties": {
"referer": { "type": "keyword" }
}
}
}
}
}
我正在尝试获取在日期范围内特定客户出现频率最高的引荐来源。我可以像这样为客户制作过滤器:
var result = await _client.SearchAsync<InsightRecord>(s =>
s.Aggregations(
a => a
.Filter("customer",customer =>
customer.Filter(q => q.Term(ir => ir.CustomerId,customerId)))
.Terms("top_referer",ts => ts.Field("request.referer"))
)
);
return result.Aggregations.Terms("top_referer").Buckets
.Select(bucket => new TopReferer { Url = bucket.Key,Count = bucket.DocCount ?? 0})
现在,我想将此范围缩小到特定时间范围。这是我到目前为止所拥有的:
var searchDescriptor = s.Aggregations(a =>
a.Filter("customer",customer =>
customer.Filter(q =>
q.Bool(b =>
b.Must(
f2 => f2.Daterange(date => date.GreaterThanorEquals(from).LessthanorEquals(to)),f1 => f1.Term(ir => ir.CustomerId,customerId)
)
)
)
)
.Terms("top_referers",ts => ts.Field("request.referer"))
);
问题在于日期过滤器未包含在查询中,而是转换为以下JSON:
{
"aggs": {
"customer": {
"filter": {
"bool": {
"filter": [{
"term": {
"customerId": {
"value": "example_customer"
}
}
}
]
}
}
},"top_referers": {
"terms": {
"field": "request.referer"
}
}
}
}
我尝试以不同的顺序订购它们,但没有帮助。始终会在JSON中显示的客户过滤条件会被跳过,日期范围也会被跳过。我还看到有些人将查询与聚合结合使用,但是我觉得我应该能够单独使用聚合来完成此任务。这可能吗?我的查询在做什么,该范围没有显示在JSON中是什么错误?
解决方法
问题在于日期range
查询未指定字段
f2 => f2.DateRange(date => date.GreaterThanOrEquals(from).LessThanOrEquals(to)),
为此查询添加字段
f2 => f2.DateRange(date => date
.Field("@timestamp")
.GreaterThanOrEquals(from)
.LessThanOrEquals(to)
),
此外,要使过滤器聚合应用于术语聚合,术语聚合必须是过滤器聚合的 sub 聚合。就像
var customerId = "foo";
var from = "now-365d";
var to = "now";
var result = await _client.SearchAsync<InsightRecord>(s => s
.Aggregations(a => a
.Filter("customer",customer => customer
.Filter(q => q
.Bool(b => b
.Must(
f2 => f2.DateRange(date => date
.Field("@timestamp")
.GreaterThanOrEquals(from)
.LessThanOrEquals(to)
),f1 => f1.Term(ir => ir.CustomerId,customerId)
)
)
)
.Aggregations(aa => aa
.Terms("top_referers",ts => ts.Field("request.referer"))
)
)
)
);
尽管不是使用过滤器聚合指定日期范围和术语查询,我倾向于将它们指定为搜索请求的查询。计算聚合时会考虑该查询。当您要查询数据集但仅在数据集的子集上运行聚合时,过滤器聚合非常有用。如果您要搜索所有个客户,但只想对一部分客户运行汇总。在实践中,对于此特定示例,无论将查询指定为搜索请求的查询部分,还是将其作为术语 sub 聚合的过滤器聚合,其结果都应相同,但是前者可能更容易获得结果。
指定为查询类似
var result = await _client.Search<InsightRecord>(s => s
.Query(q => q
.Bool(b => b
.Must(
f2 => f2.DateRange(date => date
.Field("@timestamp")
.GreaterThanOrEquals(from)
.LessThanOrEquals(to)
),customerId)
)
)
)
.Aggregations(aa => aa
.Terms("top_referers",ts => ts.Field("request.referer"))
)
);
此外,我们还可以做其他几件事
- 由于我们只对术语聚合的结果感兴趣,而对搜索结果不感兴趣,因此我们可以指定
.Size(0)
,以免打扰在响应中返回搜索结果。 - combining queries with operator overloading可以更简洁地表示
bool
查询,并且由于两个查询都是谓词(文档与查询匹配或不匹配),我们可以在filter子句中指定两者省略得分。然后,最终查询就像
var result = await _client.SearchAsync<InsightRecord>(s => s
.Size(0)
.Query(q => +q
.DateRange(date => date
.Field("@timestamp")
.GreaterThanOrEquals(from)
.LessThanOrEquals(to)
) && +q
.Term(ir => ir.CustomerId,customerId)
)
.Aggregations(aa => aa
.Terms("top_referers",ts => ts.Field("request.referer"))
)
);
生成查询
{
"aggs": {
"top_referers": {
"terms": {
"field": "request.referer"
}
}
},"query": {
"bool": {
"filter": [{
"range": {
"@timestamp": {
"gte": "now-365d","lte": "now"
}
}
},{
"term": {
"customerId": {
"value": "foo"
}
}
}]
}
},"size": 0
}
可以按照您的问题中的说明来访问术语聚合桶。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。