ElasticSearch - агрегация строк?

У меня есть следующее простое отображение:

"element": {
  "dynamic": "false",
  "properties": {
    "id": { "type": "string", "index": "not_analyzed" },
    "group": { "type": "string", "index": "not_analyzed" },
    "type": { "type": "string", "index": "not_analyzed" }
  }
} 

Что в основном является способом хранения объекта Group:

{
  id : "...",
  elements : [
    {id: "...", type: "..."},
    ...
    {id: "...", type: "..."}
  ] 
}

Я хочу узнать, сколько существует разных групп, использующих один и тот же набор типов элементов (упорядоченных, включая повторения).

Очевидным решением было бы изменить схему на:

"element": {
  "dynamic": "false",
  "properties": {
    "group": { "type": "string", "index": "not_analyzed" },
    "concatenated_list_of_types": { "type": "string", "index": "not_analyzed" }
  }
} 

Но из-за требований нам нужно иметь возможность исключать некоторые типы из группы по (агрегации) :(

Все поля документа являются идентификаторами mongo, поэтому в SQL я бы сделал что-то вроде этого:

SELECT COUNT(id), concat_value FROM (
    SELECT GROUP_CONCAT(type_id), group_id 
    FROM table
    WHERE type_id != 'some_filtered_out_type_id' 
    GROUP BY group_id
) T GROUP BY concat_value  

В Elastic с заданным отображением очень легко отфильтровать, также не проблема подсчитать, предполагая, что у нас есть объединенное значение. Излишне говорить, что суммирование не работает для строк.

Как я могу заставить это работать? :)

Спасибо!


person Alexander Mikhalchenko    schedule 23.09.2016    source источник


Ответы (1)


Наконец, я решил эту проблему с помощью скриптов и путем изменения сопоставления.

{
  "mappings": {
    "group": {
      "dynamic": "false",
      "properties": {
        "id": { "type": "string", "index": "not_analyzed" },
        "elements": { "type": "string", "index": "not_analyzed" }
      }
    }
  }
}

Все еще есть некоторые проблемы с повторяющимися элементами в массиве (ScriptDocValues.Strings), по какой-то причине удаляются дубликаты, но вот агрегация, которая подсчитывается по строке concat:

{
  "aggs": {
    "path": {
      "scripted_metric": {
        "map_script": "key = doc['elements'].join('-'); _agg[key] = _agg[key] ? _agg[key] + 1 : 1",
        "combine_script": "_agg",
        "reduce_script": "_aggs.collectMany { it.entrySet() }.inject( [:] ) { result, e -> result << [ (e.key):e.value + ( result[ e.key ] ?: 0 ) ]}"
      }
    }
  }
}

Результат будет следующим:

  "aggregations" : {
    "path" : {
      "value" : {
        "5639abfb5cba47087e8b457e" : 362,
        "568bfc495cba47fc308b4567" : 3695,
        "5666d9d65cba47701c413c53" : 14,
        "5639abfb5cba47087e8b4571-5639abfb5cba47087e8b457b" : 1,
        "570eb97abe529e83498b473d" : 1
      }
    }
  }
person Alexander Mikhalchenko    schedule 23.09.2016
comment
Есть ли у вас какие-либо идеи по этому вопросу? Он похож на ваш. stackoverflow.com/questions/60650823/ - person Radu Linu; 12.03.2020