Publié par
Il y a 10 années · 6 minutes · Java / JEE

Introduction à Hibernate Search (Googling your Persistent Domain Model)

J’ai eu l’occasion courant décembre de rencontrer Emmanuel Bernard [1] pour, entre autres, une présentation d’Hibernate Search.

La vulgarisation et la généralisation de l’utilisation des moteurs de recherche ont définitivement changé les habitudes et les exigences des utilisateurs. Pourquoi la fonctionnalité de recherche d’une application de gestion ne serait-elle pas aussi simple et performante que Google ?
Difficile d’expliquer à son responsable que cela est dû à une divergence de paradigme entre l’indexation documentaire et SQL.
Hibernate Search vise à répondre à cette question, à moindre coût, en s’appuyant sur Apache Lucene afin d’offrir au travers du modèle de persistance d’Hibernate des capacités de recherche full-text.

Réconcilier la recherche full-text et les modèles de persistance relationnels

Par nature, SQL nous limite à l’écriture de requête de recherche par mot (par terme) avec l’aide éventuelle de wildcard (‘%’, ‘?’).
La recherche SQL sur un modèle relationnel n’offre pas (ou en tout cas pas sans de très gros efforts) un ensemble de capacités dignes d’un moteur de recherche moderne :

  • L’approximation qui permet de s’affranchir des fautes de frappe (Ex : « xebi » -> « xebia »).
  • La recherche par synonyme qui permet de remonter des résultats pertinents mais ne contenant pas le terme recherché (En SQL, « JEE » est différent de « J2EE »).
  • La recherche par proximité (Ex : « persistance java » -> « Hibernate »).
  • Le classement des résultats par pertinence (result scoring).
  • La recherche multi-colonnes.

Ces fonctionnalités sont traditionnellement offertes par les solutions de recherche full-text qui s’appuient sur l’utilisation d’index inversés. Malheureusement, de telles solutions se marient souvent mal avec les systèmes de bases de données relationnelles en raison de décalages entre les deux paradigmes :

  • Un déséquilibre structurel tout d’abord : Les index full-text ne sont que du texte. Ils ne reflètent pas une quelconque structuration des données. De plus, ils ne permettent pas de gérer des relations entre les documents.
  • De plus, le mariage des deux systèmes pose des problèmes de synchronisation : comment s’assurer que le contenu de la base de données et l’index documentaire sont à jour et cohérents l’un vis-à-vis de l’autre ?
  • Enfin, les résultats de recherches full-text sont des documents. En effet, les index ne stockent pas d’objets. Encore moins des objets « managés ».

A cela s’ajoute des problèmes de portabilité et de flexibilité dus au fait que la plupart des implémentations ne sont que des surcouches propriétaires au dessus du SQL.

L’objet d’Hibernate Search est de résoudre ces décalages et de réconcilier la recherche full-text et les modèles de persistance relationnels. Pour ce faire, Hibernate Search se base sur Apache Lucene, un moteur d’indexation et de recherche full-text standalone très puissant, mais plutôt bas niveau (et donc facile à mal utiliser).
Hibernate Search permet ainsi d’utiliser les capacités d’Apache Lucene dans le cadre d’une couche de mapping Hibernate.

Architecture

Hibernate Search est donc un moteur d’indexation et de recherche full-text reposant sur Apache Lucene. Il prend ainsi en charge la gestion d’un index Lucene et sa synchronisation avec une structure objet persistée en base de données.

La mise à jour de l’index est déclenchée au travers de la capture d’événements JPA : quand une entité est insérée, mise à jour ou supprimée en base de données, Hibernate Search récupère l’événement et programme une mise à jour de l’index. Cette mise à jour est effectuée de façon transparente par Hibernate Search et ne nécessite pas l’utilisation directe des API Lucene.
Par souci d’efficacité, les opérations d’écritures dans l’index Lucene sont traitées par lots. Le traitement de ces lots s’inscrit dans la transaction courante. De cette façon, la mise à jour de l’index n’est déclenchée que si celle-ci est « commitée », permettant ainsi de garantir l’ACID-ité du système.

La recherche dans l’index se fait au travers des APIs }}org.hibernate.Query ou javax.persistence.Query{{ de la même façon que l’on écrirait des requêtes natives, HQL ou JPA-QL. Une requête de recherche Hibernate Search retourne une liste d’entités « managées » sans que le développeur ait à se soucier du fastidieux travail de mapping Objet <-> Document Lucene.

Le traitement des opérations de mise à jour de l’index peut être traité par différents backend en fonction de l’architecture et des scénarii mis en place. Hibernate Search propose deux « backend sur étagère » : Un backend Lucene (synchrone) et un backend JMS (asynchrone).

Backend synchrone

Ce mode est le plus simple : toutes les opérations de mise à jour de l’index sont traitées par le nœud (la JVM) à l’origine de l’événement déclencheur. Le traitement des mises à jour est effectué de façon synchrone (au commit de la transaction).
Ce backend adresse des environnements standalones (non clusterisés) ou en clusters symétriques (tous les nœuds partagent la même instance d’index Lucene). C’est alors Lucene qui est en charge de la gestion de la stratégie de locking.

Hibernate Search Back End

Les avantages de ce mode sont sa simplicité de mise en œuvre et la visibilité immédiate des mises à jour de l’index puisqu’elles sont traitées en synchrone.
Par contre, cette approche synchrone peut dégrader les performances de l’application front.

Backend asynchrone

Ce backend met en jeu le pattern maître / esclaves : Les opérations de mise à jour de l’index sont effectuées sur un index maître tandis que les opérations de lecture (recherche) sont effectuées sur des index esclaves. A intervalles réguliers, l’index maître est répliqué sur les esclaves (copies du maître).

Ce backend adresse des environnements clusterisés répondant à des besoins de haute performance de l’application front. Dans ce mode, chaque nœud utilise un index esclave en local. Ces indexes sont exclusivement utilisés en lecture. Lorsqu’un événement nécessite une opération de mise à jour de l’index, l’ordre de mise à jour est envoyé sur une queue JMS (tous les nœuds utilisant la même queue). Cette queue est dépilée par un consommateur unique en charge du traitement (asynchrone) des opérations de mise à jour qu’il effectue sur l’index maître.

Hibernate Search Asynchronous Back End

Le principal avantage de ce mode est de ne pas surcharger l’application front avec les traitements de mise à jour de l’index.
Il entraîne par contre un délai de mise à jour des index de recherche (Traitement asynchrone des mises à jour + délai de réplication).

Pour bien commencer

Et rendez-vous fin mars sur notre blog pour un premier sample.


[1] Emmanuel Bernard est membre de l’équipe Hibernate, Core developer à JBoss, lead developer sur les projets Hibernate Annotations, Hibernate EntityManager et Hibernate Search ainsi que membre des groupes d’expert EJB 3.0 et JSR-303.

5 réflexions au sujet de « Introduction à Hibernate Search (Googling your Persistent Domain Model) »

  1. Publié par Aurélien, Il y a 9 années

    Très bonne introduction à Hibernate Lucene.
    Cela m’a donné envie de tester le moteur sur mon site

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *