Можно ли вычислить «отличную сумму» и «отличное среднее» в эластичном поиске? - PullRequest
1 голос
/ 29 апреля 2020

Как я могу рассчитать «отличное среднее» в эластичном поиске? У меня есть некоторые денормализованные данные, такие как:

{ "record_id" : "100", "cost" : 42 }
{ "record_id" : "200", "cost" : 67 }
{ "record_id" : "200", "cost" : 67 }
{ "record_id" : "200", "cost" : 67 }
{ "record_id" : "400", "cost" : 11 }
{ "record_id" : "400", "cost" : 11 }
{ "record_id" : "500", "cost" : 10 }
{ "record_id" : "600", "cost" : 99 }

Обратите внимание, что «стоимость» всегда одинакова для данного «record_id».

То же самое с приведенными выше данными:

  1. Как получить средние значения для поля "стоимость", но ОТЛИЧИТЬ от "record_id"? Результат будет (42 + 67 + 11 + 10 + 99) /5=45.8

  2. Как я могу получить значения SUM для поля "cost", но DISTINCT по "record_id"? Результат будет 42 + 67 + 11 + 10 + 99 = 229

Могу ли я использовать комбинацию "терминов" агрегации, а затем "первого" и "среднего" субагрегаций? Я думаю, что-то вроде этого: эластичный поиск рассчитать среднее уникальных значений

1 Ответ

1 голос
/ 29 апреля 2020

Это не будет работать с terms aggs. Вот что возможно при использовании безболезненных сценариев:

Индексирование - фактическое отображение может отличаться от сгенерированного по умолчанию (особенно для части .keyword на rec_id):

POST _bulk
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"100","cost":42}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"200","cost":67}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"200","cost":67}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"200","cost":67}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"400","cost":11}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"400","cost":11}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"500","cost":10}
{"index":{"_index":"uniques","_type":"_doc"}}
{"record_id":"600","cost":99}

Затем агрегирование

GET uniques/_search
{
  "size": 0,
  "aggs": {
    "terms": {
      "scripted_metric": {
        "init_script": "state.id_map = [:]; state.sum = 0.0; state.elem_count = 0.0;",
        "map_script": """
          def id = doc['record_id.keyword'].value;
          if (!state.id_map.containsKey(id)) {
            state.id_map[id] = true;
            state.elem_count++;
            state.sum += doc['cost'].value;
          }
        """,
        "combine_script": """
            def sum = state.sum;
            def avg = sum / state.elem_count;

            def stats = [:];
            stats.sum = sum;
            stats.avg = avg;

            return stats
        """,
        "reduce_script": "return states"
      }
    }
  }
}

И уступает

...
"aggregations" : {
    "terms" : {
      "value" : [
        {
          "avg" : 45.8,
          "sum" : 229.0
        }
      ]
    }
  }
...