агрегат эластичного поиска в списке объектов с условием - PullRequest
0 голосов
/ 28 мая 2019

Скажем, у нас есть следующие документы вasticsearch:

[{
  "person": {
    'name': 'asqar'
  },
  "bill": [
    {
      code:2,
      value: 210
    },
    {
      code:3,
      value: 330
    },
    {
      code:8,
      value: 220
    },
  ]
},
{
  "person": {
    'name': 'asqar'
  },
  "bill": [
    {
      code:2,
      value: 340
    },
    {
      code:4,
      value: 340
    },
    {
      code:1,
      value: 200
    },
  ]
},
{
  "person": {
    'name': 'asqar'
  },
  "bill": [
    {
      code:2,
      value: 810
    },
    {
      code:4,
      value: 630
    },
    {
      code:8,
      value: 220
    },
  ]
}]

Я хочу применить агрегатную функцию к определенному объекту в массиве bill с некоторым условием, например, я хочу вычислить avg из value, код которого равен 2.

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

Необходимо создать поле счета как вложенный объект для фильтрации по нему.

Затем можно использовать фильтр агрегирование

Отображение:

PUT testindex/_mapping
{
  "properties": {
    "person": {
      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    },
    "bill": {
      "type": "nested",
      "properties": {
        "code": {
          "type": "integer"
        },
        "value":{
          "type": "double"
        }
      }
    }
  }
}

Данные:

    "hits" : [
      {
        "_index" : "testindex",
        "_type" : "_doc",
        "_id" : "422tAWsBd-1D6Ztt1_Tb",
        "_score" : 1.0,
        "_source" : {
          "person" : {
            "name" : "asqar"
          },
          "bill" : [
            {
              "code" : 2,
              "value" : 210
            },
            {
              "code" : 3,
              "value" : 330
            },
            {
              "code" : 8,
              "value" : 220
            }
          ]
        }
      },
      {
        "_index" : "testindex",
        "_type" : "_doc",
        "_id" : "5G2uAWsBd-1D6ZttpfR9",
        "_score" : 1.0,
        "_source" : {
          "person" : {
            "name" : "asqar"
          },
          "bill" : [
            {
              "code" : 2,
              "value" : 340
            },
            {
              "code" : 4,
              "value" : 340
            },
            {
              "code" : 1,
              "value" : 200
            }
          ]
        }
      },
      {
        "_index" : "testindex",
        "_type" : "_doc",
        "_id" : "5W2vAWsBd-1D6ZttQfQ_",
        "_score" : 1.0,
        "_source" : {
          "person" : {
            "name" : "asqar"
          },
          "bill" : [
            {
              "code" : 2,
              "value" : 810
            },
            {
              "code" : 4,
              "value" : 630
            },
            {
              "code" : 8,
              "value" : 220
            }
          ]
        }
      }
    ]

Запрос:

GET testindex/_search
{
  "size": 0, 
  "aggs": {
    "terms_agg": {
      "terms": {
        "field": "person.name.keyword"
      },
      "aggs": {
        "bill": {
          "nested": {
            "path": "bill"
          },
          "aggs": {
            "bill_code": {
              "filter": {
                "term": {
                  "bill.code": 2
                }
              },
              "aggs": {
                "average": {
                  "avg": {
                    "field": "bill.value"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Вывод:

 "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "terms_agg" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "asqar",
          "doc_count" : 3,
          "bill" : {
            "doc_count" : 9,
            "bill_code" : {
              "doc_count" : 3,
              "average" : {
                "value" : 453.3333333333333
              }
            }
          }
        }
      ]
    }
  }
1 голос
/ 29 мая 2019

Сначала необходимо убедиться, что поле bill имеет тип nested .Затем вы можете использовать вложенную агрегацию для работы с вложенными документами.Вы можете использовать агрегацию терминов в bill.code и дочернюю агрегацию avg в поле bill.value для агрегации этих терминов.Это даст вам среднее значение для каждого кода.Теперь, когда вы хотите только агрегацию по коду 2, вы можете использовать селектор сегментов агрегацию для фильтрации и получения только сегментов с кодом 2.

Таким образом, итоговый запрос агрегации будет выглядеть следующим образом:

{
  "aggs": {
    "VALUE_NESTED": {
      "nested": {
        "path": "bill"
      },
      "aggs": {
        "VALUE_TERM": {
          "terms": {
            "field": "bill.code"
          },
          "aggs": {
            "VALUE_AVG": {
              "avg": {
                "field": "bill.value"
              }
            },
            "CODE": {
              "max": {
                "field": "bill.code"
              }
            },
            "CODE_FILTER": {
              "bucket_selector": {
                "buckets_path": {
                  "code": "CODE"
                },
                "script": "params.code == 2"
              }
            }
          }
        }
      }
    }
  }
}

Пример o / p для выше:

"aggregations": {
  "VALUE_NESTED": {
    "doc_count": 9,
    "VALUE_TERM": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 2,
          "doc_count": 3,
          "CODE": {
            "value": 2
          },
          "VALUE_AVG": {
            "value": 453.3333333333333
          }
        }
      ]
    }
  }
}
...