Normaliser une adresse avec ElasticSearch et la base adresse nationale

Il y a fort fort longtemps, j’intégrais la base adresse nationale dans elasticsearch via logstash. Je ne suis pas allé plus loin faute de temps et peut-être d’envie.

Que peut-on faire avec ces quelques gigas de données me direz vous?

  • Faire des recherches pour avoir les coordonnées géographiques d’une adresse donnée
  • Faire une recherche pour avoir l’adresse normalisée
  • Faire un rapprochement avec d’autres données (avec Spark par exemple)
  • Sans doute plein d’autres use cases

Je vais m’attarder sur le deuxième point. A quoi ça sert ? et bien à avoir une adresse « propre » et utilisable par un système d’information (ex. ce que font les impôts, ou amazon). Il existe quelques solutions propriétaires qui réalisent ceci et sont assez chers. Je me suis donc mis dans la tête de le faire via elasticsearch.

Rappels des épisodes précédents

Voici le schéma de l’architecture

Présentation1

Pré-requis

Configuration Logstash

Voici ma configuration Logstash

J’ai configuré LOGSTASH pour réaliser les actions suivantes :

  • extraction des données d’un fichier
  • suppression de la ligne d’en-tête
  • gestion de la localisation avec un champ de type ‘geo_point’.

C’est assez simple (pour l’instant)

Mapping ELASTICSEARCH

Analyzers

J’ai configuré les analyzers de la manière suivante:

J’ analyse tous les mots (whitespace tokenizer) en minuscule en appliquant un filtre (ngram) permet de rechercher par caractère (ex. imp au lieu de impasse).

La c’est super couteux en espace disque et impose un plus gros traitement lors de l’insertion mais permet d’ alléger le temps de traitement des requêtes ( le gros du travail est fait lors du chargement).

Mapping

La je n’ai pas fait grand chose de particulier si ce n’est le typage des différents champs (ex. la localisation )

Création de l’index

Dans sense ou via cUrl, lancer la commande suivante :

Pour le mapping complet, voir sur mon compte github

Chargement

voir mon article précédent

Interrogation

Maintenant je peux interroger mon index

Imaginons que je fasse saisir le code postal, la ville et l’adresse et que j’interroge elasticsearch pour obtenir une adresse normalisée

Conclusion

Ce n’est qu’un début. Ce n’est sans doute pas encore très performant, si vous avez des remarques, n’hésitez pas. En tout cas, les briques et outils décrits ci-dessus permettent de normaliser des adresses a minima avec des logiciels libres, ce qui n’est pas rien.

Les sources sont disponibles sur GITHUB. Je ne pense pas que je vais en faire un projet à proprement parler mais plutôt d’une boîte à outils pour manipuler ce genre de données. J’y ajouterai sans doute quelques recherches géospatiales et peut être l’ intégration de graph.

Utilisation de spark en mode streaming

Après avoir intégré toutes les briques dans docker, il ne me « restait » plus qu’à coder la brique permettant de me connecter à une queue MQTT et d’insérer des données dans Elasticsearch.

 

Spark-logo-192x100px

J’ai décidé d’utiliser Apache Spark. Ce composant remplace Hadoop pour les traitements map reduce et permet d’exécuter ce genre de traitement dans plusieurs typologies d’environnement ( batch, cluster spark, cluster hadoop,…).

J’aime bien ce framework car il offre différentes possibilités et permet via un simple batch ( commande java -jar ) de lancer des traitements map reduce performants avec différents langages (scala, java,python, R).

Pour ce faire j’ai aussi décidé d’utiliser le langage SCALA. Spark est développé sur ce langage et fournit plus de fonctionnalités en scala que sur les autres.

Connexion à une queue MQTT

Sauvegarde dans Elasticsearch

Elasticsearch fournit une API permettant à des dérivés d’Hadoop de se connecter à un cluster Elasticsearch. L’utilisation est des plus simples.

Le programme

J’ai volontairement crée plus de variables qu’il ne faut car j’ai pas mal mis de logs 🙂

Je vais essayer de mettre mon code sur github prochainement.

 

 

 

 

 

 

 

Docker compose

Me voilà avec mes images docker réalisées. Maintenant, il faut les lier entre elles et packager le tout.

J’ai choisi d’utiliser docker-compose. c’est l’outil standard fourni par docker. Sa principale lacune est que cet outil ne s’exécute que localement. En gros, on ne pourra pas utiliser docker-compose pour exécuter de manière distribuée les différents containers (ex. la base de données sur un nœud, le serveur web sur un autre,…). Pour mon POC je n’ai pas trop besoin de ça et, il faut le dire, j’ai un peu la flemme d’installer des softs comme kubernetes.

Je ne décrirai pas l’installation. C’est beaucoup mieux fait ici.

Je mettrai prochainement le code sur github. Je pense que le code sera mis à jour ultérieurement. Il se peut donc que certains exemples de cet articles soient obsolètes.

Définition des différents composants

J’ai trois composants :

  • une instance rabbitmq qui réceptionne des messages via le protocole MQTT
  • elasticsearch qui stocke les différents évènements et les mets à disposition
  • un programme s’appuyant sur spark-streaming qui se connecte à rabbitmq , transforme les évènements réceptionnés et les envoient dans elasticsearch.

La spécification des différents composants se fait par un fichier docker-compose.yml qui est dans le répertoire racine.

Je spécifie les images que je souhaite construire, les ports exposés et les variables d’environnement

Le fichier docker-compose.yml

elasticsearch

J’ai surchargé l’image officielle d’elasticsearch en ajoutant un fichier de configuration personnalisé et en installant le plugin shield et marvel. Voici le dockerfile:

Rabbitmq

Ici j’ai souhaité ajouter deux utilisateurs au démarrage du container

La configuration se fait dans le fichier init.sh

Spark

Enfin mon code scala qui exécute SPARK est packagé sous qui la forme d’un JAR qui contient toutes les dépendances.

Le dockerfile correspondant

Je ne décrirai pas le code ici. Peut-être dans un futur article.

Construction

Exécution

Créer une image docker d’elasticsearch avec marvel préinstallé

Je fais suite à un précédent post sur elasticsearch et docker.

Il existe déjà des images docker pré configurées avec elasticsearch et marvel. Cependant, il n’en existe pas d’officielles et celle qu’il y a ne me conviennent pas trop.

J’ai décidé de créer une image se basant sur une archive de marvel pré-téléchargée.

Dans un répertoire, j’ai ajouté un répertoire install_plugins avec le zip de marvel installé ( je pourrai installer ensuite les plugins shield et license)

Voici le contenu du fichier Dockerfile:

 

Elasticsearch avec Docker

Comme évoqué dans un précédent article, j’ai décidé de me mettre (modestement) à Docker. Comme je devais utiliser elasticsearch pour un projet, j’ai dit pourquoi pas utiliser l’image docker. Voici les actions que j’ai réalisé et le (petit) problème vite résolu.

 

elasticdocker

Installation

Que du simple et du basique. elastic.co fournit une image officielle.

Problème de binding réseau

Si je démarre l’instance de manière classique, j’ai un petit soucis de binding réseau. En effet, l’instance Docker positionne le hostname à 172.17.0.1 et … ça occasionne quelques soucis lors de l’appel à mon cluster (ex.: timeout, impossibilité de joindre le cluster, catastrophe nucléaire,…).

Si on exécute la requête suivante : http://localhost:9200/_nodes/process?pretty on obtient :

Bref, ça ne le fait pas. Pour pouvoir utiliser cette image sans avoir à créer ma propre image, j’ai donc positionné les variables HOSTNAME, es.network.bind_host et es.network.host au démarrage de la machine.

Maintenant j’ai la configuration suivante :

Intégrer la base adresse nationale dans Elasticsearch

L’état fourni désormais via sa plateforme OPENDATA son référentiel des adresses du territoire français.

Si vous souhaitez avoir plus d’informations sur la démarche OPENDATA, vous pouvez consulter cette page.

Cette base est issue des données de l’IGN, de la poste, des collectivités territoriales ou encore de la communauté openstreetmap.

Chaque adresse contient le nom normalisé ainsi que les coordonnées .

Voici le descriptif des données.

Les cas d’utilisation de ces données sont nombreux. L’un deux pourrait être de les utiliser dans les recherches d’adresses. Il faudrait charger ses données dans un moteur de recherche (ELASTICSEARCH par ex.)  et de rechercher la présence d’une adresse avec pondération selon plusieurs critères ( avec filtres, recherches complexes ) et d’obtenir l’adresse normalisée et les coordonnées géographiques .

Je vais essayer de décrire les actions que j’ai réalisé pour intégrer ces données.

Architecture mise en œuvre

Présentation1

Les fichiers CSV sont placés dans un répertoire. L’archive téléchargeable contient un fichier CSV par département.

LOGSTASH joue ici pleinement le rôle d’un ETL.

Configuration LOGSTASH

La configuration est assez simple. Il suffit de savoir configurer le plugin CSV de LOGSTASH.

 ELASTICSEARCH

Le mapping généré par LOGSTASH est assez basique mais permet déjà de réaliser pas mal de requêtes. On peut également brancher KIBANA pour analyser plus finement les données.

Voici un exemple de recherche que l’on peut exécuter :

J’essaierai dans un prochain article e brancher kibana sur cet index pour avoir plus de stats.

Installation et configuration du plugin shield

Dans le cadre d’un projet de mise en oeuvre d’un moteur de recherche, on s’est attardé sur la sécurité du moteur elasticsearch.shield-triad

ce dernier dispose pour peu qu’on prenne le support d’un plugin gérant la sécurité des index : shield.

  • Ce plugin permet de sécuriser les cluster et index ELASTICEARCH. Il apporte
  • Identification et gestion des ACLS sur les cluster et index
  • IP Filtering
  • Audit
  • Cryptage des échanges

La documentation est très bien faite. Voici les actions que j’ai réalisé pour installer le tout

Installation plugin license et shield

Génération des clés privées/publiques

Création des utilisateurs

Configuration marvel

Puis indiquer dans le fichier elasticsearch.yml, le moyen de se connecter

Configuration pour une connexion LDAP

Redémarrage

Au redémarrage, vous obtiendrez cette erreur

Pour ça, je ne peux pas vous aider, il faut souscrire à un contrat de support 🙂

Mettre en oeuvre rapidement l’ autocomplétion avec Elasticsearch

Le mécanisme d’auto complétion peut se réaliser assez facilement dans elasticsearch avec les suggestions.

Voici un exemple simple d’auto complétion

Prérequis

Voici un schéma de démo que j’ai crée et des exemples

Création de l’index

Configuration de l’autocomplétion

Il faut assigner un champ de type completion dans le mapping

Test

Insertion des données

Exemple de recherche

Requête

Résultat

J’essaierai dans un prochain article d’intégrer une auto complétion plus intelligente , basée sur les phrases notamment.

Insérer des données issues d’un fichier CSV dans ELASTICSEARCH

Un cas que j’ai du implémenter avec le même schéma que précédemment:

workflow

Prendre des fichiers CSV en entrée et les insérer facilement dans ELASTICSEARCH au fil de l’eau.  J’ai donc utilisé LOGSTASH pour réaliser cette manipulation.

Cet outil sert à la base comme agrégateur de logs. Il est désormais un mini ETL .

Configuration de LOGSTASH

Explication
Dans le champ input, je spécifie ou est le fichier, ou est l’indicateur de parcours et ou est-ce que je démarre la lecture du fichier

Dans le champ filter , j’ enlève la ligne d’en-tête, puis dans l’élément csv, je spécifie les colonnes et supprime les champs techniques

Enfin, dans l’élément output, j’indique les coordonnées du serveur elasticsearch

Exécution
Il faut d’abord exécuter elasticsearch. Puis démarrer l’instance logstash comme suit :

Charger des documents JSON dans ELASTICSEARCH via LOGSTASH

Me voila avec ma stack ELK fraîchement installée. formation-elasticsearch.png

Voici un cas d’utilisation assez simple :Je recherche à insérer au fil de l’eau des documents JSON dans l’index ELASTICSEARCH. Pour ceci on peut le faire de plusieurs manières :

  • Utiliser un ETL (ex. TALEND)
  • Utiliser un programme manipulant l’API ELASTICSEARCH
  • Utiliser LOGSTASH

Cette dernière brique était dans un premier temps dédiée aux LOGS. Dorénavant, elle se rapproche d’un ETL.

Voici le cas (assez simple j’en conviens) que je vais mettre en place

Screen_Shot_10-30-14_at_04.42_PM.PNG

Configuration de LOGSTASH

LOGSTASH s’exécute dans mon cas comme un agent. Il faut créer le fichier de configuration suivant dans le répertoire /etc/logstash/conf.d :

Dans le premier bloc (input) je spécifie que je cherche à traiter les fichiers json qui sont dans mon répertoire et qu’ils sont multilignes.

Ensuite dans le bloc filter , j’applique une transformation pour les mettre en JSON. Enfin dans le dernier bloc ( output) j’affiche dans la sortie standard ( stdout() ) le résultat et je charge dans elasticsearch le document JSON ainsi chargé.

Chargement des données Il faut pour cela redémarrer logstash

Et logiquement, vous devriez voir dans les logs d’ELASTICSEARCH des lignes qui ressemblent à ça

http://127.0.0.1:9200/index/document/_search ///

Visualisation dans KIBANA

Je ne décrirais pas cette partie car je suis encore en cours d’exploration. Voici néanmoins un bon point de départ pour ceux que ça intéresse