【问题标题】:Elasticsearch aggregation by arrays of String通过字符串数组进行 Elasticsearch 聚合
【发布时间】:2016-11-15 01:00:13
【问题描述】:

我有一个 ElasticSearch 索引,用于存储电话交易(短信、彩信、电话等)及其相关费用。

这些文档的关键是 MSISDN(MSISDN = 电话号码)。在我的应用程序中,我知道有一组用户。每个用户可以拥有一个或多个 MSISDN。

这是此类文档的映射:

"mappings" : {
      "cdr" : {
        "properties" : {
          "callDatetime" : {
            "type" : "long"
          },
          "callSource" : {
            "type" : "string"
          },
          "callType" : {
            "type" : "string"
          },
          "callZone" : {
            "type" : "string"
          },
          "calledNumber" : {
            "type" : "string"
          },
          "companyKey" : {
            "type" : "string"
          },
          "consumption" : {
            "properties" : {
              "data" : {
                "type" : "long"
              },
              "voice" : {
                "type" : "long"
              }
            }
          },
          "cost" : {
            "type" : "double"
          },
          "country" : {
            "type" : "string"
          },
          "included" : {
            "type" : "boolean"
          },
          "msisdn" : {
            "type" : "string"
          },
          "network" : {
            "type" : "string"
          }
        }
      }
    }

我的目标和问题:

我的目标是创建一个查询,按 groupcallType 检索 cost。但组在 ElasticSearch 中没有表示,仅在我的 PostgreSQL 数据库中表示。

所以我将创建一个方法来检索每个现有组的所有 MSISDN,并获得类似字符串数组的列表,其中包含每个组中的每个 MSISDN。

假设我有类似的东西:

"msisdn_by_group" : [
    {
       "group1" : ["01111111111", "02222222222", "033333333333", "044444444444"]
    },
    {
       "group2" : ["05555555555","06666666666"]
    }
]

现在,我将使用它来生成 Elasticsearch 查询。我想对不同存储桶中的所有这些术语进行聚合,即成本的总和,然后通过 callType 再次对其进行拆分。 (制作堆叠条形图)。

我尝试了几件事,但没有成功(直方图、存储桶、术语和总和主要是我正在使用的关键字)。

如果这里有人可以帮助我处理订单以及我可以用来实现此目的的关键字,那就太好了:) 谢谢

编辑: 这是我最后一次尝试: 查询:

{
    "aggs" : {
        "cost_histogram": {
            "terms": {
                "field": "callType"
            },
            "aggs": {
                "cost_histogram_sum" : {
                    "sum": {
                        "field": "cost"
                    }
                }
            }
        }
    }
}

我得到了预期的结果,但它缺少“组”拆分,因为我不知道如何将 MSISDN 数组作为标准传递:

结果:

"aggregations": {
    "cost_histogram": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "data",
          "doc_count": 5925,
          "cost_histogram_sum": {
            "value": 0
          }
        },
        {
          "key": "sms_mms",
          "doc_count": 5804,
          "cost_histogram_sum": {
            "value": 91.76999999999995
          }
        },
        {
          "key": "voice",
          "doc_count": 5299,
          "cost_histogram_sum": {
            "value": 194.1196
          }
        },
        {
          "key": "sms_mms_plus",
          "doc_count": 35,
          "cost_histogram_sum": {
            "value": 7.2976
          }
        }
      ]
    }
  }

【问题讨论】:

  • 也许显示您现在的查询并解释仍然缺少什么?
  • @Val 我当然忘了,我的错!请查看我的编辑
  • 你需要另一个 terms 聚合来包装你当前的聚合。
  • 为什么不将组 ID 也存储在您的文档中?您可以在索引时查找它,然后您的文档是独立的。
  • 在文件被导入时,我们无法知道msisdn 属于哪个组。这是在 ES 中进行导入的外部 Groovy 工作。无论如何,非常感谢您的帮助,我想添加另一个“术语” agg,但我不知道如何构建它,以便它可以按字符串数组拆分。我希望我的解释足够清楚

标签: elasticsearch aggregation


【解决方案1】:

好的,我知道如何使用一个查询来完成此操作,但这是一个该死的长查询,因为它对每个组都重复,但我别无选择。我正在使用“过滤器”聚合器。

这是一个基于我在上面的问题中写的数组的工作示例:

POST localhost:9200/cdr/_search?size=0

{
    "query": {
        "term" : {
            "companyKey" : 1
        }   
    },
    "aggs" : {
        "group_1_split_cost": {
            "filter": {
                "bool": {
                    "should": [{
                        "bool": {
                            "must": {
                                "match": {
                                    "msisdn": "01111111111"
                                }
                            }
                        }
                    },{
                        "bool": {
                            "must": {
                                "match": {
                                    "msisdn": "02222222222"
                                }
                            }
                        }
                    },{
                        "bool": {
                            "must": {
                                "match": {
                                    "msisdn": "03333333333"
                                }
                            }
                        }
                    },{
                        "bool": {
                            "must": {
                                "match": {
                                    "msisdn": "04444444444"
                                }
                            }
                        }
                    }]
                }
            },
            "aggs": {
                "cost_histogram": {
                    "terms": {
                        "field": "callType"
                    },
                    "aggs": {
                        "cost_histogram_sum" : {
                            "sum": {
                                "field": "cost"
                            }
                        }
                    }
                }
            }
        },
        "group_2_split_cost": {
            "filter": {
                "bool": {
                    "should": [{
                        "bool": {
                            "must": {
                                "match": {
                                    "msisdn": "05555555555"
                                }
                            }
                        }
                    },{
                        "bool": {
                            "must": {
                                "match": {
                                    "msisdn": "06666666666"
                                }
                            }
                        }
                    }]
                }
            },
            "aggs": {
                "cost_histogram": {
                    "terms": {
                        "field": "callType"
                    },
                    "aggs": {
                        "cost_histogram_sum" : {
                            "sum": {
                                "field": "cost"
                            }
                        }
                    }
                }
            }
        }
    }
}

感谢 Elasticsearch 的较新版本,我们现在可以嵌套非常深的聚合,但是我们不能将值数组传递给“OR”运算符或类似的东西仍然有点太糟糕了。我猜它可以减少这些查询的大小。即使它们有点特殊并且在小众情况下使用,就像我的一样。

【讨论】:

  • 您有没有找到更好的方法?如果值是动态的呢?
  • 您可以将 misdn 字段中的 should 更改为术语查询,例如 terms: {"msisdn": [<comma separated values>]}
猜你喜欢
  • 2016-02-17
  • 2020-07-21
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
相关资源
最近更新 更多