Как рассчитать разницу между метриками в разных агрегатах в asticsearch

Я хочу вычислить разницу вложенных агрегаций между двумя датами.

Чтобы быть более конкретным, можно рассчитать разницу между date_1.buckets.field_1.buckets.field_2.buckets.field_3.value - date_2.buckets.field_1.buckets.field_2.buckets.field_3.value учитывая ниже запрос / ответ. Это возможно с asticsearch v.1.0.1?

Запрос агрегации выглядит следующим образом:

 {
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "date": [
                  "2014-08-18 00:00:00.0",
                  "2014-08-15 00:00:00.0"
                ]
              }
            }
          ]
        }
      }
    }
  },
  "aggs": {
    "date_1": {
      "filter": {
        "terms": {
          "date": [
            "2014-08-18 00:00:00.0"
          ]
        }
      },
      "aggs": {
        "my_agg_1": {
          "terms": {
            "field": "field_1",
            "size": 2147483647,
            "order": {
              "_term": "desc"
            }
          },
          "aggs": {
            "my_agg_2": {
              "terms": {
                "field": "field_2",
                "size": 2147483647,
                "order": {
                  "_term": "desc"
                }
              },
              "aggs": {
                "my_agg_3": {
                  "sum": {
                    "field": "field_3"
                  }
                }
              }
            }
          }
        }
      }
    },
    "date_2": {
      "filter": {
        "terms": {
          "date": [
            "2014-08-15 00:00:00.0"
          ]
        }
      },
      "aggs": {
        "my_agg_1": {
          "terms": {
            "field": "field_1",
            "size": 2147483647,
            "order": {
              "_term": "desc"
            }
          },
          "aggs": {
            "my_agg_1": {
              "terms": {
                "field": "field_2",
                "size": 2147483647,
                "order": {
                  "_term": "desc"
                }
              },
              "aggs": {
                "my_agg_3": {
                  "sum": {
                    "field": "field_3"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

И ответ выглядит так:

{
  "took": 236,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "hits": {
    "total": 1646,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "date_1": {
      "doc_count": 823,
      "field_1": {
        "buckets": [
          {
            "key": "field_1_key_1",
            "doc_count": 719,
            "field_2": {
              "buckets": [
                {
                  "key": "key_1",
                  "doc_count": 275,
                  "field_3": {
                    "value": 100
                  }
                }
              ]
            }
          }
        ]
      }
    },
    "date_2": {
      "doc_count": 823,
      "field_1": {
        "buckets": [
          {
            "key": "field_1_key_1",
            "doc_count": 719,
            "field_2": {
              "buckets": [
                {
                  "key": "key_1",
                  "doc_count": 275,
                  "field_3": {
                    "value": 80
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }
}

Спасибо.

3 ответа

Решение

Никакие арифметические операции не допускаются между результатами двух агрегатов из DSL эластичного поиска, даже с использованием сценариев. (До версии 1.1.1, по крайней мере, я знаю)

Такие операции должны обрабатываться на стороне клиента после обработки результата aggs.

Ссылка

упругости поиск агрегации для сортировки по соотношению агрегации

С упругим поиском возможна новая версия (например: 5.6.9):

{
  "size": 0,
    "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "filter": [
            {
              "range": {
                "date_created": {
                  "gte": "2018-06-16T00:00:00+02:00",
                  "lte": "2018-06-16T23:59:59+02:00"
                }
              }
            }
          ]
        }
      }
    }
  },
  "aggs": {
    "by_millisec": {
      "range" : {
        "script" : {
          "lang": "painless",
            "source": "doc['date_delivered'][0] - doc['date_created'][0]"
        },
        "ranges" : [
          { "key": "<1sec", "to": 1000.0 },
          { "key": "1-5sec", "from": 1000.0, "to": 5000.0 },
          { "key": "5-30sec", "from": 5000.0, "to": 30000.0 },
          { "key": "30-60sec", "from": 30000.0, "to": 60000.0 },
          { "key": "1-2min", "from": 60000.0, "to": 120000.0 },
          { "key": "2-5min", "from": 120000.0, "to": 300000.0 },
          { "key": "5-10min", "from": 300000.0, "to": 600000.0 },
          { "key": ">10min", "from": 600000.0 }
        ]
      }
    }
  }
}

В 1.0.1 я ничего не мог найти, но в 1.4.2 вы могли попробовать scripted_metric агрегация (пока экспериментальная).

Вот scripted_metric страница документации

Я не очень хорошо разбираюсь в синтаксисе asticsearch, но думаю, что ваши метрические данные будут такими

init_script- просто инициализируйте аккумулятор на каждую дату:

"init_script": "_agg.d1Val = 0; _agg.d2Val = 0;"

map_script- проверить дату документа и добавить в нужный аккумулятор:

"map_script": "if (doc.date == firstDate) { _agg.d1Val += doc.field_3; } else { _agg.d2Val = doc.field_3;};",

reduce_script - накапливать промежуточные данные от разных осколков и возвращать окончательные результаты:

"reduce_script": "totalD1 = 0; totalD2 = 0; for (agg in _aggs) {  totalD1 += agg.d1Val ; totalD2 += agg.d2Val ;}; return totalD1 - totalD2"

Я не думаю, что в этом случае вам нужно combine_script,

Если конечно, если вы не можете использовать 1.4.2, то это не поможет:-)

Другие вопросы по тегам