l'API Lucene

 


I.       Introduction

 

Avec l’expansion du volume de données sur tout système informatique, il est souvent nécessaire de pouvoir chercher et retrouver rapidement et facilement ce que l’on a besoin.

Lors de la programmation de n’importe quelle application, la fonction de recherche est souvent fastidieuse à développer, ne correspond pas toujours à ce que l’on a besoin et est difficile à faire évoluer.

 

C’est pourquoi la fondation Apache a développé une API : Apache Lucene qui une bibliothèque de moteur de recherche complète et de haute-performance écrit entièrement en java. C’est une technologie adaptée pour presque n’importe quelle application qui a besoin d’une recherche intégrale du texte sur plate-forme diverses.

 

II.    Découverte de l’API Lucene

 

Lucene est une API permettant de créer facilement des applications de recherche

Les avantages de Lucene est qu’il est flexible, puissant et facile à utiliser.

Lucene est disponible avec une licence gratuite open-source LGPL.

Notez que Lucene est une API, ce qui veux dire que tout les cotés difficiles ont été implémentés, et qu’il ne vous reste plus que le plus simple.

Vous pouvez alors facilement développer une application de recherche personnalisée, parfaitement adapté à vos besoins.

 

Notons également que le projet apache-Lucene développe des outils open-source de recherche comprenant entre autre :

·        Lucene Java, permettant une indexation et une technologie de recherche basée sur java.

·        Nutch basé sur Lucene qui permet une application de recherche web.

·        Hadoop qui est une plate forme distribuée utilisée par Nutch.

·        Lucene4c est un moteur de recherche basé sur du C compatible avec Lucene Java, construit sur le runtime portable de apache.

A. Ce que fait l’API Lucene

Avec l’API Lucene, il est possible de :

  • Générer des index à partir de documents.
  • Effectuer des recherches à partir des index créés.
  • Supprimer des index.

 

B. Les packages

Voici un détail des principaux paquetages et ce qu’ils représentent :

 

org.apache.lucene : package de plus haut niveau
org.apache.lucene.analysis : API et code pour convertir texte et index. org.apache.lucene.analysis.standard : Un indexeur basé sur la grammaire construit avec javaCC
org.apache.lucene.document : Les documents indexés

org.apache.lucene.index Code pour manipuler les index.
org.apache.lucene.queryParser Un simple parseur de requêtes.
org.apache.lucene.search Recherche d’index.

org.apache.lucene.util Quelques classes contenant des outils.

C. Le projet Lucene

Vous pourrez trouver l’API, toute la documentation dont vous avez besoin, ainsi que des utilisations avancées, sur le site d’apache dans partie Lucene à l’url suivante :

http://lucene.apache.org/java/docs/index.html

 

III.  Présentation des classes importantes de l’API Lucene

 

A. L’analyseur

org.apache.lucene.analysis.Analyzer;

org.apache.lucene.analysis.standard.StandardAnalyzer;

L’analyseur, souvent utilisé avec l’analyseur standard convertit toutes les chaînes de caractères en minuscule, et filtre les mots et caractères inutiles. Par mots et caractères inutiles on entend les mots commun du langage comme les articles (de, du, le, la, etc.…) et autres chaines de caractères qu’il est inutile de rechercher.

Notons que les règles sont différentes du langage et vous devez utiliser l’analyseur correspondant à la langue utilisée.

 

B. IndexWriter

org.apache.lucene.index.IndexWriter

La classe indexWriter est la classe principale responsable de créer les index. Pour l’utiliser vous devez l’instancier avec un chemin ou peuvent être écrits les index. Si ce chemin n’existe pas, celui-ci sera créé, sinon il rafraichira l’index existant. Vous devez également lui passer une instance d’un analyseur (org.apache.lucene.analysis.Analyzer).

C.            Document et Field

org.apache.lucene.document.Document;
org.apache.lucene.document.Field;

Document est la représentation d’un document indexé par Lucene.
Celui contient des sections appelées Fields qui vont contenir les valeurs indexées (comme par exemple une date, un texte, une chaîne de caractères, etc.…). Il est possible de spécifier comment les valeurs sont enregistrées et analysées par l’analyseur, comme par exemple il est possible de spécifier que la valeur ne soit pas utilisée comme critère de recherche (UN_TOKENIZED).

 

D.            Query et QueryParser

org.apache.lucene.queryParser.QueryParser;
org.apache.lucene.search.Query;

QueryParser permet de parser une requête permettant d’effectuer des opérations complexes. Le queryparser est construit avec un analyseur pour interpréter votre requête, de la même manière qu’un index en retirant les mots et caractères inutiles.

La grammaire BNF du parsage d’une requête est la suivante :

  Query  ::= ( Clause )*
  Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" )

Pour plus d’informations sur les opérateurs, se reporter à la documentation officielle à l’adresse suivante http://lucene.apache.org/java/docs/queryparsersyntax.html donnant le détail complet sur les requêtes.

Query est la classe abstraite pour les requêtes.

E.             Searcher, IndexSearcher et Hits

org.apache.lucene.search.Hits;
org.apache.lucene.search.IndexSearcher;
org.apache.lucene.search.Searcher;

Searcher et IndexSearcher permet d’effectuer des recherches sur l’ensemble des index, il suffit de leur passer les fichiers d’index.

Le résultat de la recherche est retourné grâce à la méthode search de la classe Searcher et retourne une collection de Hit contenant la liste des documents correspondant sur lequel il faut itérer.

 

 

 

 

Schéma d’une recherche standard

 

IV.Utilisation des classes

Nous allons voir une petite application qui permettra d’indexer des fichiers textes puis chercher les fichiers à partir de mots

Ces classes sont issues des exemples donnés comme démonstration par les créateurs du projet mais qui ont été simplifiées afin de se consacrer uniquement à la plus simple utilisation de Lucene.Cet exemple comprend 3 classes :

·  Une pour convertir les objets fichier en document indexable : FileDocument 

·  Une pour indexer des documents à partir de fichiers : FileIndexer

·  Une pour rechercher les index précédemment créés: FileSearcher

A. FileDocument

Pour indexer les fichiers, ceux-ci doivent être des documents, il faut donc tout d’abord les convertir.Le document (org.apache.lucene.document.Document) représente un document auquel il est possible d’ajouter des champs (org.apache.lucene.document.Field). Dans l’exemple suivant, nous créons un document à partir d’un fichier à partir duquel nous indexons son chemin, son nom et son contenu.

package main;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;

public class FileDocument {           

                /**
                 * Lucene peut seulement indexer des objets de type document
                 * Donc les fichiers sont convertit en document selon ce que l'on veut indexer
                 */

                public static Document Document(File file) throws FileNotFoundException {
                               //le document que nous allons remplir
                               Document doc = new Document();

                               //ajoute le champ contenant le chemin du fichier.
                               //le champ sera indexé  Field.Store.YES
                               //mais pas tokenizé ( séparé en chaine plus petite )

                                doc.add(new Field("path", file.getPath(), Field.Store.YES, Field.Index.UN_TOKENIZED));

                               doc.add(new Field("name",  file.getName(),  Field.Store.YES, Field.Index.UN_TOKENIZED));

                               //ajoute le contenu du fichier
                               doc.add(new Field("content", new FileReader(file)) );

                               //retourne le document
                               return doc;
                               }
}

 

B. FileIndexer

Dans cette partie, nous utilisons

·                    les IndexWriter pour indexer les documents

·                    l’analyseur

Voici l’implémentation utilisant les principes d’indexation : la classe FileIndexer a une méthode index qui obtient un fichier index qui peux être indexé.

Pour indexer un objet, le fichier doit être convertit en un document avec champs, qui peuvent être indexé à partir de la classe FileDocument précédemment créée.

package main;

import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexWriter;

public class FileIndexer {
                /**
                 * Convertit les objet indexé en document Et écrit le document avec  un
                 * indexWriter
                 *
                 * @param le  fichier à indexé
                 */
                public static void index(File file, String baseIndex ) {
                               try {
                                               // repertoire où sont stocké les fichiers d'index
                                               String indexFile = baseIndex;
                                               // ################# creation du writer ######################                                           // le IndexWriter qui ecrira les documents
                                               IndexWriter writer = null;

                                   // créé le repertoire d'index si celui ci n'existe pas
                                    boolean create;
                                               File f = new File(indexFile);
                                               if (f.exists() && f.isDirectory()) {
                                             create = false;

                                   } else {
                                             create = true;
                                   }
                                   // initialise le writer qui va etre utilise
                                   writer = new IndexWriter(indexFile, new  StandardAnalyzer(), create);


                                    // ################# ajoute le document ######################                                     writer.addDocument(FileDocument.Document(file));
                                               writer.optimize();
                                               if (null != writer) {
                                                               writer.close();
                                               }
                               } catch (IOException e) {
                                               e.printStackTrace();
                               }
                }
}

 

C.     FileSearcher

 

La classe SearchFile est assez simple.

Elle est utilisée avec :

  • Un indexsearcher
  • Un StandardAnalyzer (utilisé aussi dans IndexFile)
  • Un queryparser

 

L’objet query contient le résultat de QueryParser qui est passé au searcher. Le résultat du searcher est retourné dans une collection de document appelé « Hits » qui sont alors itéré et affichés à l’utilisateur.

package main;

import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Quer
import org.apache.lucene.search.Searcher;

public class FileSearcher {

                public  static void  search(String queryString, String baseIndex) {

                               try {
                                               //créé un searcher à partir du fichier d'index
                                               String indexFile = baseIndex;
                                              
Searcher searcher = new IndexSearcher(indexFile);

                                               //l'analyseur qui sera utilisé pour la requete
                                               Analyzer
analyzer = new StandardAnalyzer();

                                               //recherche dans le champ content la valeur queryString avec l'analyseur
                                               Query query= QueryParser.parse(queryString, "content", analyzer);

                                               //obtient les hits à partir de la requete precedente
                                               Hits hits = searcher.search(query);

 

 

 

                                               //affiche les 10 premier résultat
                                               int start = 0;
                                               final int HITS_PER_PAGE = 10;
                                               int end = Math.min(HITS_PER_PAGE, hits.length());

                                               //Itére sur les résultats
                                               //Le résultat est un tableau de document
                                               System.out.println("Résultats : ");
                                               if (hits.length() > 0) {
                                                               for (int i = start; i < end; i++) {
                                                                              System.out.println("Chemin : "
                                                                                                              + hits.doc(i).get("path").toString());
                                                                              System.out.println("Nom du fichier : "
                                                                                                              + hits.doc(i).get("name").toString());
                                                                              System.out.println();
                                                               }
                                               } else {
                                                               System.out.println("Aucun document trouvé.");
                                               }
                               } catch (ParseException e) {
                                               e.printStackTrace();
                               } catch (IOException e) {
                                               e.printStackTrace();
                               }
                }
}

 

D. Test

Pour tester le tout nous avons utilisé 5 fichiers textes que nous avons ajoutés au répertoire d’index baseIndex en appelant la fonction FileIndexer.index.

Nous avons ensuite fait une recherche avec la fonction search

package main;

import java.io.File;

public class Launch {

public static void main(String[] args) {


//répertoire de base ou vont être contenu les fichiers d’index
String baseIndex = "D:\\FichiersIndexe";

FileIndexer.index(new File("c:\\1.txt"), baseIndex);               
FileIndexer.index(new File("c:\\2.txt"), baseIndex);
FileIndexer.index(new File("c:\\3.txt"), baseIndex);
FileIndexer.index(new File("c:\\4.txt"), baseIndex);
FileIndexer.index(new File("c:\\5.txt"), baseIndex);

//recherche des fichier ayant comme contenu la chaîne to
FileSearcher.search("toto", baseIndex);                    

}

}

Voici la sortie de ce programme (en effet le fichier 5.txt contenait la chaine toto).

Résultats :

Chemin : c:\5.txt

Nom du fichier : 5.txt

V.    Conclusion

Nous avons pu voir que l’API Lucene nous à permit de créer très facilement une fonction de recherche avec très peu de code. De plus, ce qui a été développé peut évoluer facilement.

L’API supporte maintenant 30 langues et peut être utilisée également dans un développement Web, mais aussi avec des flux RSS, document office (Word, PDF, PowerPoint, Excel, etc…) et autres, ce qui montre que les possibilités d’utilisation sont assez voir très vastes.

VI.Sources

 

http://lucene.apache.org

http://lucene.apache.org/java/docs/api/index.html




Retrouvez ci-dessous les autres sections du Laboratoire Sun
Evènements
Java Sun Net Talk LIVE CHAT le 2 Avril à 16h303/29/08
SolarisSunDécouvrez les nouveaux Sun Fire sous Intel10/11/07
JavaValtech Days10/9/07
JavaApacheCon du 1 au 4 mai à Amsterdam2/13/07

Exemples de code
JavaManipuler les looks and feel (lister et affecter)10/15/07
JavaFaire sa propre injection de dépendance avec les annotations5/9/06
JavaSplash screen avec progress Bar5/5/06
JavaFaire un splash screen en swing5/5/06

Actualités
SunProjet Kenai: une nouvelle forge open source10/3/08
SunSun Microsystems en forme !8/4/08
SunOpenDS un ldap 100% java7/24/08
SunSun et Fujitsu annoncent un nouveau Sparc647/16/08
SunVisualVM, un outil de surveillance des applications Java7/10/08

Tips du laboratoire
EclipseVisual Editor avec Eclipse Europa, c'est possible3/28/08
EclipseGérer les projets dans un workspace.10/16/07
JavaManager votre server d'application avec Eclipse4/21/07
JavaVue des sub-packages avec Eclipse4/21/07
JavaGlisser-déposer avec Eclipse4/21/07

Laboratoire SUPINFO des technologies Sun
labo-sun@supinfo.com


Conditions d'utilisation et © Copyright SUPINFO International University
23, rue de Château Landon - 75010 PARIS - Tél : +33 (0) 153359700 Fax : +33 (0) 153359701
Respect de la vie privée