多列主要/分组依据?

时间:2019-05-19 15:54:28

标签: elasticsearch

在弹性中,我试图计算字段值的组合。

在SQL中,这就像

从tbl GROUP BY a,b中选择a,b,COUNT(a)

(我的数据是Apache日志,我正在计算以下内容的组合 client_ip + method + response_code)

示例数据

a,b,c,d

a,b,c,d

a,b,c,e

预期产量

a,b,c,d = 2

a,b,c,e = 1

字段均为文本 匹配应准确无误 输出需要显示组合和计数 我不想在文本字段上启用字段数据,因为我的代码将是开源的,所以我希望对开箱即用的弹性进行最小的更改以模仿用户

用了几个小时的阅读时间并且不是一个明智的选择,每个例子与此都大不相同。

任何帮助表示赞赏!

我一直在看:

基数,多基数 Aggs,群组,字段与关键字

1 个答案:

答案 0 :(得分:1)

下面是的三种方法(主要是两种,尽管我已经提到了三种,但前两种是相似的)来实现这一目的:

解决方案1:使用Elasticsearch DSL

我已经提到了示例映射,示例文档,示例聚集查询和响应:

映射:

请注意,我已经以multi-field格式创建了所有字段。这意味着对于text类型的每个字段,例如client_ip,您拥有其兄弟字段client_ip.keyword,其类型为keyword。它在此字段下面,聚合查询将起作用。

除非您将fielddata设置为enabled,否则无法在Text类型上运行聚合查询。我不建议这样做,如果您必须做到这一点,则最好利用多字段,如下所述。

PUT myipindex
{
  "mappings": {
    "mydocs": {
      "properties":{
        "client_ip": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "method": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "response_code":{
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

示例文档:

POST myipindex/mydocs/1
{
  "client_ip": "10.10.10.10",
  "method": "GET",
  "response_code": "200"
}

POST myipindex/mydocs/2
{
  "client_ip": "10.10.10.10",
  "method": "GET",
  "response_code": "200"
}

POST myipindex/mydocs/3
{
  "client_ip": "10.10.10.11",
  "method": "GET",
  "response_code": "200"
}

POST myipindex/mydocs/4
{
  "client_ip": "10.10.10.11",
  "method": "POST",
  "response_code": "200"
}

汇总查询:

我只是在下面的树/子聚合形式中创建了3个Terms Aggregation,以帮助您理解:

Terms Aggregation for client_ip
- Terms Aggregation for method
 - Terms Aggregation for response_code

以下是实际查询:

POST myipindex/_search
{
  "size": 0,
  "aggs":{
    "my_ip":{
      "terms": {
        "field": "client_ip.keyword",
        "size": 10,
        "min_doc_count": 1
      },
      "aggs": {
        "my_method": {
          "terms": {
            "field": "method.keyword",
            "size": 10,
            "min_doc_count": 1
          },
          "aggs": {
            "my_response_code": {
              "terms": {
                "field": "response_code.keyword",
                "size": 10,
                "min_doc_count": 1
              }
            }
          }
        }
      }
    }
  }
}

聚集响应:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "my_ip" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "10.10.10.10",
          "doc_count" : 2,
          "my_method" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "GET",
                "doc_count" : 2,
                "my_response_code" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : "200",
                      "doc_count" : 2
                    }
                  ]
                }
              }
            ]
          }
        },
        {
          "key" : "10.10.10.11",
          "doc_count" : 2,
          "my_method" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "GET",
                "doc_count" : 1,
                "my_response_code" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : "200",
                      "doc_count" : 1
                    }
                  ]
                }
              },
              {
                "key" : "POST",
                "doc_count" : 1,
                "my_response_code" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : "200",
                      "doc_count" : 1
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

解决方案2:通过无痛脚本使用Elasticsearch DSL

此解决方案与解决方案1类似,在该解决方案中,我仍在使用术语汇总,但为此我编写了一个自定义脚本。

由于输出格式的原因,您可能想优先于解决方案1。

汇总查询:

POST myipindex/_search
{
  "size": 0,
  "aggs": {
    "myagg": {
      "terms": {
        "script": {
          "source": """
            return doc['client_ip.keyword'].value + ", " + doc ['method.keyword'].value + ", " + doc['response_code.keyword'].value;
          """,
          "lang": "painless"
        }
      }
    }
  }
}

聚集响应:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "myagg" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "10.10.10.10, GET, 200",
          "doc_count" : 2
        },
        {
          "key" : "10.10.10.11, GET, 200",
          "doc_count" : 1
        },
        {
          "key" : "10.10.10.11, POST, 200",
          "doc_count" : 1
        }
      ]
    }
  }
}

解决方案3:如果您有Elasticsearch xpack,请使用SQL Access

如果您有权使用xpack的SQL Access功能,则只需执行以下查询:

POST /_xpack/sql?format=txt
{
  "query": "SELECT client_ip, method, response_code, count(*) FROM myipindex GROUP BY client_ip, method, response_code"

}

回复:

   client_ip   |    method     | response_code |   COUNT(1)    
---------------+---------------+---------------+---------------
10.10.10.10    |GET            |200            |2              
10.10.10.11    |GET            |200            |1              
10.10.10.11    |POST           |200            |1              

让我知道这是否有帮助!