breizhcamp 2015 - comment (ne pas réussir à) modéliser ses data dans elasticsearch
TRANSCRIPT
BreizhCamp 2015 #BzhCmp BreizhCamp 2015 #BzhCmp
Comment (ne pas réussir à)
modéliser ses data dans
Elasticsearch!
Bruno Bonnin - @_bruno_b_
$ whoami
Bruno Bonnin
> Plus de 15 ans dans les télécoms (dev, archi, pompier)
> Aujourd’hui @_bruno_b_ github.com/bbonnin
Il était une fois un assureur…
Le contexte
Contrats Personnes TEL LDAP
Copie entre
systèmes
Navigation
entre clients
Le puits de données avec Elastic !
Contrats Personnes TEL LDAP
Search-based Apps
Consultation uniquement,
les systèmes d’origine
restent maîtres de la
donnée
ELK : La triplette de la mort !
Quelques questions à se poser…
• Les usages ? Partiellement connus… • Vue 360° du sociétaire • Recherche sur des référentiels • Ça arrive au fur et à mesure…
• Quelles données ? Toutes (ou presque) !
• De multiple sources de données, complexes à croiser
• Des contraintes techniques ? Système des
mises à jour imposé ! • Messages générés à partir des updates issus des différents
système, sans garanti d’ordre • Problème potentiel de mises à jour des documents dans ES
(cas nested : conteneur de la donnée pas encore présente dans le puits)
Alimentation
Du
Puits de
données
Focus : mises à jour du puits
Contrats
Personnes
TEL
LDAP
JMS
Fil
de l’e
au
Batc
h
Quel modèle pour elastic ?
Sinistres TEL Contrats
Personnes
?
« La brute » ? Un seul type de document !
{
"nom" : "Haddock",
"prenom" : "Archibald",
"age" : 56,
"contrats" : [
{
"formule" : "assur_auto",
"bien" : {
"immatriculation" : "1-AAA-99",
"modele" : "peugeot 504",
}
"garanties" : [ ... ],
},
{ … }
],
"sinistres" : [
{ … }, { … }
]
}
Do
c S
ocie
taire
« La brute » ? Un seul type de document !
{
"nom" : "Haddock",
"prenom" : "Archibald",
"age" : 56,
"contrats" : [
{
"formule" : "assur_auto",
"bien" : {
"immatriculation" : "1-AAA-99",
"modele" : "peugeot 504",
}
"garanties" : [ ... ],
},
{ … }
],
"sinistres" : [
{ … }, { … }
]
}
Do
c S
ocie
taire
Personnes
Contrats
Sinistres
« La brute » ? Un seul type de document !
{
"query" : {
"nested" : {
"path" : "contrats",
"query" : {
"bool" : {
"must" : [ {
"match" : {
"contrats.formule" : “assur_auto"
},
"match" : {
"contrats.bien.modele" : "peugeot 504"
}
]
}
}
}
}
}
}
{
"societaire" : {
"properties" : {
"contrats" : {
"type" : "nested ",
"properties" : {
"formule" : {
"type" : "string“
},
"bien" : { … },
…
}
},
"sinistres" : {
"type" : "nested"
}
}
}
}
Mappin
g
Query
« La brute » ? Un seul type de document !
Avantage(s) : • Avec une seule requête, on récupère
l’ensemble des données d’un sociétaire • Requêtes complexes sur les sous-documents Désavantage(s) : • La mise à jour !
• Temps de ré-indexation • Complexité (quid des messages concernant un sous-
partie sans le document conteneur ?)
• Vue orientée « sociétaire » : quid des use cases orientés « contrat » ?
« La brute » ? Un seul type de document !
Avantage(s) : • Avec une seule requête, on récupère
l’ensemble des données d’un sociétaire • Requêtes complexes sur les sous-documents Désavantage(s) : • La mise à jour !
• Temps de ré-indexation • Complexité (quid des messages concernant un sous-
partie sans le document conteneur ?)
• Vue orientée « sociétaire » : quid des use cases orientés « contrat » ?
« Le truand » ? Un doc par objet source
{
"num_soc" : "1234",
"nom" : "Haddock",
"prenom" : "Archibald",
"age" : 56
}
So
cié
taire
{
"num_contrat" : "6789",
"type" : "auto",
"immatriculation" : "1-AAA-99",
"modele" : "peugeot 504",
"num_soc" : "1234"
}
Contr
at
{
"num_contrat" : "6789",
…
} Gara
ntie
{
"num_soc" : "1234",
…
}
Sin
istr
e
« Le truand » ? Un doc par objet source
{
"num_soc" : "1234",
"nom" : "Haddock",
"prenom" : "Archibald",
"age" : 56
}
So
cié
taire
{
"num_contrat" : "6789",
"type" : "auto",
"immatriculation" : "1-AAA-99",
"modele" : "peugeot 504",
"num_soc" : "1234"
}
Contr
at
{
"num_contrat" : "6789",
…
} Gara
ntie
Personne
Contrats
Contrats
{
"num_soc" : "1234",
…
}
Sin
istr
e
Sinistres
« Le truand » ? Un doc par objet source
GET /societaire,contrats/_search
{
"query" : {
“term" : {
“num_soc" : “1234"
}
}
}
Query
… {
"_index" : “assureur",
"_type" : "contrats",
"_id" : "2045",
"_score" : 4.4011974,
"_source“ : {
"num_contrat" : "2045",
"num_soc" : “1234",
"type" : "assur_maison",
"bien" : {
"type" : "chateau",
"adresse" : “moulinsart"
}
}
} ]
}
"hits" : {
"total" : 2,
"max_score" : 4.417726,
"hits" : [ {
"_index" : “assureur",
"_type" : "societaire",
"_id" : "45",
"_score" : 4.417726,
"_source“ : {
"num_soc" : “1234",
"nom" : "haddock"
}
}, …
Result
Recherche sur 2 types de docs en
utilisant le champ commun
« num_soc »
« Le truand » ? Un doc par objet source
Avantage(s) :
• Facile à mettre à jour (1 type de doc
correspond à 1 type de message)
Désavantage(s) :
• Requêtage : devient vite complexe pour
avoir une information complète • Multiplication des requêtes côté client pour
reconstituer le modèle
« Le truand » ? Un doc par objet source
Avantage(s) :
• Facile à mettre à jour (1 type de doc
correspond à 1 type de message)
Désavantage(s) :
• Requêtage : devient vite complexe pour
avoir une information complète • Multiplication des requêtes côté client pour
reconstituer le modèle
« Le bon » ? Un mix nested et parent/child
{
"num_soc" : "1234",
"nom" : "Haddock",
"prenom" : "Archibald",
"age" : 56
}
So
cié
taire
{
"num_contrat" : "6789",
"type" : "maison",
"bien" : {
"type" : "chateau",
"localisation" : "moulinsart"
}
"garanties" : [ {…}, {…} ]
}
Contr
at
« Le bon » ? Un mix nested et parent/child
{
"num_soc" : "1234",
"nom" : "Haddock",
"prenom" : "Archibald",
"age" : 56
}
So
cié
taire
{
"num_contrat" : "6789",
"type" : "maison",
"bien" : {
"type" : "chateau",
"localisation" : "moulinsart"
}
"garanties" : [ {…}, {…} ]
}
Contr
at
Personnes
Contrats
parent=1234 Relation parent/child entre des docs
liés mais vivant indépendamment
Contrat complet avec nested docs
car forte dépendance
« Le bon » ? Un mix nested et parent/child
{
"societaire" : { … },
"contrat" : {
“_parent” : {
"type" : “societaire“
},
"properties" : {
“bien" : {
"type" : "nested"
},
“garanties" : {
"type" : "nested"
}
}
Mappin
g
PUT /contrat/6789?parent=1234
{
"num_soc" : "1234",
"type" : "assur_maison",
"bien" : {
"type" : "chateau",
"adresse" : "moulinsart",
},
"garanties" : []
}
Indexation
Déclaration du parent
« Le bon » ? Un mix nested et parent/child
GET /societaire/_search
{
“query” : {
“has_child" : {
“type” : “contrat”,
"query" : {
"match" : {
“bien.adresse" : “moulinsart"
}
}
},
"inner_hits" : {}
}
}
}
Query
…
"inner_hits" : {
"contrats" : {
"hits" : {
"total" : 1,
"max_score" : 3.4336133,
"hits" : [ {
"_index" : “assureur",
"_type" : "contrat",
"_id" : “6789",
"_score" : 3.4336133,
"_source“ : {
"num_contrat" : “6789",
"num_soc" : “1234",
"type" : "assur_maison",
"bien" : {
"type" : "chateau",
"adresse" : "moulinsart"
}
} } ]
{
"_index" : “assureur",
"_type" : "societaire",
"_id" : “1234",
"_score" : 1.0,
"_source“ : {
"num_soc" : “1234",
"nom" : "haddock"
},
…
Result
« inner_hits » (new 1.5) :
permet d’avoir les contrats
en plus des sociétaires
dans le résultat
« Le bon » ? Un mix nested et parent/child
Avantage(s) :
• Modèle permettant de répondre à la plupart des usages
(orienté sociétaire ou contrat)
• Séparation de documents ayant des cycles de vie
différents
• Avec inner_hits, capacité à retrouver des documents liés
entre eux facilement
Désavantage(s) :
• Requêtes plus lentes pour les docs liés par une lien
parent/enfant
• Elastic met en mémoire la table des liens
Cluster Elastic
Architecture
Nœud sans
data Nœud data 1 Nœud data 2
Shield
Marvel
Alim puits de
données 1
Alim puits de
données 2
JMS
…
Taille des index (mesure PoC) : 400 Go
En résumé
Penser « usages » est primordial !
Utiliser les nested documents pour des données ayant
un lien fort, avec le même cycle de vie
• Ne pas hésiter à dupliquer
Utiliser les liens parents/enfants sur les documents
pouvant vivre indépendamment les uns des autres
• Requêtes avec « inner_hits »
Tenir compte des contraintes techniques de votre env
MERCI !
Crédit photos : https://www.flickr.com/photos/hoyvinmayvin