2014-09-23 3 views
11

У меня есть некоторые документы: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 
    } 
    } 
} 

Благодарим за помощь! :-)

+0

ли мой ответ решить вашу проблему –

ответ

29

Если ElasticSearch версия 1.3 или выше, вы могли бы использовать subaggregation типа 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 
          } 
         } 
        ] 
        } 
       } 
      } 
     ] 
     } 
    } 
} 
+0

Отлично, вы спасете мою жизнь !! – Geany

+0

Эй, @ThomasC, любая идея как фильтровать записи, которые должны быть объединены так? Я пробую уже полчаса. Благодаря ! – lisak

+0

Привет @lisak! Вы не можете вложить агрегацию под top_hits, однако, возможно противоположное. Попробуйте использовать агрегацию фильтра и вставьте top_hits под. Или вы можете отфильтровать результаты в разделе запроса – ThomasC

2

Упругий поиск не предоставляет отдельные документы по значению или группе по уникальному значению. Но есть работа вокруг этого вы можете сделать это, если вы используете 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); 
    } 

} 
+0

Что делать, если вы используете разбивку на страницы? Получают страницы с 8 результатами, другие с 10 и другими с 7, если вы получаете 10 результатов на страницу? –