Elasticsearch фильтрует группу документов по полю

У меня есть некоторые документы:

{"name": "John", "district": 1},
{"name": "Mary", "district": 2},
{"name": "Nick", "district": 1},
{"name": "Bob", "district": 3},
{"name": "Kenny", "district": 1}

Как я могу отфильтровать/выбрать отдельные документы по районам?

{"name": "John", "district": 1},
{"name": "Mary", "district": 2},
{"name": "Bob", "district": 3}

В SQL я могу использовать GROUP BY. Я попробовал агрегацию терминов, но она вернула только количество различных.

"aggs": {
  "distinct": {
    "terms": {
      "field": "district",
      "size": 0
    }
  }
}

Спасибо за помощь! :-)


person Kevin    schedule 23.09.2014    source источник
comment
Решит ли мой ответ вашу проблему?   -  person Akash Yadav    schedule 23.09.2014


Ответы (2)


Если у вас ElasticSearch версии 1.3 или выше, вы можете использовать субагрегацию типа top_hits, который даст вам (по умолчанию) три первых совпадающих документа, отсортированных по вашей оценке запроса (здесь 1, поскольку вы используете запрос match_all).

Вы можете установить параметр size больше 3.

Следующий набор данных и запрос:

POST /test/districts/
{"name": "John", "district": 1}

POST /test/districts/
{"name": "Mary", "district": 2}

POST /test/districts/
{"name": "Nick", "district": 1}

POST /test/districts/
{"name": "Bob", "district": 3}

POST test/districts/_search
{
  "size": 0, 
  "aggs":{
    "by_district":{
      "terms": {
        "field": "district",
        "size": 0
      },
      "aggs": {
        "tops": {
          "top_hits": {
            "size": 10
          }
        }
      }
    }
  }
}

Выведет документы так, как вы хотите:

{
   "took": 5,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 4,
      "max_score": 0,
      "hits": []
   },
   "aggregations": {
      "by_district": {
         "buckets": [
            {
               "key": 1,
               "key_as_string": "1",
               "doc_count": 2,
               "tops": {
                  "hits": {
                     "total": 2,
                     "max_score": 1,
                     "hits": [
                        {
                           "_index": "test",
                           "_type": "districts",
                           "_id": "XYHu4I-JQcOfLm3iWjTiOg",
                           "_score": 1,
                           "_source": {
                              "name": "John",
                              "district": 1
                           }
                        },
                        {
                           "_index": "test",
                           "_type": "districts",
                           "_id": "5dul2XMTRC2IpV_tKRRltA",
                           "_score": 1,
                           "_source": {
                              "name": "Nick",
                              "district": 1
                           }
                        }
                     ]
                  }
               }
            },
            {
               "key": 2,
               "key_as_string": "2",
               "doc_count": 1,
               "tops": {
                  "hits": {
                     "total": 1,
                     "max_score": 1,
                     "hits": [
                        {
                           "_index": "test",
                           "_type": "districts",
                           "_id": "I-9Gd4OYSRuexhP1dCdQ-g",
                           "_score": 1,
                           "_source": {
                              "name": "Mary",
                              "district": 2
                           }
                        }
                     ]
                  }
               }
            },
            {
               "key": 3,
               "key_as_string": "3",
               "doc_count": 1,
               "tops": {
                  "hits": {
                     "total": 1,
                     "max_score": 1,
                     "hits": [
                        {
                           "_index": "test",
                           "_type": "districts",
                           "_id": "bti2y-OUT3q2mBNhhI3xeA",
                           "_score": 1,
                           "_source": {
                              "name": "Bob",
                              "district": 3
                           }
                        }
                     ]
                  }
               }
            }
         ]
      }
   }
}
person ThomasC    schedule 23.09.2014
comment
Отлично, вы спасли мне жизнь!! - person Kevin; 23.09.2014
comment
Привет, @ThomasC, есть идеи, как фильтровать записи, которые должны быть объединены таким образом? уже полчаса пытаюсь. Спасибо ! - person lisak; 30.11.2015
comment
Привет @lisak! Вы не можете вложить агрегацию в top_hits, однако возможно и обратное. Попробуйте использовать агрегацию фильтров и вложите в нее top_hits. Или вы можете отфильтровать результаты в разделе запросов. - person ThomasC; 17.12.2015
comment
@ThomasC, не могли бы вы ответить на этот stackoverflow.com/questions/46764307/ - person Sunil Garg; 16.10.2017
comment
Это работает, но если есть более 500 уникальных районов, есть ли способ разбиения на страницы, где я могу вставить ключевое слово from, агрегация терминов не поддерживает это - person Abhijit; 01.01.2020

Эластичный поиск не предоставляет отдельных документов по значению или группировке по уникальному значению. Но для этого есть обходной путь, вы можете сделать это, если используете Java-клиент или можете преобразовать его на подходящий язык.

SearchResponse response = client.prepareSearch().execute().actionGet();
SearchHits hits = response.getHits();

Iterator<SearchHit> iterator = hits.iterator();
Map<String, SearchHit> distinctObjects = new HashMap<String,SearchHit>();
while (iterator.hasNext()) {
    SearchHit searchHit = (SearchHit) iterator.next();
    Map<String, Object> source = searchHit.getSource();
    if(source.get("district") != null){
        distinctObjects.put(source.get("district").toString(),source);
    }

} 
person Akash Yadav    schedule 23.09.2014
comment
Что делать, если вы используете пагинацию? Получаете ли вы страницы с 8 результатами, другие с 10 и третьи с 7, если вы получаете 10 результатов на страницу? - person Vladimir Nul; 12.12.2017
comment
это не обходной путь. это собственное колесо переписать. Собираетесь ли вы прочитать все объекты в вашей памяти? а если их миллионы? - person walv; 10.09.2018