web-dev-qa-db-fra.com

Rechercher des documents avec une valeur de chaîne vide sur elasticsearch

J'ai essayé de filtrer avec elasticsearch uniquement les documents contenant une chaîne vide dans son corps. Jusqu'à présent, je n'ai pas de chance. 

Avant de continuer, je dois mentionner que j'ai déjà essayé les nombreuses "solutions" disséminées sur Interwebz et StackOverflow.

Voici donc la requête que j'essaie d'exécuter, suivie de ses homologues:

{
    "query": {
        "filtered":{
            "filter": {
                "bool": {
                    "must_not": [
                        {
                            "missing":{
                                "field":"_textContent"
                            }
                        }
                    ]
                }
            }
        }
    }
}

J'ai aussi essayé ce qui suit:

 {
    "query": {
        "filtered":{
            "filter": {
                "bool": {
                    "must_not": [
                        {
                            "missing":{
                                "field":"_textContent",
                                "existence":true,
                                "null_value":true
                            }
                        }
                    ]
                }
            }
        }
    }
}

Et les suivants:

   {
    "query": {
        "filtered":{
            "filter": {
                    "missing": {"field": "_textContent"}
            }
        }
    }
}

Aucun de ce qui précède n'a fonctionné. Je reçois un résultat vide quand je sais avec certitude qu'il existe des enregistrements contenant un champ de chaîne vide.

Si quelqu'un peut me fournir de l'aide, je vous en serai très reconnaissant.

Merci!

24
Paulo Victor

Si vous utilisez l'analyseur par défaut (standard), rien ne lui permet d'analyser s'il s'agit d'une chaîne vide. Vous devez donc indexer le champ textuellement (non analysé). Voici un exemple:

Ajoutez un mappage qui indexera le champ sans tabou. Si vous avez également besoin d’une copie sous forme de jetons du champ indexé, vous pouvez utiliser un Multi Field type. 

PUT http://localhost:9200/test/_mapping/demo
{
  "demo": {
    "properties": {
      "_content": {
        "type": "string",
        "index": "not_analyzed"
      }
    }
  }
}

Ensuite, indexez quelques documents. 

/POST http://localhost:9200/test/demo/1/
{
  "_content": ""
}

/POST http://localhost:9200/test/demo/2
{
  "_content": "some content"
}

Effectuer une recherche:

POST http://localhost:9200/test/demo/_search
{
  "query": {
    "filtered": {
      "filter": {
        "term": {
          "_content": ""
        }
      }
    }
  }
}

Renvoie le document avec la chaîne vide.

{
    took: 2,
    timed_out: false,
    _shards: {
        total: 5,
        successful: 5,
        failed: 0
    },
    hits: {
        total: 1,
        max_score: 0.30685282,
        hits: [
            {
                _index: test,
                _type: demo,
                _id: 1,
                _score: 0.30685282,
                _source: {
                    _content: ""
                }
            }
        ]
    }
}
18
Dan Tuffery

Même avec l’analyseur par défaut, vous pouvez effectuer ce type de recherche: utilisez un filtre script , qui est plus lent mais qui peut gérer la chaîne vide:

curl -XPOST 'http://localhost:9200/test/demo/_search' -d '
{
 "query": {
   "filtered": {
     "filter": {
       "script": {
         "script": "_source._content.length() == 0"
       }
     }
   }
 }
}'

Il retournera le document avec une chaîne vide sous la forme _content sans un mappage spécial.

Comme indiqué par @js_gandalf, ceci est obsolète pour ES> 5.0. A la place, vous devez utiliser: query-> bool-> filter-> script comme dans https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

10
VirgileD

Pour ceux d'entre vous qui utilisent une recherche élastique 5.2 ou supérieure et qui restent bloqués. Le moyen le plus simple est de réindexer correctement vos données avec le type de mot clé. Ensuite, toutes les recherches de valeurs vides ont fonctionné. Comme ça:

"query": {
    "term": {"MY_FIELD_TO_SEARCH": ""}
}

En fait, lorsque je réindexe ma base de données et réexécute la requête. Cela a fonctionné =)

Le problème était que mon champ était de type: texte et PAS un mot clé. Changement de l'index en mot clé et réindexation:

curl -X PUT https://username:[email protected]:9200/mycoolindex

curl -X PUT https://user:[email protected]:9200/mycoolindex/_mapping/mycooltype -d '{
  "properties": {
            "MY_FIELD_TO_SEARCH": {
                    "type": "keyword"
                },
}'

curl -X PUT https://username:[email protected]:9200/_reindex -d '{
 "source": {
   "index": "oldindex"
 },
 "dest": {
    "index": "mycoolindex"
 }
}'

J'espère que cela aidera quelqu'un qui était aussi bloqué que je trouvais ces valeurs vides.

4
js_gandalf

afin de trouver la chaîne vide d'un champ dans votre document, il est très important pour le mappage du champ, dans Word, son paramètre index/analyzer.

Si son index est not_analyzed, ce qui signifie que le jeton est simplement une chaîne vide, vous pouvez simplement utiliser la requête term pour le trouver, comme suit:

{"from": 0, "size": 100, "query":{"term": {"name":""}}}

Sinon, si le paramètre index est analyzed et que la plupart des analyseurs considèrent la chaîne vide comme une valeur nulle Sovous pouvez utiliser le filtre pour rechercher la chaîne vide.

{"filter": {"missing": {"existence": true, "field": "name", "null_value": true}}, "query": {"match_all": {}}}

voici le script Gist que vous pouvez référencer: https://Gist.github.com/hxuanji/35b982b86b3601cb5571

BTW, je vérifie les commandes que vous avez fournies, il semble que vous ne voulez PAS le document de chaîne vide . Et toutes mes commandes ci-dessus ne sont que pour les trouver, il suffit donc de le mettre dans la partie must_not de la requête bool irait bien .My ES est 1.0.1.


Pour ES 1.3.0, le Gist que j'ai fourni ne peut pas trouver la chaîne vide. Il semble que cela ait été rapporté: https://github.com/elasticsearch/elasticsearch/issues/7348 . Attendons de voir comment ça se passe.

Quoi qu'il en soit, il fournit également une autre commande pour trouver

{"requête": { "filtré": { "filtre": { "ne pas": { "filtre": { "intervalle": { "prénom": { } } } } } }}}

name est le nom du champ pour trouver la chaîne vide. Je l'ai testé sur ES 1.3.2.

2
hxuanji

J'utilise Elasticsearch 5.3 et j'avais des problèmes avec certaines des réponses ci-dessus.

Le corps suivant a fonctionné pour moi.

 {
    "query": {
        "bool" : {
            "must" : {
                "script" : {
                    "script" : {
                        "inline": "doc['city'].empty",
                        "lang": "painless"
                     }
                }
            }
        }
    }
}

Remarque: vous devrez peut-être activer le fielddata pour les champs de texte, il est désactivé par défaut. Bien que je lise ceci: https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata.html avant de le faire.

Pour activer le fielddata pour un champ, par exemple. 'ville' sur l'index 'entreprise' avec le nom de type 'enregistrement' dont vous avez besoin:

PUT business/_mapping/record
{
    "properties": {
        "city": {
          "type": "text",
          "fielddata": true
        }
      }
}
1
Glen Thompson

Si vous ne voulez pas ou ne pouvez pas réindexer, il existe un autre moyen. :-)

Vous pouvez utiliser l'opérateur de négation et un caractère générique pour faire correspondre toute chaîne non vide *

GET /my_index/_search?q=!(fieldToLookFor:*)
0
Andy Medlicott

Pour les champs imbriqués, utilisez:

curl -XGET "http://localhost:9200/city/_search?pretty=true" -d '{
     "query" : {
         "nested" : {
             "path" : "country",
             "score_mode" : "avg",
             "query" : {
                 "bool": {
                    "must_not": {
                        "exists": {
                            "field": "country.name" 
                        }
                    }
                 }
             }
         }
     }
}'

NOTE: chemin et champ constituent ensemble pour la recherche. Changer au besoin pour que vous travailliez.

Pour les champs réguliers:

curl -XGET 'http://localhost:9200/city/_search?pretty=true' -d'{
    "query": {
        "bool": {
            "must_not": {
                "exists": {
                    "field": "name"
                } 
            } 
        } 
    } 
}'
0
HBK

OU en utilisant la syntaxe de chaîne de requête lucene 

q =! (yourfield.keyword: "")

Voir Elastic Search Reference https://www.elastic.co/guide/fr/elasticsearch/reference/6.5/query-dsl-query-string-query.html#query-string-syntax

0
JammerUK

Solution trouvée ici https://github.com/elastic/elasticsearch/issues/7515 Cela fonctionne sans réindex.

PUT t/t/1
{
  "textContent": ""
}

PUT t/t/2
{
  "textContent": "foo"
}

GET t/t/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "exists": {
            "field": "textContent"
          }
        }
      ],
      "must_not": [
        {
          "wildcard": {
            "textContent": "*"
          }
        }
      ]
    }
  }
}
0
Serhiy Demydenko

Vous devez déclencher l'indexeur de mots clés en ajoutant .content à votre nom de champ. En fonction de la configuration de l'index d'origine, la procédure suivante "ne fonctionne" que pour moi à l'aide de AWS ElasticSearch v6.x.

GET /my_idx/_search?q=my_field.content: ""

0
John Robi

Je n'ai pas réussi à rechercher des chaînes vides dans un champ de texte. Cependant, il semble fonctionner avec un champ de type mot clé. Je suggère donc ce qui suit:

    delete /test_idx

    put test_idx
    {
      "mappings" : {
        "testMapping": {
          "properties" : {
            "tag" : {"type":"text"},
            "content" : {"type":"text",
                         "fields" : {
                           "x" : {"type" : "keyword"}
                         }
            }
          }
        }
      }
    }

put /test_idx/testMapping/1
{
  "tag": "null"
}

put /test_idx/testMapping/2
{
  "tag": "empty",
  "content": ""
}

GET /test_idx/testMapping/_search
{
   "query" : {
     "match" : {"content.x" : ""}}}
             }
}
0
Martin Maletinsky