Elasticsearch
Différence entre les indices et les types
Recherche…
Remarques
Il est facile de voir les type comme une table dans une base de données SQL, où l' index est la base de données SQL. Cependant, ce n’est pas un bon moyen d’aborder le type s.
Tout sur les types
En fait, les types sont littéralement un champ de métadonnées ajouté à chaque document par Elasticsearch: _type . Les exemples ci-dessus ont créé deux types: my_type et my_other_type . Cela signifie que chaque document associé aux types a un champ supplémentaire défini automatiquement comme "_type": "my_type" ; Ceci est indexé avec le document, ce qui en fait un champ de recherche ou de filtrage , mais cela n’a pas d’impact sur le document brut lui-même, votre application n’a donc pas besoin de s’en préoccuper.
Tous les types vivent dans le même index, et donc dans les mêmes fragments collectifs de l'index. Même au niveau du disque, ils vivent dans les mêmes fichiers. La seule séparation fournie par la création d'un second type est une séparation logique. Chaque type, qu'il soit unique ou non, doit exister dans les mappages et tous ces mappages doivent exister dans votre état de cluster. Cela consomme de la mémoire et, si chaque type est mis à jour de manière dynamique, il réduit les performances à mesure que les mappages changent.
En tant que tel, il est recommandé de ne définir qu'un seul type, sauf si vous avez réellement besoin d'autres types. Il est courant de voir des scénarios où plusieurs types sont souhaitables. Par exemple, imaginez que vous avez un index de voiture. Il peut vous être utile de le décomposer en plusieurs types:
- BMW
- chevy
- honda
- Mazda
- mercedes
- nissan
- rangerover
- toyota
- ...
De cette façon, vous pouvez rechercher toutes les voitures ou les limiter par fabricant à la demande. La différence entre ces deux recherches est aussi simple que:
GET /cars/_search
et
GET /cars/bmw/_search
Ce qui n'est pas évident pour les nouveaux utilisateurs d'Elasticsearch, c'est que la seconde forme est une spécialisation de la première forme. Il est littéralement réécrit pour:
GET /cars/_search
{
"query": {
"bool": {
"filter": [
{
"term" : {
"_type": "bmw"
}
}
]
}
}
}
Il filtre simplement tout document non indexé avec un champ _type dont la valeur était bmw . Comme chaque document est indexé avec son type en tant _type champ _type , cela sert de filtre assez simple. Si une recherche réelle avait été fournie dans l'un ou l'autre exemple, le filtre serait alors ajouté à la recherche complète, le cas échéant.
Ainsi, si les types sont identiques, il est préférable de fournir un seul type (par exemple, le manufacturer dans cet exemple) et de l'ignorer efficacement. Ensuite, dans chaque document, fournissez explicitement un champ appelé make ou quel que soit le nom que vous préférez et filtrez-le manuellement chaque fois que vous souhaitez vous y limiter. Cela réduira la taille de vos mappages à 1/n où n est le nombre de types séparés. Il ajoute un autre champ à chaque document, au profit d'une cartographie autrement simplifiée.
Dans Elasticsearch 1.x et 2.x, un tel champ doit être défini comme
PUT /cars
{
"manufacturer": { <1>
"properties": {
"make": { <2>
"type": "string",
"index": "not_analyzed"
}
}
}
}
- Le nom est arbitraire.
- Le nom est arbitraire et il pourrait correspondre au nom du type si vous le vouliez également.
Dans Elasticsearch 5.x, ce qui précède fonctionnera toujours (il est obsolète), mais le meilleur moyen est d'utiliser:
PUT /cars
{
"manufacturer": { <1>
"properties": {
"make": { <2>
"type": "keyword"
}
}
}
}
- Le nom est arbitraire.
- Le nom est arbitraire et il pourrait correspondre au nom du type si vous le vouliez également.
Les types doivent être utilisés avec parcimonie dans vos index, car ils gonflent les mappages d'index, généralement sans grand bénéfice. Vous devez en avoir au moins un, mais rien ne dit que vous devez en avoir plus d’un.
Questions courantes
- Que se passe-t-il si j'ai deux types (ou plus) qui sont pour la plupart identiques, mais qui ont quelques champs uniques par type?
Au niveau de l'index, il n'y a pas de différence entre un type utilisé avec quelques champs peu utilisés et entre plusieurs types partageant un groupe de champs non fragmentés avec quelques champs non partagés (ce qui signifie que l'autre type n'utilise même pas le champ (s)).
Dit différemment: un champ peu utilisé est rare à travers l'index indépendamment des types . La rareté ne profite pas - ou ne fait vraiment pas mal - l’indice simplement parce qu’il est défini dans un type distinct.
Vous devez simplement combiner ces types et ajouter un champ de type distinct.
- Pourquoi des types distincts doivent-ils définir des champs exactement de la même manière?
Parce que chaque champ n'est réellement défini qu'une seule fois au niveau Lucene, quel que soit le nombre de types. Le fait que les types existent du tout est une caractéristique d'Elasticsearch et ne constitue qu'une séparation logique.
- Puis-je définir des types séparés avec le même champ défini différemment?
Non. Si vous parvenez à trouver un moyen de le faire dans ES 2.x ou version ultérieure, vous devez alors ouvrir un rapport de bogue . Comme indiqué dans la question précédente, Lucene les considère tous comme un seul champ, il n'y a donc aucun moyen de faire en sorte que cela fonctionne correctement.
ES 1.x en a fait une exigence implicite, ce qui permettait aux utilisateurs de créer des conditions dans lesquelles les correspondances d'une partition dans un index différaient réellement d'une autre partition du même index. C'était effectivement une condition de course et cela pouvait entraîner des problèmes imprévus.
Exceptions à la règle
- Les documents parent / enfant nécessitent des types distincts à utiliser dans le même index.
- Le parent vit dans un type.
- L'enfant vit dans un type distinct (mais chaque enfant vit dans le même fragment que son parent).
- Des cas d'utilisation extrêmement complexes où la création de tonnes d'indices est indésirable et l'impact de champs rares est préférable à l'alternative.
- Par exemple, le plug-in de surveillance Elasticsearch, Marvel (1.x et 2.x) ou X-Pack Monitoring (5.x +) surveille Elasticsearch lui-même pour détecter les modifications dans le cluster, les nœuds, les index, les index spécifiques (le niveau d'index), et même des éclats. Il pourrait créer plus de 5 index chaque jour pour isoler les documents ayant des correspondances uniques ou aller à l'encontre des meilleures pratiques pour réduire la charge du cluster en partageant un index (note: le nombre de mappages définis est le même, mais le nombre d'index créés est réduit de
nà 1). - Ceci est un scénario avancé, mais vous devez tenir compte des définitions de champs partagés entre les types!
- Par exemple, le plug-in de surveillance Elasticsearch, Marvel (1.x et 2.x) ou X-Pack Monitoring (5.x +) surveille Elasticsearch lui-même pour détecter les modifications dans le cluster, les nœuds, les index, les index spécifiques (le niveau d'index), et même des éclats. Il pourrait créer plus de 5 index chaque jour pour isoler les documents ayant des correspondances uniques ou aller à l'encontre des meilleures pratiques pour réduire la charge du cluster en partageant un index (note: le nombre de mappages définis est le même, mais le nombre d'index créés est réduit de
Créer explicitement un index avec un type
L'exemple utilise le protocole HTTP de base, qui se traduit facilement par cURL et d'autres applications HTTP. Ils correspondent également à la syntaxe Sense , qui sera renommée en console dans Kibana 5.0.
Remarque: L'exemple insère <#> pour attirer l'attention sur les pièces. Ceux-ci doivent être supprimés si vous le copiez!
PUT /my_index <1>
{
"mappings": {
"my_type": { <2>
"properties": {
"field1": {
"type": "long"
},
"field2": {
"type": "integer"
},
"object1": {
"type": "object",
"properties": {
"field1" : {
"type": "float"
}
}
}
}
}
},
"my_other_type": {
"properties": {
"field1": {
"type": "long" <3>
},
"field3": { <4>
"type": "double"
}
}
}
}
- Cela crée l'
indexutilisant le noeud final create index. - Cela crée le
type. - Les champs partagés dans le
types dans le mêmeindexdoivent partager la même définition! ES 1.x n'a pas strictement appliqué ce comportement, mais c'était une exigence implicite. ES 2.x et ci-dessus appliquent strictement ce comportement. - Les champs uniques à travers le
types sont corrects.
Les index (ou index) contiennent des types. Les types sont un mécanisme pratique pour séparer des documents, mais ils nécessitent que vous définissiez - dynamiquement / automatiquement ou explicitement - un mappage pour chaque type que vous utilisez. Si vous définissez 15 types dans un index, vous avez 15 mappages uniques.
Voir les remarques pour plus de détails sur ce concept et pourquoi vous pouvez ou non vouloir utiliser des types.
Création dynamique d'un index avec un type
L'exemple utilise le protocole HTTP de base, qui se traduit facilement par cURL et d'autres applications HTTP. Ils correspondent également à la syntaxe Sense , qui sera renommée en console dans Kibana 5.0.
Remarque: L'exemple insère <#> pour attirer l'attention sur les pièces. Ceux-ci doivent être supprimés si vous le copiez!
DELETE /my_index <1>
PUT /my_index/my_type/abc123 <2>
{
"field1" : 1234, <3>
"field2" : 456,
"object1" : {
"field1" : 7.8 <4>
}
}
- S'il existe déjà (à cause d'un exemple précédent), supprimez l'index.
-
my_indexun document dans l'index,my_index, avec le type,my_typeet l'IDabc123(peut être numérique, mais c'est toujours une chaîne).- Par défaut, la création d'index dynamique est activée en indexant simplement un document. Ceci est idéal pour les environnements de développement, mais ce n'est pas nécessairement bon pour les environnements de production.
- Ce champ est un nombre entier, donc la première fois qu'il est vu, il doit être mappé. Elasticsearch prend toujours le type le plus large pour tout type entrant, de sorte qu'il serait mappé comme un
longplutôt qu'unintegerou unshort(les deux pouvant contenir1234et456). - La même chose est vraie pour ce domaine également. Il sera mappé comme un
doubleplutôt que comme unfloatcomme vous le souhaitez.
Cet index et ce type créés dynamiquement correspondent approximativement au mappage défini dans le premier exemple. Cependant, il est essentiel de comprendre comment <3> et <4> affectent les mappages définis automatiquement.
Vous pouvez suivre cela en ajoutant un autre type dynamiquement au même index:
PUT /my_index/my_other_type/abc123 <1>
{
"field1": 91, <2>
"field3": 4.567
}
- Le type est la seule différence avec le document ci-dessus. L'identifiant est le même et ça va! Il n'a pas de relation avec l'autre
abc123n'est qu'il se trouve dans le même index. -
field1existe déjà dans l'index, il doit donc être du même type que celui défini dans les autres types. Soumettre une valeur qui était une chaîne ou non un entier échouerait (par exemple,"field1": "this is some text"ou"field1": 123.0).
Cela créerait dynamiquement les mappages pour my_other_type dans le même index, my_index .
Remarque: Il est toujours plus rapide de définir les mappages au lieu de demander à Elasticsearch de l'exécuter dynamiquement au moment de l'index.
Le résultat final de l'indexation des deux documents serait similaire au premier exemple, mais les types de champs seraient différents et par conséquent légèrement inutiles:
GET /my_index/_mappings <1>
{
"mappings": {
"my_type": { <2>
"properties": {
"field1": {
"type": "long"
},
"field2": {
"type": "long" <3>
},
"object1": {
"type": "object",
"properties": {
"field1" : {
"type": "double" <4>
}
}
}
}
}
},
"my_other_type": { <5>
"properties": {
"field1": {
"type": "long"
},
"field3": {
"type": "double"
}
}
}
}
- Cela utilise le point de terminaison
_mappingspour obtenir les mappages de l'index que nous avons créé. - Nous avons créé dynamiquement
my_typedans la première étape de cet exemple. -
field2est maintenant unlongau lieu d'unintegerparce que nous ne l'avons pas défini au départ. Cela peut s'avérer être un gaspillage de stockage sur disque. -
object1.field1est maintenant undoublepour la même raison que # 3 avec les mêmes ramifications que # 3.- Techniquement, un
longpeut être compressé dans beaucoup de cas. Cependant, undoublene peut pas être compressé car il s'agit d'un nombre à virgule flottante.
- Techniquement, un
- Nous avons également créé dynamiquement
my_other_typedans la deuxième étape de cet exemple. Sa cartographie se révèle être la même parce que nous utilisions déjà lelonget ledouble.- Rappelez-vous que
field1doit correspondre à la définition demy_type(et il le fait). -
field3est unique pour ce type, il n'a donc pas cette restriction.
- Rappelez-vous que