2015-06-09 16 views
32

Sto tentando di trovare i tag correlati a quello attualmente visualizzato. Ogni documento nel nostro indice è taggato. Ogni tag è formata da due parti - un ID e di testo Nome:Come ottenere un'aggregazione Elasticsearch con più campi

{ 
    ... 
    meta: { 
     ... 
     tags: [ 
      { 
       id: 123, 
       name: 'Biscuits' 
      }, 
      { 
       id: 456, 
       name: 'Cakes' 
      }, 
      { 
       id: 789, 
       name: 'Breads' 
      } 
     ] 
    } 
} 

per recuperare i tag correlati Sto semplicemente l'interrogazione di documenti e ottenere un aggregato di loro tag:

{ 
    "query": { 
     "bool": { 
      "must": [ 
       { 
        "match": { 
         "item.meta.tags.id": "123" 
        } 
       }, 
       { 
        ... 
       } 
      ] 
     } 
    }, 
    "aggs": { 
     "baked_goods": { 
      "terms": { 
       "field": "item.meta.tags.id", 
       "min_doc_count": 2 
      } 
     } 
    } 
} 

Questo funziona perfettamente , Sto ottenendo i risultati che voglio. Tuttavia, ho bisogno sia del codice identificativo sia del nome per fare qualcosa di utile. Ho esplorato come eseguire questa operazione, le soluzioni sembrano essere:

  1. combinare i campi durante l'indicizzazione
  2. Uno script per munge insieme i campi
  3. un'aggregazione nidificato

Opzione uno e due non sono disponibili per me, quindi sono andato con 3 ma non risponde in modo atteso. Data la seguente query (ancora alla ricerca di documenti anche taggati con 'Biscuits'):

{ 
    ... 
    "aggs": { 
     "baked_goods": { 
      "terms": { 
       "field": "item.meta.tags.id", 
       "min_doc_count": 2 
      }, 
      "aggs": { 
       "name": { 
        "terms": { 
         "field": "item.meta.tags.name" 
        } 
       } 
      } 
     } 
    } 
} 

mi metterò questo risultato:

{ 
    ... 
    "aggregations": { 
     "baked_goods": { 
      "buckets": [ 
       { 
        "key": "456", 
        "doc_count": 11, 
        "name": { 
         "buckets": [ 
          { 
           "key": "Biscuits", 
           "doc_count": 11 
          }, 
          { 
           "key": "Cakes", 
           "doc_count": 11 
          } 
         ] 
        } 
       } 
      ] 
     } 
    } 
} 

L'aggregazione nidificato include sia il termine di ricerca e il tag Io vengo dopo (restituito in ordine alfabetico).

Ho cercato di attenuarlo aggiungendo un exclude all'aggregazione nidificata, ma questo ha rallentato troppo la query (circa 100 volte per 500000 documenti). Finora la soluzione più veloce è quella di decodificare il risultato manualmente.

Qual è il modo migliore per ottenere una aggregazione di tag con l'ID tag e il nome del tag nella risposta?

Grazie per averlo fatto così lontano!

risposta

44

A quanto sembra, il tuo tags non è nested. Perché questa aggregazione funzioni, you need it nested in modo che sia presente un'associazione tra uno id e uno name. Senza nested l'elenco dei id s solo un array e l'elenco dei name s è un altro array:

"item": { 
     "properties": { 
     "meta": { 
      "properties": { 
      "tags": { 
       "type": "nested",   <-- nested field 
       "include_in_parent": true, <-- to, also, keep the flat array-like structure 
       "properties": { 
       "id": { 
        "type": "integer" 
       }, 
       "name": { 
        "type": "string" 
       } 
       } 
      } 
      } 
     } 
     } 
    } 

Si noti inoltre che ho aggiunto alla mappatura questa linea "include_in_parent": true il che significa che i vostri nested tag sarà, inoltre, si comportano come una struttura "piatta" come una matrice.

Quindi, tutto ciò che avevi finora nelle tue query continuerà a funzionare senza modifiche alle query.

Ma, per questa query particolare del vostro, l'aggregazione deve cambiare a qualcosa di simile:

{ 
    "aggs": { 
    "baked_goods": { 
     "nested": { 
     "path": "item.meta.tags" 
     }, 
     "aggs": { 
     "name": { 
      "terms": { 
      "field": "item.meta.tags.id" 
      }, 
      "aggs": { 
      "name": { 
       "terms": { 
       "field": "item.meta.tags.name" 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

e il risultato è simile a questo:

"aggregations": { 
     "baked_goods": { 
     "doc_count": 9, 
     "name": { 
      "doc_count_error_upper_bound": 0, 
      "sum_other_doc_count": 0, 
      "buckets": [ 
       { 
        "key": 123, 
        "doc_count": 3, 
        "name": { 
        "doc_count_error_upper_bound": 0, 
        "sum_other_doc_count": 0, 
        "buckets": [ 
         { 
          "key": "biscuits", 
          "doc_count": 3 
         } 
        ] 
        } 
       }, 
       { 
        "key": 456, 
        "doc_count": 2, 
        "name": { 
        "doc_count_error_upper_bound": 0, 
        "sum_other_doc_count": 0, 
        "buckets": [ 
         { 
          "key": "cakes", 
          "doc_count": 2 
         } 
        ] 
        } 
       }, 
       ..... 
+1

@i_like_robots Sono curioso, hai provato la mia soluzione suggerita? –

+1

ha deciso di mantenere la taglia per se stesso, grazie per la buona risposta! – asktomsk

+2

Alla fine, sì! Alla fine siamo riusciti a passare il tempo a creare un nuovo indice con campi nidificati correttamente, ma temo che non lo fosse fino a poco tempo fa. Grazie per il tempo dedicato a rispondere alla mia domanda e mi scuso per aver trascurato qualsiasi etichetta di Overflow dello stack! –