Comment rechercher toutes les valeurs uniques d'un champ donné avec Elasticsearch?
J'ai un genre de requête comme select full_name from authors
, afin que je puisse afficher la liste aux utilisateurs sur un formulaire.
Vous pouvez faire un facette des termes sur votre champ 'full_name'. Mais pour le faire correctement, vous devez vous assurer que vous ne le jetez pas lors de l'indexation, sinon chaque entrée dans la facette sera un terme différent qui fait partie du contenu du champ. Vous devrez probablement le configurer comme "non_analysé" dans votre mappage. Si vous le recherchez également et que vous souhaitez toujours le symboliser, vous pouvez simplement l'indexer de deux manières différentes en utilisant multi-champ .
Vous devez également tenir compte du fait que, selon le nombre de termes uniques faisant partie du champ full_name, cette opération peut être coûteuse et nécessiter une quantité de mémoire importante.
Pour Elasticsearch 1.0 et versions ultérieures, vous pouvez tirer parti de terms aggregation
pour faire ça,
requête DSL:
{
"aggs": {
"NAME": {
"terms": {
"field": "",
"size": 10
}
}
}
}
Un vrai exemple:
{
"aggs": {
"full_name": {
"terms": {
"field": "authors",
"size": 0
}
}
}
}
Ensuite, vous pouvez obtenir toutes les valeurs uniques du champ authors
. taille = 0 signifie que le nombre de termes ne doit pas être limité (cela nécessite que la version soit 1.1.0 ou ultérieure).
Réponse:
{
...
"aggregations" : {
"full_name" : {
"buckets" : [
{
"key" : "Ken",
"doc_count" : 10
},
{
"key" : "Jim Gray",
"doc_count" : 10
},
]
}
}
}
Les réponses existantes ne fonctionnaient pas pour moi dans Elasticsearch 5.X, pour les raisons suivantes:
"size": 0
N'a pas pu analyser car "[la taille] doit être supérieure à 0".full_name
. Cependant, un champ keyword
non analysé peut être utilisé pour les agrégations. Solution 1 : utilisez Scroll API . Il fonctionne en conservant un contexte de recherche et en effectuant plusieurs demandes, renvoyant à chaque fois des lots de résultats ultérieurs. Si vous utilisez Python, le module elasticsearch a la fonction d'assistance scan()
pour gérer le défilement à votre place et renvoyer tous les résultats.
Solution 2 : utilisez Search After API . Il est similaire à Scroll, mais fournit un curseur en direct au lieu de conserver un contexte de recherche. Il est donc plus efficace pour les demandes en temps réel.
Intuition: Dans le langage SQL:
Select distinct full_name from authors;
est équivalent à
Select full_name from authors group by full_name;
Ainsi, nous pouvons utiliser la syntaxe de regroupement/agrégat dans ElasticSearch pour trouver des entrées distinctes.
Supposons que la structure stockée dans la recherche élastique soit la suivante:
[{
"author": "Brian Kernighan"
},
{
"author": "Charles Dickens"
}]
Ce qui n'a pas fonctionné: Agrégation simple
{
"aggs": {
"full_name": {
"terms": {
"field": "author"
}
}
}
}
J'ai eu l'erreur suivante:
{
"error": {
"root_cause": [
{
"reason": "Fielddata is disabled on text fields by default...",
"type": "illegal_argument_exception"
}
]
}
}
Ce qui a fonctionné comme un charme: Ajout . Mot clé avec le champ
{
"aggs": {
"full_name": {
"terms": {
"field": "author.keyword"
}
}
}
}
Et l'exemple de sortie pourrait être:
{
"aggregations": {
"full_name": {
"buckets": [
{
"doc_count": 372,
"key": "Charles Dickens"
},
{
"doc_count": 283,
"key": "Brian Kernighan"
}
],
"doc_count": 1000
}
}
}
Astuce bonus:
Supposons que le champ en question soit imbriqué comme suit:
[{
"authors": [{
"details": [{
"name": "Brian Kernighan"
}]
}]
},
{
"authors": [{
"details": [{
"name": "Charles Dickens"
}]
}]
}
]
Maintenant, la bonne requête devient:
{
"aggregations": {
"full_name": {
"aggregations": {
"author_details": {
"terms": {
"field": "authors.details.name"
}
}
},
"nested": {
"path": "authors.details"
}
}
},
"size": 0
}
Travailler pour Elasticsearch 5.2.2
curl -XGET http://localhost:9200/articles/_search?pretty -d '
{
"aggs" : {
"whatever" : {
"terms" : { "field" : "yourfield", "size":10000 }
}
},
"size" : 0
}'
Le "size":10000
signifie obtenir (au plus) 10000 valeurs uniques. Sans cela, si vous avez plus de 10 valeurs uniques, seules 10 valeurs sont renvoyées.
Le "size":0
signifie qu'en résultat, "hits"
ne contiendra aucun document. Par défaut, 10 documents sont retournés, dont nous n'avons pas besoin.
Référence: agrégation des termes du compartiment
Notez également que, selon cette page , les facettes ont été remplacées par des agrégations dans Elasticsearch 1.0, qui sont un surensemble de facettes.