Условия Elasticsearch или агрегирование количества элементов - упорядочить по количеству различных значений

Друзья,

Я провожу некоторый анализ, чтобы найти уникальные пары из сотен миллионов документов. Мнимый пример показан ниже:

документ field1 field2

  1. AAA: BBB
  2. AAA: CCC
  3. PPP: QQQ
  4. PPP: QQQ
  5. ХХХ: ГГГ
  6. ХХХ: ГГГ
  7. МММ: NNN

90% документа содержит уникальную пару, как показано выше в документах 3, 4, 5, 6 и 7, которые меня не интересуют в результате агрегирования. Мне интересно объединить документы 1 и 2.

Запрос на агрегирование терминов:



    "aggs": {
        "f1": {
            "terms": {
                "field": "FIELD1",
                "min_doc_count": 2
              },
              "aggs": {
                "f2": {
                      "terms": {
                    "field": "FIELD2"
                      }
                }
              }
        }
    }

Результат агрегирования сроков



    "aggregations": {
         "f1": {
               "buckets": [
                 {
                    "key": "PPP",
                    "doc_count": 2,
                    "f2": {
                        "buckets": [
                              {
                               "key": "QQQ",
                            "doc_count": 2
                              }
                         ]
                    }
                  },
                  {
                    "key": "XXX",
                    "doc_count": 2,
                    "f2": {
                        "buckets": [
                              {
                               "key": "YYY",
                            "doc_count": 2
                              }
                         ]
                    }
                  },
                  {
                    "key": "AAA",
                    "doc_count": 2,
                    "f2": {
                        "buckets": [
                              {
                                   "key": "BBB",
                                "doc_count": 1
                              },
                              {
                               "key": "CCC",
                               "doc_count": 1
                              }
                         ]
                    }
                  }
            ]
         }
    }

Меня интересует только, чтобы ключ AAA находился в результате агрегации. Как лучше всего отфильтровать результат агрегирования, содержащий отдельные пары?

Я пробовал с агрегацией мощности, которая приводит к подсчету значений unque. Однако я не могу отфильтровать то, что мне не интересно, из результатов агрегирования.

Запрос агрегирования мощности



    "aggs": {
        "f1": {
            "terms": {
                "field": "FIELD1",
                "min_doc_count": 2
              },
            "aggs": {
                "f2": {
                      "cardinality": {
                        "field": "FIELD2"
                      }
                }
              }
        }
    }

Результат агрегирования мощности



    "aggregations": {
        "f1": {
               "buckets": [
                 {
                    "key": "PPP",
                    "doc_count": 2,
                    "f2": {
                          "value" : 1
                    }
                  },
                  {
                    "key": "XXX",
                    "doc_count": 2,
                    "f2": {
                          "value" : 1
                    }
                  },
                  {
                    "key": "AAA",
                    "doc_count": 2,
                    "f2": {
                          "value" : 2
                    }
                  }
            ]
         }
    }

По крайней мере, если бы я мог отсортировать по количеству элементов, это помогло бы мне найти обходные пути. Пожалуйста, помогите мне в этом отношении.

P.S: Написание программы Spark / Mapreduce для постобработки / фильтрации результата агрегирования не является ожидаемым решением этой проблемы.


person Deepak    schedule 03.09.2014    source источник
comment
Если вы хотите применить сортировку к количественному значению, полученному из второй агрегации, вы можете сделать это, применив order в первой агрегации, как это "terms":{"field":"field1","min_doc_count":2,"order":{"f2":"desc/asc"}}   -  person Vara Prasad    schedule 21.12.2015


Ответы (2)


Я предлагаю использовать запрос фильтра вместе с агрегатами, поскольку вас интересует только field1 = AAA.

У меня есть похожий пример.

Например, у меня есть список всех пациентов в моей больнице. Я храню их употребление наркотиков во вложенном объекте DRUG. Каждый пациент мог принимать разные лекарства, и каждый мог принимать одно лекарство несколько раз.

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

{
  "size": 0,
  "_source": false,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "nested": {
          "path": "DRUG",
          "filter": {
            "bool": {
              "must": [{ "term": { "DRUG.NAME": "aspirin" } }]
  }}}}}},
  "aggs": {
    "DRUG_FACETS": {
      "nested": {
        "path": "DRUG"
      },
      "aggs": {
        "DRUG_NAME_FACETS": {
          "terms": { "field": "DRUG.NAME", "size": 0 },
          "aggs": {
            "DISTINCT": { "cardinality": { "field": "DRUG.PATIENT" } }
          }
  }}}}
}

Пример результата:

{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 6,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "DRUG_FACETS": {
      "doc_count": 11,
      "DRUG_NAME_FACETS": {
        "buckets": [
          {
            "key": "aspirin",
            "doc_count": 6,
            "DISTINCT": {
              "value": 6
            }
          },
          {
            "key": "vitamin-b",
            "doc_count": 3,
            "DISTINCT": {
              "value": 2
            }
          },
          {
            "key": "vitamin-c",
            "doc_count": 2,
            "DISTINCT": {
              "value": 2
            }
          }
        ]
      }
    }
  }
}

Первым в ведрах будет аспирин. Но вы можете видеть, что еще 2 пациента также принимали витамин B, когда принимали аспирин.

Если вы измените значение поля DRUG.NAME на другое название лекарства, например, «витамин-b», я полагаю, вы получите витамин-b в первой позиции ведер.

Надеюсь, это поможет в вашем вопросе.

person TonyLxc    schedule 26.10.2014
comment
Вместо использования query, который в конечном итоге будет использовать контекст запроса и вычислять оценки, лучше определить фильтр в вашей агрегации, а затем определить субагрегации. - person Ashvjit Singh; 14.01.2020

Немного поздно, надеюсь, это поможет другим.

Простой подход - отфильтровать только записи AAA в верхней агрегации:

{
  "size": 0,
  "aggregations": {
    "filterAAA": {
      "filter": {
        "term": {
          "FIELD1": "AAA"
        }
      },
      "aggregations": {
        "f1": {
          "terms": {
            "field": "FIELD1",
            "min_doc_count": 2
          },
          "aggregations": {
            "f2": {
              "terms": {
                "field": "FIELD2"
              }
            }
          }
        }
      }
    }
  }
}
person Eli    schedule 23.08.2017