Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Comment (ne pas réussir à) modéliser ses data d...

Comment (ne pas réussir à) modéliser ses data dans Elasticsearch

Présentation faite au BreizhCamp 2015 sur la modélisation des données dans Elasticsearch.

Bruno Bonnin

June 25, 2015
Tweet

More Decks by Bruno Bonnin

Other Decks in Programming

Transcript

  1. BreizhCamp 2015 #BzhCmp BreizhCamp 2015 #BzhCmp Comment (ne pas réussir

    à) modéliser ses data dans Elasticsearch! Bruno Bonnin - @_bruno_b_
  2. $ whoami Bruno Bonnin > Plus de 15 ans dans

    les télécoms (dev, archi, pompier) > Aujourd’hui @_bruno_b_ github.com/bbonnin
  3. 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
  4. 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)
  5. Alimentation Du Puits de données Focus : mises à jour

    du puits Contrats Personnes TEL LDAP JMS Fil de l’eau Batch
  6. « 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" : [ { … }, { … } ] } Doc Societaire
  7. « 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" : [ { … }, { … } ] } Doc Societaire Personnes Contrats Sinistres
  8. « 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" } } } } Mapping Query
  9. « 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 » ?
  10. « 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 » ?
  11. « Le truand » ? Un doc par objet source

    { "num_soc" : "1234", "nom" : "Haddock", "prenom" : "Archibald", "age" : 56 } Sociétaire { "num_contrat" : "6789", "type" : "auto", "immatriculation" : "1-AAA-99", "modele" : "peugeot 504", "num_soc" : "1234" } Contrat { "num_contrat" : "6789", … } Garantie { "num_soc" : "1234", … } Sinistre
  12. « Le truand » ? Un doc par objet source

    { "num_soc" : "1234", "nom" : "Haddock", "prenom" : "Archibald", "age" : 56 } Sociétaire { "num_contrat" : "6789", "type" : "auto", "immatriculation" : "1-AAA-99", "modele" : "peugeot 504", "num_soc" : "1234" } Contrat { "num_contrat" : "6789", … } Garantie Personne Contrats Contrats { "num_soc" : "1234", … } Sinistre Sinistres
  13. « 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 »
  14. « 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
  15. « 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
  16. « Le bon » ? Un mix nested et parent/child

    { "num_soc" : "1234", "nom" : "Haddock", "prenom" : "Archibald", "age" : 56 } Sociétaire { "num_contrat" : "6789", "type" : "maison", "bien" : { "type" : "chateau", "localisation" : "moulinsart" } "garanties" : [ {…}, {…} ] } Contrat
  17. « Le bon » ? Un mix nested et parent/child

    { "num_soc" : "1234", "nom" : "Haddock", "prenom" : "Archibald", "age" : 56 } Sociétaire { "num_contrat" : "6789", "type" : "maison", "bien" : { "type" : "chateau", "localisation" : "moulinsart" } "garanties" : [ {…}, {…} ] } Contrat 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
  18. « Le bon » ? Un mix nested et parent/child

    { "societaire" : { … }, "contrat" : { “_parent” : { "type" : “societaire“ }, "properties" : { “bien" : { "type" : "nested" }, “garanties" : { "type" : "nested" } } Mapping PUT /contrat/6789?parent=1234 { "num_soc" : "1234", "type" : "assur_maison", "bien" : { "type" : "chateau", "adresse" : "moulinsart", }, "garanties" : [] } Indexation Déclaration du parent
  19. « 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
  20. « 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
  21. 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
  22. 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