Lucene et Cocoon

Mise en oeuvre de l'indexation et de la recherche avec le projet Apache Lucene dans Cocoon


Francois  Jannin 
ENSEEIHT

Dates de modification
Revision 1.0
Revision 1.19 mars 2006
1. Présentation
2. Indexation d'un corpus de documents
2.1. indexation par crawling
2.2. indexation par transformation
3. Recherche sur un index
3.1. Utilisation de SearchGenerator
3.2. Syntaxe des requêtes

1. Présentation

Lucene est une projet Apache pour l'indexation de documents en vue de faire de la recherche et des statistiques sur ces derniers. Cocoon est un framework de transformations XSLT basé sur des pipelines, chargé de traiter un ensemble de contenus décrits sous forme XML afin de les convertir vers un panel de formats de sorties varié et extensible : PDF, RTF, WORD, HTML, WML pour ne citer que les formats les plus utilisés. Il est loisible aux développeurs d'implémenter des composants pour étendre les capacités de traitement du framework vers d'autres sources d'entrée ou d'autres formats de sortie.

Pipeline Cocoon : Generator ► Transformer ► Serializer

Cocoon intègre l'API Lucene à travers plusieurs composants, apportant ainsi les fonctionnalités d'indexation et de recherche à ce dernier :

2. Indexation d'un corpus de documents

L'indexation peut se faire de deux manières différentes:

2.1. indexation par crawling

La première méthode consiste à fournir une URL de départ à partir de laquelle tous les liens vont être parcourus afin de collecter les paires URL/contenu qui servent de base de départ à l'indexation. Ceci se fait à l'aide d'une page XSP, sorte de document XML mêlant du contenu et de la logique de programmation(ici langage Java). Pour résumer, la technologie XSP est au XML ce que JSP est au HTML. Voici un exemple de code d'une page XSP permettant la création d'un index par crawling

LuceneCocoonIndexer lcii;
  Analyzer analyzer = LuceneCocoonHelper.getAnalyzer( "org.apache.lucene.analysis.standard.StandardAnalyzer" );
  
  void createIndex(String baseURL, boolean create) throws ProcessingException {
    try {
      
      lcii = (LuceneCocoonIndexer)this.manager.lookup( LuceneCocoonIndexer.ROLE );
      Directory directory = LuceneCocoonHelper.getDirectory( new File( workDir, "index" ), create );
      lcii.setAnalyzer( analyzer );
      URL base_url = new URL( baseURL );
      lcii.index( directory, create, base_url );
    } catch (...)
...

Cette méthode implique de disposer d'un document index et d'un contenu que l'on peut parcourir exhaustivement de lien en lien: elle est donc plus adaptée à l'indexation du contenu d'un site qu'à celui d'un corpus de documents indépendant.

2.2. indexation par transformation

La seconde façon se fait au niveau même du sitemap à l'aide d'un transformer spécifique, LuceneIndexTransformer, composant qui prends en entrée un document XML contenant les URL et les contenus des documents à indexer. En sortie, il génère un rapport sur les documents et leur temps de traitement. Le travail d'implémentation consiste donc à mettre en place dans un pipeline une série de transformations dédiées à l'élaboration du document entrée, et éventuellement à l'affichage du rapport de l'indexation en sortie. Voici un exemple de ce que l'on peut trouver dans le sitemap :

Tout ce qui se situe en amont de la tranformation nommée « index » représente la préparation du document d'entrée, lequel donne quelque chose de ce genre :

<lucene:index xmlns:lucene="http://apache.org/cocoon/lucene/1.0" 
   analyzer="org.apache.lucene.analysis.standard.StandardAnalyzer" 
   directory="index" 
   create="false" 
   merge-factor="20">

   <lucene:document url="http://localhost/sample.html">
      <!-- here is some sample content -->
      <html>
         <head>
            <title lucene:store="true">Sample</title>
         </head>
         <body>
            <h1>Blah</h1>
            <a href="blah.jpg" title="download blah image"
               lucene:text-attr="title">
               <img src="blah-small.jpg" alt="Blah"
                  lucene:text-attr="alt"/>
            </a>
         </body>
      </html>
   </lucene:document>

   <lucene:document url="http://localhost/sample-2.html">
      <!-- Another sample doc -->
      <html>
         <head>
            <title lucene:store="true">Second Sample</title>
         </head>
         <body>
            <h1>Foo</h1>
            <p>Lorem ipsum dolor sit amet, 
            consectetuer adipiscing elit. </p>
         </body>
      </html>
   </lucene:document>

</lucene:index>
LuceneIndexTransformer indexe le contenu des éléments XML incluent dans l'élément <lucene:document>.

Pour indexer également certains attributs, il faut intégrer parmi les attributs l'attribut "lucene-text-attr", pour lequel on définie une valeur correspondant aux attributs que l'on veut indexer. L'attribut "lucene:store" permet de définir des éléments qui seront stockés en même temps que l'URL du document afin de pouvoir être affichés parmi les résultats de la recherche.

Les attributs de l'élément racine <lucene:index> sont les suivants :

3. Recherche sur un index

3.1. Utilisation de SearchGenerator

Le composant SearchGenerator s'intègre en entrée de pipeline dans le sitemap, et fait référence au nom de l'index qu'il doit utiliser pour la recherche. L'emplacement physique du répertoire utilisé pour stocker l'index est le work directory de Cocoon, à savoir :

${TOMCAT_HOME)/work\Catalina\localhost\cocoon\cocoon-files

Pipeline Cocoon pour la recherche :

<map:match pattern="findIt">
   <map:generate type="search" label="content">
      <map:parameter name="index" value="injac-index"/>
   </map:generate>
   <map:transform type="log"/>
   <map:transform src="stylesheets/search-index2html.xsl">
      <map:parameter name="use-request-parameters" value="true"/>
   </map:transform>
   <map:serialize type="html"/>
</map:match>

Les paramètres reçus par SearchGenerator permettent de spécifier la requête, mais également le nombre de résultat par page, l'index de début et de fin de la page courante ainsi que ceux de la page précédente et suivante le cas échéant. Voici un tableau récapitulant ces paramètres :

Paramètres du SearchGenerator

Nom valeur par défaut Description
queryString pas de valeur par défaut Spécifie la chaîne de requête exécutable par le moteur de recherche
pageLength 10 Nombre de résultats affichés par page
startIndex 0 Index de départ de l'affichage des résultats
startNextIndex 0 Index de départ de l'affichage pour la page suivante
startPreviousIndex 0 Index de départ de l'affichage pour la page précédente

Cela signifie que le SearchGenerator ne renvoie pas que des résultats bruts, mais également des éléments permettant de construire une page de navigation sur les résultats. Le document de sortie de ce generator a la forme suivante :

?xml version="1.0" encoding="UTF-8"?>
<search:results date="1101730810578" query-string="ldap" start-index="0" page-length="10">
<search:hits total-count="2" count-of-pages="1">
<search:hit rank="0" score="0.32969838" uri="/slide/files/UT1/Cri/exploitation-LDAPGLOBAL-20040923.xml?title=&file=exploitation-LDAPGLOBAL-20040923.xml"/>
<search:hit rank="1" score="0.2851561" uri="/slide/files/UT1/Cri/ldap_samba_howto.xml?title=Ldap Samba&file=ldap_samba_howto.xml"/>
</search:hits>
<search:navigation total-count="2" count-of-pages="1" has-next="false" has-previous="false" next-index="2" previous-index="0">
<search:navigation-page start-index="0"/>
</search:navigation>
</search:results>

3.2. Syntaxe des requêtes

Lucene implémente une syntaxe pour les expressions de requêtes permettant une série de fonctionnalités de recherche :