web-dev-qa-db-fra.com

elasticsearch filtrant par la taille d'un champ qui est un tableau

Comment puis-je filtrer des documents qui ont un champ qui est un tableau et a plus de N éléments?

Comment puis-je filtrer les documents qui ont un champ qui est un tableau vide?

Les facettes sont-elles la solution? Si c'est le cas, comment?

39
eran

Je voudrais regarder le filtre de script . Le filtre suivant doit renvoyer uniquement les documents contenant au moins 10 éléments dans le champ fieldname, qui est un tableau. N'oubliez pas que cela peut coûter cher en fonction du nombre de documents que vous avez dans votre index.

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > 10"
    }
}

Concernant la deuxième question: avez-vous vraiment un tableau vide là-bas? Ou est-ce juste un champ de tableau sans valeur? Vous pouvez utiliser le filtre missing missing pour obtenir des documents qui n'ont pas de valeur pour un champ spécifique:

"filter" : {
    "missing" : { "field" : "user" }
}

Sinon, je suppose que vous devez utiliser le script à nouveau, comme ce que j'ai suggéré ci-dessus, avec une longueur différente en entrée. Si la longueur est constante, je le mettrais dans la section params pour que le script soit mis en cache par elasticsearch et réutilisé, car il est toujours identique:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > param1"
        "params" : {
            "param1" : 10
        }
    }
}
45
javanna

la réponse de javanna est correcte sur Elasticsearch version 1.3.x et antérieure, puisque la version 1.4 du module de script par défaut a été remplacée par groovy (était mvel ).

Pour répondre à la question de OP.

Sur Elasticsearch 1.3.x et versions antérieures, utilisez ce code:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > 10"
    }
}

Sur Elasticsearch 1.4.x et versions ultérieures, utilisez ce code:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.size() > 10"
    }
}

De plus, sur Elasticsearch 1.4.3 et versions ultérieures, vous devrez activer le script dynamique car il a été désactivé par défaut, à cause d'un problème de sécurité. Voir: https://www.elastic.co/guide/fr/elasticsearch/reference/1.4/modules-scripting.html

12
MicroAleX

A mon avis, la méthode correcte de filtrage des tableaux en fonction de la taille à l'aide de scripts est la suivante:

"filter" : {
    "script" : {
        "script" : "_source.fieldName.size() > 1"
    }
}

Si je fais cela comme @javanna suggère que cela jette une exception groovy.lang.MissingPropertyException: No such property: length for class: Java.lang.String

6
lisak

Je poste toujours ici pour ceux qui sont restés dans la même situation avec moi… .. Disons que vos données ressemblent à ceci:

{
    "_source": {
        "fieldName" : [
            {
                "f1": "value 11",
                "f2": "value 21"
            },
            {
                "f1": "value 12",
                "f2": "value 22"
            }
        ]
    }
}

Ensuite, pour filtrer fieldName avec une longueur> 1, par exemple:

"query": {
    "bool" : {
        "must" : {
            "script" : {
                "script" : {
                    "inline": "doc['fieldName.f1'].values.length > 1",
                    "lang": "painless"
                 }
            }
        }
    }
}

La syntaxe du script est la suivante: documentation ES 5.4 https://www.elastic.co/guide/fr/elasticsearch/reference/current/query-dsl-script-query.html .

5
ThangTD

Le moyen le plus simple de procéder consiste à "dénormaliser" vos données afin que vous disposiez d'une propriété contenant le nombre et d'un booléen, qu'elle existe ou non. Ensuite, vous pouvez simplement rechercher sur ces propriétés.

Par exemple:

{
   "id": 31939,
   "hasAttachments": true,
   "attachmentCount": 2,
   "attachments": [
      {
         "type": "Attachment",
         "name": "txt.txt",
         "mimeType": "text/plain"
      },
      {
         "type": "Inline",
         "name": "jpg.jpg",
         "mimeType": "image/jpeg"
      }
   ]  
}
2
superlogical

Lorsque vous avez besoin de trouver des documents contenant des champs dont la taille/longueur doit être supérieure à zéro @javanna a donné une réponse correcte. Je voulais seulement ajouter si votre champ est un champ de texte et que vous voulez trouver des documents contenant du texte dans ce champ, vous ne pouvez pas utiliser la même requête. Vous devrez faire quelque chose comme ceci:

GET index/_search 
{
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "FIELD_NAME": {
                            "gt": 0
                        }
                    }
                }
            ]
        }
    }
}

Ce n’est pas une réponse exacte à cette question car la réponse existe déjà, mais la solution à un problème similaire que j’avais, peut-être que quelqu'un le trouvera utile.

1
Luka Lopusina