ELASTICSEARCH — подсчитывает уникальное значение с условием

#elasticsearch

#elasticsearch

Вопрос:

Я хотел бы получить запрос, который возвращает количество повторений поля в соответствии с уникальным значением другого поля. У меня есть этот json:

           "name" : james,
          "city" : "chicago" <----------- same
        },
        {
          "name" : james,
          "city" : "san francisco"
        },
        {
          "name" : james,
          "city" : "chicago" <-----------same
        },
         {
          "name" : Mike,
          "city" : "chicago"
        },
         {
          "name" : Mike,
          "city" : "texas"<-----------same
        },
         {
          "name" : Mike,
          "city" : "texas"<-----------same
        },
         {
          "name" : Peter,
          "city" : "chicago"
        },
  

Я хочу создать запрос, в котором я буду подсчитывать на основе уникального значения двух полей.
Например, джеймс равен 2, потому что есть два равных поля (имя: Джеймс, город, Чикаго) и другое поле (имя: Джеймс, город: Сан-Франциско).
Тогда результат был бы следующим:

   {
    "key" : "james",
    "doc_count" : 2
  },
  {
    "key" : "Mike",
    "doc_count" : 2
  },
  {
    "key" : "Peter",
    "doc_count" : 1
  },
  

Возможно ли подсчитать одно значение из двух полей?

Ответ №1:

Вы можете выполнить двухуровневую агрегацию терминов:

 {
  "size": 0,
  "aggs": {
    "names": {
      "terms": {
        "field": "name.keyword",
        "size": 10
      },
      "aggs": {
        "citys_by_name": {
          "terms": {
            "field": "city.keyword",
            "size": 10,
            "min_doc_count": 2
          }
        }
      }
    }
  }
}
  

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

 "aggregations" : {
    "names" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "james",
          "doc_count" : 15,
          "citys_by_name" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "chicago",
                "doc_count" : 14
              }
            ]
          }
        },
        {
          "key" : "Peter",
          "doc_count" : 2,
          "citys_by_name" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "chicago",
                "doc_count" : 2
              }
            ]
          }
        },
        {
          "key" : "mike",
          "doc_count" : 2,
          "citys_by_name" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [ ]
          }
        }
      ]
    }
  }
  

Или вы можете объединить поля:

 GET test/_search
{
  "size": 0,
  "aggs": {
    "names": {
      "terms": {
        "script": {
          "source": "return doc['name.keyword'].value   ' '   doc['city.keyword'].value",
          "lang": "painless"
        },
        "field": "name.keyword",
        "size": 10,
        "min_doc_count": 2
      }
    }
  }
}
  

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

  "aggregations" : {
    "names" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "james chicago",
          "doc_count" : 14
        },
        {
          "key" : "Peter chicago",
          "doc_count" : 2
        }
      ]
    }
  }
  

Если вам нужна дополнительная статистика по сегментам, используйте агрегацию stats_buckets:

 {
  "size": 0,
  "aggs": {
    "names": {
      "terms": {
        "script": {
          "source": "return doc['name.keyword'].value   ' '   doc['city.keyword'].value",
          "lang": "painless"
        },
        "field": "name.keyword",
        "size": 10,
        "min_doc_count": 2
      }
    },
   "names_stats":{
      "stats_bucket": {
        "buckets_path":"names._count"
      }
    }
    }
  }
  

Приведет:

 "aggregations" : {
    "names" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "james PARIS",
          "doc_count" : 15
        },
        {
          "key" : "james chicago",
          "doc_count" : 13
        },
        {
          "key" : "samuel PARIS",
          "doc_count" : 11
        },
        {
          "key" : "fred PARIS",
          "doc_count" : 2
        }
      ]
    },
    "names_stats" : {
      "count" : 4,
      "min" : 2.0,
      "max" : 15.0,
      "avg" : 10.25,
      "sum" : 41.0
    }
  }
  

Комментарии:

1. Можно было бы получить количество ключей в корзинах? Например, в последнем ответе с ключом: Джеймс Чикаго, ключ: Питер Чикаго; количество ключей в сегментах == 2.

2. Используйте Stats_buckets. Я обновлю свой ответ. Но будьте осторожны с выполнением этого запроса

3. помог ли вам мой ответ? если да, пожалуйста, не забудьте проголосовать

Ответ №2:

Это было решение, которое решило проблему для меня

 GET test/_search?filter_path=aggregations.count
{
  "size": 0,
  "aggs": {
    "names": {
      "terms": {
        "script": {
          "source": "return doc['name.keyword'].value   ' '   doc['city.keyword'].value",
          "lang": "painless"
        },
        "field": "name.keyword",
        "size": 10,
        "min_doc_count": 2
      }
    },
    "count":{
      "cardinality": {"script": "return doc['name.keyword'].value   ' '   doc['city.keyword'].value"
      }
    }
  }
}
  

Вывод:

 {
  "aggregations" : {
      "count" : {
        "value" : 2
    }
  }
}