我有一个包含“命中”文档的elasticsearch索引(包括ip/timestamp/uri等字段),这些文档是从我的nginx访问日志中填充的。
我正在寻找一种方法来获取总数量的hits / ip -但是对于一个ip的子集,也就是那些今天进行请求的ip。
我知道我可以通过以下操作进行过滤聚合:
/search?size=0
{
'query': { 'bool': { 'must': [
{'range': { 'timestamp': { 'gte': $today}}},
{'query_string': {'query': 'status:200 OR status:404'}},
]}},
'aggregations': {'c': {'terms': {'field': 'ip', 'size': 99999}}}
}但是这只会把今天完成的点击量加起来,我想要索引中的总数,但是只有今天有点击量的IP。这个是可能的吗?
-编辑-
我尝试过全局选项,但是
'aggregations': {'c': {'global': {}, 'aggs': {'c2': {'terms': {'field': 'remote_user', 'size': 99999}}}}}返回来自所有IP;它忽略了我在时间戳上的过滤器(例如。其中包括几天前命中的IP)
发布于 2021-07-30 09:38:12
有一种方法可以在单个查询中实现您想要的结果,但是由于它涉及脚本编写,而且性能可能会受到影响,这取决于运行此查询的数据量。
其思想是利用聚合,以便在整个文档集上构建自己的聚合逻辑。
我们下面所做的非常简单:
下面是查询的样子:
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进行筛选(使用terms查询),并使用terms聚合对每个IP进行点击计数。
发布于 2021-07-28 08:23:25
在您已经共享的示例中,您有一个查询,并且您的文档会根据这个查询进行过滤。但是,您希望您的聚合能够接受所有文档,而不管查询是什么。
这就是为什么存在global选项。
此上下文由索引和正在搜索的文档类型定义,但不受搜索查询本身的影响。
示例查询示例:
{
"query": {
"match": { "type": "t-shirt" }
},
"aggs": {
"all_products": {
"global": {},
"aggs": {
"avg_price": { "avg": { "field": "price" } }
}
}
}
}https://stackoverflow.com/questions/68556524
复制相似问题