有一种方法可以在单个查询中实现您想要的结果,但由于它涉及脚本,并且性能可能会受到影响,具体取决于您将运行此查询的数据量。
我们的想法是利用 scripted_metric
aggregation 在整个文档集上构建您自己的聚合逻辑。
我们下面要做的很简单:
- 我们不提供任何查询,因此我们考虑完整的文档集
-
映射阶段:我们构建所有 IP 的映射,并为每个
- 我们计算总点击次数
- 如果它今天命中并且具有给定的状态(与您在查询中所做的相同),我们会对其进行标记
-
减少阶段:我们返回标记为今天有点击的每个 IP 的总点击数
查询如下所示:
POST my-index/_search
{
"size": 0,"aggs": {
"all_time_hits": {
"scripted_metric": {
"init_script": "state.ips = [:]","map_script": """
// initialize total hits count for each IP and increment
def ip = doc['ip.keyword'].value;
if (state.ips[ip] == null) {
state.ips[ip] = [
'total_hits': 0,'hits_today': false
]
}
state.ips[ip].total_hits++;
// flag IP if:
// 1. it has hits today
// 2. the hit had one of the given statuses
def today = Instant.ofEpochMilli(new Date().getTime()).truncatedTo(ChronoUnit.DAYS);
def hitDate = doc['timestamp'].value.toInstant().truncatedTo(ChronoUnit.DAYS);
def hitToday = today.equals(hitDate);
def statusOk = params.statuses.indexOf((int) doc['status'].value) >= 0;
state.ips[ip].hits_today = state.ips[ip].hits_today || (hitToday && statusOk);
""","combine_script": "return state.ips;","reduce_script": """
def ips = [:];
for (state in states) {
for (ip in state.keySet()) {
// only consider IPs that had hits today
if (state[ip].hits_today) {
if (ips[ip] == null) {
ips[ip] = 0;
}
ips[ip] += state[ip].total_hits;
}
}
}
return ips;
""","params": {
"statuses": [200,404]
}
}
}
}
}
答案如下:
"aggregations" : {
"all_time_hits" : {
"value" : {
"123.123.123.125" : 1,"123.123.123.123" : 4
}
}
}
我认为这几乎符合您的预期。
另一个选项(性能更高,因为没有脚本)需要您进行两次查询。首先,具有日期范围和状态检查的查询使用 terms
聚合来检索今天命中的所有 IP(就像您现在所做的那样),然后是第二个查询,您在这些 IP 上进行过滤(使用 {{ 1}} 查询)对整个索引(无日期范围或状态检查)并使用 terms
聚合获取每个索引的命中计数。
,
在您共享的示例中,您有一个查询,并且您的文档会根据该查询进行过滤。但是您希望您的聚合处理所有文档,而不管查询如何。
这就是 global
选项存在的原因。
此上下文由您搜索的索引和文档类型定义,但不受搜索查询本身的影响。
示例查询示例:
{
"query": {
"match": { "type": "t-shirt" }
},"aggs": {
"all_products": {
"global": {},"aggs": {
"avg_price": { "avg": { "field": "price" } }
}
}
}
}
本文链接:https://www.f2er.com/24457.html