Comment obtenir une agrégation Elasticsearch avec plusieurs champs

j'essaie de trouver des tags reliés à celui que vous consultez actuellement. Chaque document de notre index est étiqueté. Chaque étiquette est formée de deux parties - un ID et un nom de texte:

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

Pour récupérer les tags, je suis simplement l'interrogation de documents et d'obtenir un total de leurs balises:

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

Cela fonctionne parfaitement, j'obtiens les résultats que je veux. Cependant, j'exige à la fois l'identification de l'étiquette et nom de faire quelque chose d'utile. J'ai exploré comment ce faire, les solutions semblent être:

  1. Combiner les champs lors de l'indexation
  2. Un script pour munge ensemble les champs
  3. imbriquée agrégation

les options 1 et 2 ne sont pas disponibles pour moi donc j'ai choisi 3 mais il ne répond pas de manière attendue. Compte tenu de la requête suivante (toujours à la recherche de documents également marqués 'Biscuits'):

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

je vais obtenir ce résultat:

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

l'agrégation imbriquée inclut à la fois le terme de recherche et la balise je suis après (renvoyée dans l'ordre alphabétique).

j'ai essayé d'atténuer cela en ajoutant un exclude à l'agrégation imbriquée mais cela ralentit la requête beaucoup trop (environ 100 fois pour 500000 docs). Jusqu'à présent, la solution la plus rapide consiste à dé duper le résultat manuellement.

Quelle est la meilleure façon d'obtenir une agrégation de tags avec les tags ID et tag nom dans la réponse?

Merci d'être venus jusqu'ici!

34
demandé sur i_like_robots 2015-06-09 12:47:00

1 réponses

en apparence, votre tags n'est pas nested. Pour que cette agrégation fonctionne,vous en avez besoin nested alors qu'il y a une association entre un id et name. Sans nested la liste des ids est juste un tableau et la liste des names est un autre tableau:

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

aussi, notez que j'ai ajouté à la correspondance cette ligne "include_in_parent": true ce qui signifie que votre nested les balises se comporteront aussi comme un tableau "plat" structure.

donc, tout ce que vous aviez jusqu'à présent dans vos requêtes fonctionnera toujours sans aucun changement aux requêtes.

mais, pour cette requête particulière de la vôtre, l'agrégation doit changer à quelque chose comme ceci:

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

Et le résultat est comme ceci:

   "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
                        }
                     ]
                  }
               },
               .....
47
répondu Andrei Stefan 2015-06-18 15:31:47