Il était une fois : un conte de fées élastique !

Il était une fois…

En fait, il y a 2 ans, je cherchais un moyen pour distribuer Hibernate search sur plusieurs noeuds. Ma première idée était de stocker les index dans une base de données partagée par les différents noeuds. Oui ! Il s’agit d’une idée stupide en terme de performances, mais j’avais envie d’essayer et de construire ce modèle.

Après avoir cherché du code source, je suis finalement tombé sur la classe JdbcDirectory du projet Compass. Et sur la page d’accueil du projet, j’aperçois quelque chose qui parle du future de Compass et d’Elasticsearch.

The future of compass and Elasticsearch

Deux clics plus tard, je découvre Elasticsearch. Je le télécharge, le démarre et me dis : « Bordel ! Mais comment est-ce possible ? ». Ce projet venait non seulement de résoudre tous mes problèmes en ajoutant des fonctionnalités dont je n’avais même pas conscience, le tout en moins de 30 secondes ! Je n’ai pas dormi pendant une semaine entière, vraiment ! C’était trop magique pour être vrai ! Après quelques heures de travail, Elasticsearch était intégré dans mon projet et fournissait déjà les premières recherches full text. J’ai dit à mes collègues que ce projet est si magnifique que je veux en faire parti si un jour une société est créée.

A partir de ce moment, j’ai cherché comment contribuer en retour sur le projet. Mais, je n’étais ni un expert Elasticsearch, ni même un expert Lucene. J’ai alors cherché du contenu français parlant du projet et je n’ai trouvé qu’un ou deux articles. J’ai commencé alors à écrire du contenu sur mon blog personnel. J’ai également commencé à écrire quelques plugins. La rivière RSS fut la première. Elle fut d’ailleurs mon premier projet open-source.

J’ai rencontré Shay Banon la première fois en Juin 2011 pour une conférence donnée à Paris. Il donnait un talk sans slides comme il sait les faire. Très impressionnant ! It just works ! Je lui ai alors dit que comme je ne pouvais pas directement contribuer au coeur du projet, je pouvais essayer de promouvoir le projet en France. Il a immédiatement accepté. La communauté française était née !

Elasticsearch French Community

 

Une année plus tard, mon talk pour Devoxx France était accepté et tout allait vraiment démarrer à partir de là. Le groupe français n’a pas cessé de grossir depuis, de jour en jour.

Quelques mois plus tard, la société Elasticsearch BV était créée. Il était vraiment clair dans mon esprit que je devais les rejoindre. Quand vous tombez amoureux, vous devez vous marier ! J’ai rencontré à nouveau Shay à Devoxx 2012 et nous en avons parlé, notamment de ce que je pourrais apporter à Elasticsearch. Et maintenant, deux ans après ma première rencontre avec Elasticsearch, mon rêve devient réalité, comme dans les contes de fées !

Protéger son cluster Elasticsearch avec Jetty

Nativement, Elasticsearch expose l’ensemble de ses services sans aucune authentification et donc une commande du type curl -XDELETE http://localhost:9200/myindex peut faire de nombreux dégâts non désirés.

De plus, si vous développez une application JQuery avec un accès direct depuis le poste client à votre cluster Elasticsearch, le risque qu’un utilisateur joue un peu avec votre cluster est grand !

Alors, pas de panique… La société Sonian Inc. a open sourcé son plugin Jetty pour Elasticsearch pour notre plus grand bonheur ;-)

Principe

Le principe consiste à rajouter une surcouche Jetty à Elasticsearch, sous forme de plugin.

Il ne reste plus qu’à restreindre certaines URL et certaines méthodes (DELETE par exemple) à certains utilisateurs.

Guide d’installation

Pour installer le plugin, connectez vous à votre serveur hébergeant Elasticsearch et allez dans le répertoire d’installation :

Installez le plugin (vérifiez la compatibilité entre la version du plugin et celle de votre noeud) :

Récupérez le fichier de configuration de jetty proposé par Sonian en exemple :
Idem pour le fichier avec les logins / password :

Il faut ensuite modifier la configuration Elasticsearch et ajouter la ligne suivante dans config/elasticsearch.yml :

Les petits gars de Sonian ayant très bien fait leur boulot, les protections nécessaires sont déjà en place avec le fichier config/jetty.xml très complet.

Modifiez les valeurs par défaut de login/password dans config/realm.properties :

Redémarrez Elasticsearch. Si vous l’avez installé en tant que service :

Et voilà ! Impossible de faire des commandes du type :

Mais avec authentification, ça passe :

Mon talk sur Elasticsearch sélectionné pour Devoxx France

Bonjour,

C’est avec une certaine émotion et fierté que j’ai appris samedi dernier la sélection de mon talk sur Elasticsearch à Devoxx France.

Devoxx France est une conférence organisée du 18 au 20 avril 2012 à Paris, pour les Développeurs. Y faire parti au milieu de talents incroyables est vraiment un honneur.

Je suis d’autant plus comblé que je vais pouvoir parler du sujet qui me passionne depuis maintenant 1 an : Elasticsearch.

A l’origine, Shay Banon devait venir lui-même nous parler de l’analyse des données avec les facettes Elasticsearch, mais il ne pourra malheureusement pas être présent.

  • Le moins : vous n’avez pas en face de vous le BIG BOSS ! :-(
  • Le plus : la conférence est en français ;-)

Mon objectif pour ce talk est de vous faire partager mon enthousiasme pour ce projet magnifique, de faire décoller la communauté française @ElasticsearchFR et de susciter des engouements à utiliser, forker et contribuer !

 

Je vais principalement présenter les fonctionnalités d’Elasticsearch que j’utilise tous les jours, parler un peu architecture, insister sur la partie facette (navigation par facettes) et faire quelques démos live… Je vais d’ailleurs avoir besoin de votre concours pour faire un « maximum de bruit » sur Twitter pendant la conf !

Pour le moment, le slot de la conférence est le jeudi 19 avril à partir de 11H30.

Réservez votre journée ! Venez nombreux !

Quel client Java pour ElasticSearch ?

Il existe deux modes d’accès à Elasticsearch :

  • Inscrire un noeud client dans le cluster ElasticSearch
  • Utiliser un client « simple »

Noeud client dans un cluster Elasticsearch

L’idée de cette méthode est de fabriquer un noeud Elasticsearch (node) qui démarre avec les mêmes caractéristiques qu’un noeud d’indexation et de recherche sauf qu’on lui précise qu’il n’hébergera pas de données.

Pour cela, on utilise la propriété suivante :


node.data=false

Elle indique que le noeud que nous démarrons n’hébergera pas de données. En gros, c’est un noeud qui sert juste à fabriquer des clients…

L’avantage est qu’il n’est pas nécessaire de configurer quoi que ce soit car la particularité des noeuds Elasticsearch est de s’auto-découvrir les uns les autres grâce aux fonctions de multicast.

Démarrer un noeud autonome est également intéressant pour réaliser des tests unitaires. En effet, dans ce cas, vous avez une instance autonome complète d’Elasticsearch.

Démarrer un noeud et obtenir un client, ce n’est pas bien difficile :


// Build a node
Node node = NodeBuilder.nodeBuilder().node();

// Get a client from the node
Client client = node.client();

Avec la première ligne, vous devriez voir apparaître dans les logs de vos noeuds Elasticsearch, le fait qu’un nouveau noeud a rejoint le cluster.

Client « simple » ou TransportClient

Un Transport Client est un client Elasticsearch autonome plus léger qui n’appartient pas réellement au cluster de noeuds Elasticsearch. Ainsi, lorsqu’un client démarre, aucune trace n’apparaît dans les logs des noeuds du cluster puisque ce client ne fait pas proprement parti du cluster.

Pour qu’un tel client sache comment trouver des noeuds Elasticsearch du cluster que vous souhaitez rejoindre, il faut lui indiquer au moins une adresse. Vous pouvez préciser plusieurs adresses pour mieux gérer les pannes et la répartition de charge.

Pour démarrer un tel client, on écrit donc :


TransportClient client = new TransportClient()
.addTransportAddress(new InetSocketTransportAddress("localhost", 9300))
.addTransportAddress(new InetSocketTransportAddress("localhost", 9301));

Quel client choisir ?

Passer par un noeud pour obtenir un client peut perturber votre cluster, même si en théorie, ça devrait être neutre. Car le noeud fait partie du cluster. Donc, quand il meurt, les autres noeuds doivent être prévenus pour prendre des décisions. En l’occurrence, aucune décision à prendre car le noeud n’héberge pas de données. Mais cela nécessite un traitement même minime de la part des noeuds.

De la même façon quand un noeud arrive dans le cluster, il se déclare, occupe deux ports de communication (9200-9299 et 9300-9399) car en tant que noeud il peut être amené à recevoir des requêtes.

De plus, un noeud ElasticSearch démarre plus de Threads et notamment un qui pose problème en ce moment en raison d’un souci avec la librairie Guava. En mode debug sous Eclipse par exemple, cela va vous empêcher de redémarrer proprement votre webapp sans avoir à redémarrer le serveur d’application.

En production, c’est pareil. Si vous embarquez dans votre webapp un noeud client Elasticsearch, vous devrez obligatoirement redémarrer le serveur d’application sous peine d’erreur de mémoire (OOM).

Donc, mon expérience m’indique qu’il vaut mieux passer par des clients plus légers et neutres pour le cluster. J’ai donc choisi dans mes projets la deuxième option lorsque j’ai besoin d’un client dans une webapp.

Lorsque je veux faire des tests unitaires (ou d’intégration) de mon application, j’utilise plutôt la première méthode.

Et il y a un moyen de choisir quand je veux ce que je veux ?

Dans un prochain article, je vous décrirai la factory Spring que j’ai développée et publiée sur github.

La version n’est pas encore finalisée, notamment en raison d’un petit bug avec la version 0.19.0.RC2 d’Elasticsearch, mais la version SNAPSHOT est en cours de tests dans un de mes projets.

Mon premier plugin ElasticSearch : RSS River

Il existe dans ElasticSearch la notion de river (rivière) qui comme son nom le laisse supposer permet de voir s’écouler des données depuis une source jusqu’à ElasticSearch.

Au fur et à mesure que les données arrivent, la rivière les transporte et les envoie à l’indexation dans Elastic Search.

En standard, il existe 4 rivières :

  • CouchDB qui permet d’indexer toutes les nouveautés d’une base CouchDB. Voir aussi cet article à ce propos.
  • RabbitMQ qui permet de récupérer des documents dans une queue de traitement asynchrone (genre JMS)
  • Twitter qui permet d’indexer votre flux de messages twitter par exemple
  • Wikipedia qui permet d’indexer toutes les nouveautés de l’encyclopédie au fur et à mesure de leurs publications

Premiers pas

J’ai commencé par bidouiller un peu la rivière CouchDB pour y apporter quelques fonctionnalités dont mes collègues avaient besoin :

Finalement, le principe se révèle assez simple. Il faut une classe qui implémente River et qui hérite de AbstractRiverComponent.

Là, il ne reste plus qu’à implémenter :

  • Le constructeur
  • La méthode start qui se lance quand la rivière démarre
  • La méthode close qui se lance lorsque la rivière stoppe

Et mon flux RSS alors ?

Oui… J’y viens…

Au fait, tout le monde sait ce qu’est un flux RSS ? La spécification officielle est ici.

Je reprends donc le plugin CouchDB River, je le mavenise (ouais, je ne suis pas encore super fan de Gradle), et je l’adapte à mes besoins.

Pour faire simple, je vais suivre la mécanique suivante :

  • Toutes les x minutes, je télécharge le flux RSS demandé que je transforme en POJO en me basant sur le travail fait par Lars Vogel
  • Je compare la date du flux (balise pubDate) avec la dernière date de flux (que j’avais stockée dans ElasticSearch)
  • Si le flux est plus récent, je parcours tous les éléments du flux (item)
    • Je fabrique un identifiant de l’item basé sur un encodage du champ description. Pour cela, je me sers de ce qui est déjà présent dans ES.
    • Si cet identifiant a déjà été envoyé à ES, alors on ignore cet item.
    • Sinon, on le pousse vers ElasticSearch dans un document de type « page »

Les champs récupérés pour le moment dans le flux RSS sont :

  • title
  • description
  • author
  • link

Ca marche ?

Mes profs en école d’ingé me disaient : « non ! ça fonctionne… »

Bon, une fois le plugin publié sous github, il est simple de l’utiliser.

Tout d’abord, on l’installe :

$ bin\plugin -install dadoonet/rssriver/0.0.1

Puis, on démarre ES et on créé notre index pour stocker le flux RSS :

$ curl -XPUT 'http://localhost:9200/lemonde/' -d '{}'

Puis on ajoute la rivière :

$ curl -XPUT 'http://localhost:9200/_river/lemonde/_meta' -d '{
  "type": "rss",
  "rss": {
    "url": "http://www.lemonde.fr/rss/une.xml"
  }
}'

Et voilà…

A partir de ce moment, on peut faire des recherches dans le flux… Par exemple :

$ curl –XGET 'http://localhost:9200/lemonde/_search?q=taxe'

On peut jouer sur les paramètres de la rivière en modifiant les paramètres url pour l’adresse du flux et update_rate pour la fréquence de mise à jour du flux (en millisecondes).

Egalement, il peut être souhaitable (conseillé) de modifier le mapping par défaut du type « page » :

$ curl -XPUT 'http://localhost:9200/lefigaro/' -d '{}'

$ curl -XPUT 'http://localhost:9200/lefigaro/page/_mapping' -d '{
  "page" : {
    "properties" : {
      "title" : {"type" : "string", "analyzer" : "french"},
      "description" : {"type" : "string", "analyzer" : "french"},
      "author" : {"type" : "string"},
      "link" : {"type" : "string"}
    }
  }
}'

$ curl -XPUT 'localhost:9200/_river/lefigaro/_meta' -d '{
  "type": "rss",
  "rss": {
    "url": "http://rss.lefigaro.fr/lefigaro/laune",
    "update_rate": 900000
  }
}'

Et maintenant ?

Que vais-je faire de tout ce temps ? Que sera ma vie ?

J’envisage de faire une nouvelle évolution du plugin CouchDB car pour le moment, il ne traite pas la récupération des pièces jointes (format binaire).

Et bien évidemment, poursuivre sur le plugin RSS River qui doit traiter d’autres balises et être testé avec d’autres flux…

D’ailleurs, si vous l’utilisez et que vous rencontrez des problèmes, n’hésitez pas à contribuer en créant des bugs ou en forkant et améliorant le projet.

Les sources sont ici : https://github.com/dadoonet/rssriver

 

 

ElasticSearch et les « facets »

Les aventures avec ElasticSearch se poursuivent.

Combien de fois ai-je dit récemment que ce projet est absolument génial et qu’il va constituer à mon sens un des projets majeurs des prochaines années…

Qui n’a pas besoin de moteur de recherche ? Qui s’est déjà « emmerdé » à fabriquer ça lui-même ou à utiliser des briques pouvant aider au prix d’une complexité plus ou moins grande de mise en oeuvre ?

Je crois que nous sommes tous passés par là !!!

Et là, ce projet permet en quelques heures (minutes) de faire tourner un moteur de recherche complet…

Les facettes (facets)

Bref, là n’est pas mon propos d’aujourd’hui. Le thème du jour est la notion de facets. Je l’ai testé en quelques minutes sur une base de 1,5 millions de documents indexés à mon boulot. Résultat bluffant !

Une facette permet d’ajouter des informations à un résultat de recherche. Imaginez un site marchand. Vous cherchez un ou plusieurs mots, par exemple : rasoir.

Le site vous fournit une liste des éléments correspondants et en général ajoute des informations pour vous aider à affiner votre recherche.

Par exemple, le nom des fabricants de ces produits avec le nombre d’objets trouvés pour les 10 principaux fabricants. Dans notre cas, on pourrait avoir par exemple :

  • Tous (134)
  • Philips (35)
  • Braun (21)
  • Calor (12)

Ce résultat qui décore notre résultat de recherche se nomme une facette (facet in english).

Il existe différents types de facettes. Celle dont nous venons de parler est une facette de type TERMS, c’est à dire qu’Elastic Search va renvoyer la distribution des 10 principaux termes trouvés pour une propriété donnée des documents par rapport à une requête.

{
    "query" : {
        "match_all" : { }
    },
    "facets" : {
        "tag" : {
            "terms" : {
                "field" : "tag",
                "size" : 10
            }
        }
    }
}

En passant une requête de ce type, on obtiendra la consolidation et le comptage associé de tous les principaux termes du champ tag de toute notre base de documents.

Il existe d’autres types de facettes très intéressantes :

  • les facettes RANGE : pour donner une distribution sur un intervale de valeurs. Par exemple, pour reprendre notre exemple de site marchand, vous pouvez utiliser la facette RANGE pour donner la distribution des prix pour les intervales de 0 à 10 €, de 10 à 20 €, de 20 à 50 € et au delà de 50 €.
  • les facettes DATE HISTOGRAM : pour donner un comptage avec un axe X des temps (période à décider : jour, mois, année, …). Par exemple, le nombre de vente par mois pour un produit donné.

La liste complète est disponible sur le site d’Elastic Search.

Et les résultats ?

Là où cela devient très fort, c’est que cette recherche s’exécute en temps réel, même sur des données « neuves » qui arrivent en permanence et avec un temps de réponse assez incroyable.

A titre d’exemple, sur la base de 1,5 millions de documents que je citais plus haut en début de document, j’ai pu ainsi faire un outil d’analyse rapidement (à peine 4 heures de boulot – et encore, c’est juste parce que je ne suis pas assez bon en Javascript !) sur des déclarations en douane. Ce qui est surprenant, c’est que sans avoir fait le moindre effort d’optimisation, nous avons pu regarder l’effet des saisons sur l’importation de tomates au fur et à mesure des années et sur les TOP 10 des pays d’importation !

Pour réaliser cela, je n’ai fait que suivre l’excellent article sur le blog d’elastic search. Je ne peux pas malheureusement pas vous montrer le résultat :-( Mais sachez que cela réagit en quelques secondes sur un poste bureautique avec peu de mémoire. Alors, imaginez si vous mettez cela en production avec 16 ou 32 Go de RAM distribué sur plusieurs noeuds !!!

Vous pouvez également utiliser le résultat des facettes comme point d’entrée ergonomique pour filtrer ensuite le résultat de vos recherches : un clic sur le nom du fabriquant du produit fera par exemple la même recherche dans Elastic Search avec en plus un filtre posé sur le nom du fabriquant.

Quelle(s) conclusion(s) en tirer ?

Bon, j’ai un peu bluffé dans mon premier exemple… La possibilité d’avoir la somme totale de tous les résultats ( Tous (134)  ) n’existe pas encore. Shay Banon, l’auteur du projet, a accepté ma demande d’évolution #1029 à ce sujet. Pour le moment, il faut faire un calcul à la main (enfin, en javascript je veux dire) !

Dans la même requête, vous pouvez associer plusieurs facettes d’un seul coup. Dans mon cas de démo au boulot, j’ai mis 5 facettes. Un appel = les 10 premiers résultats de ma recherche plus 5 facettes d’analyse des données…

Sinon, oubliez les requêtes SQL que vous faites tourner pendant quelques minutes pour vous fabriquer vos statistiques. Oubliez les moteurs de recherche en SQL (si ! si ! ça existe encore !). Je me demande du coup quel sera le devenir de projets comme Hibernate Search ? Même si avec la sortie d’Hibernate OGM, on sent une tentative astucieuse de garder la communauté des développeurs Hibernate. Pour ma part, j’avais commencé à écrire un plugin Hibernate pour Elastic Search mais finalement je l’ai supprimé de mon projet car il n’apporte quasiment que des contraintes pour le peu d’intérêt qu’il apporte. Une vraie novation pourrait être d’ajouter à Hibernate Search un stockage des données dans Elastic Search, mais Shay Banon a un point de vue divergent sur les annotations utilisées. Du coup, un projet (OSEM) soutenu par Shay a vu le jour grâce à l’excellent travail d’Aloïs Cochard. Une fois stabilisé, ce projet rejoindra le projet Elastic Search afin de proposer des annotations standards pour vos objets Java à rendre cherchables (Searchable).

De mon côté, je réfléchis au développement d’un simple plugin maven pour générer automatiquement les fichiers de mapping pour Elastic Search basés sur les entités annotées Searchable. A suivre donc !

Installez chez vous Elastic Search et testez juste en ligne de commande (avec des curl) ces fonctionnalités et dites vous que le petit résultat que vous observez sur quelques documents tient autant la route sur une forte volumétrie… C’est la puissance de Lucene associée à l’ingéniosité de l’auteur d’Elastic Search qui met ainsi à notre disposition un outil simple, basé sur des technos simples mais au combien efficace !!!

Je vous ai dit que j’adore ce projet ???? ;-)

CouchDB

Après avoir testé ElasticSearch, me voici parti pour regarder ce monde étrange qu’on appelle le NoSQL

A dire vrai, j’ai entendu ce mot il y a quelques années, sans jamais vraiment m’y interesser… Après tout, une base de données non SQL, ça n’est tout simplement pas possible !!!

Puis, à force de cotoyer le monde d’ElasticSearch et les technos JSon et REST, je me lance.

Pour des raisons très pratiques, je choisis CouchDB de Apache. D’une part, il est directement intégrable avec ElasticSearch, et à la lecture rapide de sa documentation, il semble répondre à un des besoins auquel une équipe de mon pôle de développement est confrontée.

Notre besoin (résumé) :

  • Archiver des données de notre SI afin notamment de décharger les bases live (Front Office).
  • Historiser ces données
  • Y associer des pièces jointes (vues PDF et XML)
  • Etre en mesure d’y accéder facilement
  • Prévenir des consommateurs de ces documents qu’il y a des nouveautés à récupérer et à traiter (Décisionnel)
  • Etre en mesure de rechercher ces documents

Au début, les équipes ont pensé mettre en place des copies via des fichiers XML dans des répertoires partagés depuis les applications Front Office (live), puis des scripts shell pour recopie dans des espaces propres à chaque consommateur de données qui traitera ensuite les flux à son rythme. Sans entrer dans les détails, c’est un peu genre « je fais tout moi-même à la main, comme je l’aurais fait en 1995″…

Depuis le monde a un peu changé, non ?

Alors, que peut faire CouchDB pour nous :

  • Stocker des documents (format JSON)
  • Y associer des pièces jointes (PDF et XML)
  • Le tout avec un mode de transport simple : HTTP / REST
  • Gestion d’un flux type RSS pour informer n’importe qui de toutes les modifications apportées à la base
  • Gestion des révisions de chaque document
  • Non adhérence à un format particulier (contrairement aux SGBD-R)
  • Capacité de stockage et de montée en charge
  • Réplication ultra simple
  • Partitionnement

Bon, ça c’est sur le papier… Rien ne vaut un bon test…

On se lance donc avec un ami pour mettre en place une plate-forme de test.

Nous partons d’une base de données disposant de plusieurs millions d’enregistrements divers (sous Oracle). Notre objectif :

  • Les lire avec un DAO classique dans Oracle
  • JSONiser chaque entité
  • La transformer aussi en une vue XML (module déjà existant)
  • La transformer aussi en une vue PDF (nous avons déjà développé tout cela avant)
  • Envoyer le tout à CouchDB.

Il faut 5 minutes pour installer CouchDB (grand max !), 20 minutes pour comprendre que le firewall de Microsoft n’est pas notre ami et que nous avons intérêt à ouvrir le port CouchDB si nous voulons pouvoir communiquer avec CouchDB depuis une autre machine !

On lance le batch sur une machine et on envoie vers un CouchDB… Là, tranquille, au rythme de 15-20 documents par seconde, notre base se remplit petit à petit !

On consulte un document JSON ainsi : http://couchdb/index/ref000000001/

Si on veut prendre la version PDF, c’est beaucoup plus compliqué : http://couchdb/index/ref000000001/ref000000001.pdf

Je passe la version XML… C’est aussi compliqué !

 

Au bout de 50 000 documents, nous nous lançons un nouveau défi : répliquer sur une autre instance CouchDB.

Installation de CouchDB sur une autre machine. Cette fois, on ne perd pas de temps pour le firewall : on sait directement où enlever le blocage…

Puis on se connecte sur l‘interface de gestion de CouchDB et on demande une réplication de la première machine vers la deuxième… Il faut 10 secondes pour configurer cela. C’est vraiment trop simple pour fonctionner directement ! Mais, si ! Ca fonctionne !

La réplication commence… 20 à 50 documents répliqués par seconde… Le tout sur un PC assez lent. On est loin des conditions de PROD !

En même temps, notre BATCH continue à alimenter la première instance.

 

Arrivés à 100 000 documents, nous n’en n’avons pas assez !!!

Nous décidons de nous lancer un nouveau défi. Il nous reste 10 minutes avant une réunion de présentation de ces concepts à notre management. Nous avons largement le temps !

Alors, nous décidons de lancer un noeud ElasticSearch sur une machine et d’y ajouter le plugin river CouchDB. Puis nous activons ce plugin pour ouvrir une rivière (river) vers la première instance de CouchDB… Et là, encore un miracle… Nos documents se déversent sans aucun effort dans ElasticSearch.

Nous avons donc au final, au bout d’une demi journée d’efforts surhumains (fallait quand même développer le batch initial), atteint nos objectifs.

 

Reste à regarder cette histoire de flux RSS (sorte d’inscription aux nouveautés de la base). Cela est nativement porté par la fonction _changes de CouchDB. C’est absolument génial. Comme si vous aviez un trigger permanent et automatique sur chaque modification apportée dans la base. Avec la possibilité de faire un appel à _changes en précisant là où nous en étions la dernière fois que nous y avons fait appel (gestion différentielle), ou encore mieux, de façon continue, de laisser en permanence un flux HTTP ouvert dans lequel se déverse au fil de l’eau chaque changement apporté…

C’est vraiment bluffant et simplissime à l’usage.

 

C’en est tellement facile que cela paraît suspect…

Les prochains tests sont maintenant de faire monter la volumétrie à quelques millions de données pour voir comment cela se passe…

 

La suite au prochain numéro !

 

La recherche élastique…

En cherchant un bout de code pour rendre la couche Hibernate Search facilement distribuable sur un cluster de machines JBoss, je suis tombé sur le projet ElasticSearch.

Au début, un peu interloqué… Puis, je me lance…

Je télécharge le projet. Je dézippe.

Je lance…

Miracle. En quelques secondes, je dispose d’un outil dans un Cloud, simple, me permettant d’indexer n’importe quel type de document, de le récupérer et de faire une recherche (au sens google du terme) sur n’importe quel champ… Et cela, quelque soit la technologie employée (Java, C#, .Net, Php, à la main, …).

La simplicité repose sur l’intégration de quelques technologies simples et éprouvées : JSon, REST, Lucene.

Là, où cela devient très fort, c’est lorsque vous démarrez sur une seconde machine dans le même réseau, une autre instance d’Elastic Search… Et là : réplication automatique. Votre nouvelle instance fait parti du Cloud…

Sans rien faire… Presque magique.

Lorsque vous montez encore 2 autres instances (ça peut être sur la même machine – les ports d’écoute s’adaptent automatiquement), alors Elastic Search réparti l’indexation sur plusieurs machines…

La Team est très active. Il suffit de regarder la fréquence des commits sur github. Elle fournit un composant Java simple à utiliser.

En deux lignes, on se connecte au cloud (sans trop savoir à quelle machine exactement, le principal étant de trouver un service), et on envoie nos demandes d’indexation ou de recherche…

Je vous recommande fortement de regarder de très près ce projet qui va rapidement s’imposer comme une référence.

Pour ma part, je travaille en ce moment à développer une méthode très simple pour interfacer automatiquement et de façon transparente l’indexation des entités gérées par Hibernate. L’idée est de pousser les entités Hibernate à chaque fois qu’elles sont insérées, mises à jour ou effacées vers Elastic Search plutôt que vers Hibernate Search. Le tout avec très peu d’annotations.

Plus d’informations dans quelques jours je pense…

Installation FusionForge 5.0 sur Redhat 5

Voici la suite de l’article sur l’installation d’une forge.

Finalement, le temps d’obtenir une machine sous Redhat 5 a laissé le temps à la team FusionForge de sortir une release finale de la version 5.0.

Nous voilà donc lancés dans cette installation que je me propose de décrire ici.

A noter que pour le moment la forge n’est pas totalement opérationnelle. Des évolutions dans la configuration devront être menées et j’espère pouvoir tenir à jour cet article pour les décrire.

Processus d’installation

Préinstallation

Création du sous-domaine

Il faut choisir un nom « agréable » pour la machine et le déclarer dans le DNS. Dans le reste du document, on considère qu’on installe la forme sous le nom maforge.mondomaine.

Espace disque

Il est recommandé également de prévoir un espace disque suffisant pour la forge en montant par exemple un disque sur une baie SAN. Dans le reste du document, on considère que le répertoire disponible est /maforge.

Configuration YUM pour internet

Les scripts d’installation nécessitent d’avoir un accès à internet pour télécharger à l’aide de yum les modules nécessaires pouvant manquer dans l’installation par défaut de la machine. Pour cela, si il est nécessaire de passer par un proxy, le déclarer dans yum.conf sous la forme d’une ligne :

proxy=http://adresseipproxy:port/

Téléchargement de la distribution fusionforge

Les packages à télécharger pour installer la forge sont disponibles à l’adresse :

http://fusionforge.org/frs/?group_id=6

A noter que le document présent est basé sur la version 5.0 de la forge. Il est conseillé de prendre la version notée « allinone ».

Dans la suite, on considère qu’on a téléchargé le fichier : fusionforge-5.0-allinone.tar.bz2

Processus d’installation

Une fois le fichier d’installation téléchargé, le déposer dans un répertoire temporaire de la machine, par exemple : /tmp

Puis en tant qu’utilisateur root :

cd /tmp
bunzip2 fusionforge-5.0-allinone.tar.bz2
tar xf fusionforge-5.0-allinone.tar

On doit se retrouver avec un répertoire /tmp/fusionforge-5.0

cd /tmp/fusionforge-5.0
install.sh maforge.modomaine

Ce script exécute l’installation de la forge :

  • Téléchargement des dépendances (via le script fusionforge-install-1-deps.php)
  • Installation des scripts de la forge, des répertoires, … (via le script fusionforge-install-2.php)
  • Création de la base de données (fusionforge-install-3-db.php)

Lors de l’installation, le script demande d’entrer le nom de l’utilisateur administrateur de la forge et son mot de passe.

Note :

Lors de l’installation, le script semble ne pas avoir complètement fonctionné correctement. Des analyses sont en cours.

De ce fait, un démarrage manuel de la base postgres a dû être effectué à l’aide la commande suivante.

/etc/rc.d/init.d/postgresql start

Une fois ces opérations menées, il doit être possible d’ouvrir un navigateur web à l’adresse :

http://maforge.modomaine/

Page d'accueil de la forge

Processus post-installation

Déplacement des fichiers sur la baie SAN

La forge s’installe dans ses répertoires par défaut. En attendant que la communauté de développeur de la forge rende paramétrable les répertoires, un certain nombre d’action sont nécessaires pour déplacer les répertoires d’installation vers un disque adéquat (sur la baie SAN par exemple).

Pour faire ces déplacements, il est nécessaire de stopper la base de données :

/etc/rc.d/init.d/postgresql stop

Le tableau ci-dessous donne les répertoires par défaut d’installation de la forge et les répertoires cibles vers lesquels on souhaite se déplacer.

Répertoire origine Répertoire destination Commentaire
/opt/gforge /maforge/fforge50 Contient les sources, les scripts php, bref, toute le « programme » forge
/var/lib/gforge /maforge/files Contient les répertoires de travail (svn, uploads, …)
/var/lib/pgsql /maforge/pgsql Contient la base de données
/etc/gforge /maforge/conf Contient la configuration (forge, apache, plugins)
/opt/groups /maforge/groups ???

Pour déplacer les fichiers, faire :

mkdir /maforge/conf
mv /etc/gforge/* /maforge/conf/
rmdir /etc/gforge
ln -s /maforge/conf/ /etc/gforge

mkdir /maforge/pgsql
mv /var/lib/pgsql/* /maforge/pgsql/
mv /var/lib/pgsql/.bash_profile /maforge/pgsql/
rmdir /var/lib/pgsql
ln -s /maforge/pgsql/ /var/lib/pgsql

mkdir /maforge/files
mv /var/lib/gforge/* /maforge/files/
rmdir /var/lib/gforge
ln -s /maforge/files/ /var/lib/gforge

mkdir /maforge/fforge50
mv /opt/gforge/* /maforge/fforge50/
rmdir /opt/gforge
ln -s /maforge/fforge50/ /opt/gforge

mkdir /maforge/groups
mv /opt/groups/* /maforge/groups/
rmdir /opt/groups
ln -s /maforge/groups/ /opt/groups

Puis redémarrer postgres :

/etc/rc.d/init.d/postgresql start

Patch sur les répertoires SVN et CVS

L’installation de la forge semble poser des problèmes sur Redhat 5 et CentOS 5 car des répertoires attendus par la forge ne sont pas créés. Il faut donc, créer des liens symboliques pour corriger ce problème :

ln -s /maforge/files/svnroot /maforge/files/svn
ln -s /maforge/files/cvsroot /maforge/files/cvs
ln -s /maforge/files /scmrepos
ln -s /maforge/files/svnroot /svnroot
ln -s /maforge/files/cvsroot /cvsroot

Installation BIND et configuration DNS (PROVISOIRE/EN COURS)

La forge doit gérer elle-même ses DNS afin de pouvoir déclarer chaque nouveau projet dans son espace propre (par exemple nomprojet.maforge.mondomaine).

Pour cela, une délégation de DNS doit être réalisée par le DNS principal du domaine mondomaine pour laisser le service BIND de la forge gérer le sous-domaine maforge.mondomaine.

Il faut donc également installer le service BIND sur la forge et le configurer.

Note : A compléter

Voir aussi : https://fusionforge.org/docman/view.php/6/1/gforge_manual.plain.html#id2623367