弹性搜索:仅汇总特定的嵌套文档

时间:2018-05-26 11:01:27

标签: elasticsearch aggregation

我想聚合满足给定查询的特定嵌套文档。

让我通过一个例子解释一下。我在索引中插入了两条记录:

第一份文件是,

    {
      "project": [
        {
          "subject": "maths",
          "marks": 47
        },
        {
          "subject": "computers",
          "marks": 22
        }
      ]
    }

第二个文件是,

    {
      "project": [
        {
          "subject": "maths",
          "marks": 65
        },
        {
          "subject": "networks",
          "marks": 72
        }
      ]
    }

其中包含主题以及每条记录中的标记。从那些文件中,我需要从给定的文件中单独得到maths个主题。

我试过的查询是:

    {
      "size": 0,
      "aggs": {
        "avg_marks": {
          "avg": {
            "field": "project.marks"
          }
        }
      },
      "query": {
        "bool": {
          "must": [
            {
              "query_string": {
                "query": "project.subject:maths",
                "analyze_wildcard": true,
                "default_field": "*"
              }
            }
          ]
        }
      }
    }

返回汇总所有不需要的平均标记的结果。

    {
      "took": 1,
      "timed_out": false,
      "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
      },
      "hits": {
        "total": 2,
        "max_score": 0,
        "hits": []
      },
      "aggregations": {
        "avg_marks": {
          "value": 51.5
        }
      }
    }

我只需要从给定文档中获得平均数学主题,其中预期结果为56.00

任何有关查询或想法的帮助都会有所帮助。 提前谢谢。

1 个答案:

答案 0 :(得分:0)

首先,您需要在映射中指定索引具有嵌套字段,如下所示:

$ jq -cr 'paths(scalars)' tmp.json
["data1"]
["data2"]
["key1","data3"]
["key1","data4"]
["key2","data5"]
$ jq -r 'paths(scalars) | join("_")' tmp.json
data1
data2
key1_data3
key1_data4
key2_data5

然后你插入你的文档:

PUT /nested-index {
    "mappings": {
        "document": {
            "properties": {
                "project": {
                    "type": "nested",
                    "properties": {
                        "subject": {
                            "type": "keyword"
                        },
                        "marks": {
                            "type": "long"
                        }
                    }
                }
            }
        }
    }
}

然后插入第二个doc:

PUT nested-index/document/1
{
    "project": [
        {
            "subject": "maths",
            "marks": 47
        },
        {
            "subject": "computers",
            "marks": 22
        }
    ]
}

然后你进行聚合,但指定你有这样的嵌套结构:

PUT nested-index/document/2
{
    "project": [
        {
            "subject": "maths",
            "marks": 65
        },
        {
            "subject": "networks",
            "marks": 72
        }
    ]
}

以及为什么你的查询不起作用以及为什么给出这个结果是因为当你有嵌套字段并做平均值时它会对一个数组中的所有数字求和如果在那个数组中你有一些关键字并不重要你想要仅由一个主题聚合。

因此,如果您有这两个文档,因为在两个文档中您都有数学科目avg将按如下方式计算:

(47 + 22 + 65 + 72)/ 4 = 51.5

如果你想要avg for networks它会返回你(因为在一个文件中你有网络,但它会对数组中的所有值做平均):

65 + 72 = 68.5

所以你需要在这种情况下使用嵌套结构。

如果你只对一个主题感兴趣,那么你只需要为这样的主题进行聚合(主题等于"数学"):

GET nested-index/_search
{
    "size": 0,
    "aggs": {
        "subjects": {
            "nested": {
                "path": "project"
            },
            "aggs": {
                "subjects": {
                    "terms": {
                        "field": "project.subject",
                        "size": 10
                    },
                    "aggs": {
                        "average": {
                            "avg": {
                                "field": "project.marks"
                            }
                        }
                    }
                }
            }
        }
    }
}