2014-09-23 11 views
11

Mam kilka dokumentów:Elasticsearch filtr Grupa dokument przez pola

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

Jak można filtrować/SELECT odrębne dokumenty po okręgu?

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

W języku SQL mogę używać GROUP BY. Próbowałem agregacji warunków, ale zwrócono tylko liczbę odrębną.

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

Dziękuję za pomoc! :-)

+0

moja odpowiedź rozwiązać swój problem –

Odpowiedz

29

Jeśli wersja ElasticSearch wynosi 1,3 lub powyżej, można użyć subaggregation typu top_hits która daje (domyślnie) trzy najlepsze dokumenty pasujące do wyniku zapytania (tutaj 1, gdy używasz zapytania match_all).

Można ustawić parametr size do więcej niż 3.

Poniższy zestaw danych i zapytania:

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 
      } 
     } 
     } 
    } 
    } 
} 

wyjściowe będą dokumenty, jak chcesz:

{ 
    "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

Doskonale, uratujesz mi życie !! – Geany

+0

Hey @ThomasC, każdy pomysł, jak również filtrować rekordy, które mają być agregowane w ten sposób? Próbuję już pół godziny. Dzięki ! – lisak

+0

Witam @lisak! Nie można zagnieździć agregacji pod top_hits, jednak jest odwrotnie. Spróbuj użyć agregacji filtrów i zagnieżdż w top_hits. Lub możesz filtrować wyniki w sekcji zapytania – ThomasC

2

Wyszukiwanie elastyczne nie zapewnia odrębnych dokumentów wartości lub grupy o unikalnej wartości. Ale jest obejście do tego można to zrobić, jeśli używasz klienta Java czy można przekształcić go w odpowiednim języku

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

Co, jeśli używasz stronicowania? Czy otrzymujesz strony z 8 wynikami, inne z 10, a inne z 7, jeśli dostajesz 10 wyników na stronę? –