Introduction à Lucene

Introduction à Lucene
Dans cette leçon, nous comprendrons le fonctionnement derrière l'un des moteurs de recherche en texte intégral les plus puissants, Apache Lucene. Avec Apache Lucene, nous pouvons utiliser les API qu'il expose dans de nombreux langages de programmation et construire les fonctionnalités dont nous avons besoin. Lucene est l'un des moteurs les plus puissants sur lesquels Elasticsearch est construit. Avant de commencer par une application qui démontre le fonctionnement d'Apache Lucene, nous comprendrons comment le fonctionnement de Lucene et de plusieurs de ses composants. Commençons.

Pourquoi Lucene est-il nécessaire?

La recherche est l'une des opérations les plus courantes que nous effectuons plusieurs fois par jour. Cette recherche peut se trouver sur plusieurs pages Web qui existent sur le Web ou une application musicale ou un référentiel de code ou une combinaison de tous ces éléments. On pourrait penser qu'une base de données relationnelle simple peut également prendre en charge la recherche. C'est correct. Des bases de données comme MySQL prennent en charge la recherche de texte intégral. Mais qu'en est-il du Web ou d'une application musicale ou d'un référentiel de code ou d'une combinaison de tous ces? La base de données ne peut pas stocker ces données dans ses colonnes. Même si c'était le cas, il faudra un temps inacceptable pour exécuter la recherche de ce gros.

Un moteur de recherche en texte intégral est capable d'exécuter une requête de recherche sur des millions de fichiers à la fois. La vitesse à laquelle les données sont stockées dans une application aujourd'hui est énorme. L'exécution de la recherche en texte intégral sur ce type de volume de données est une tâche difficile. En effet, les informations dont nous avons besoin pourraient exister dans un seul fichier sur des milliards de fichiers conservés sur le Web.

Comment fonctionne Lucene?

La question évidente qui devrait vous venir à l'esprit est: comment Lucene est-il si rapide dans l'exécution des requêtes de recherche en texte intégral? La réponse à cela, bien sûr, est à l'aide d'indices qu'il crée. Mais au lieu de créer un index classique, Lucene utilise Indices inversés.

Dans un index classique, pour chaque document, nous collectons la liste complète des mots ou des termes que le document contient. Dans un index inversé, pour chaque mot de tous les documents, nous stockons quel document et positionnement ce mot / terme peut être trouvé à. Ceci est un algorithme de haut niveau qui rend la recherche très facile. Considérez l'exemple suivant de la création d'un index classique:

Doc1 -> "this", "est", "simple", "lucene", "échantillon", "classique", "inversé", "index"
Doc2 -> "Running", "elasticsearch", "ubuntu", "update"
Doc3 -> "Rabbitmq", "Lucene", "Kafka", "", "Spring", "Boot"

Si nous utilisons l'index inversé, nous aurons des indices comme:

This -> (2, 71)
Lucene -> (1, 9), (12,87)
Apache -> (12, 91)
Framework -> (32, 11)

Les indices inversés sont beaucoup plus faciles à entretenir. Supposons que si nous voulons trouver Apache en termes de mes termes, j'aurai des réponses tout de suite avec des indices inversés alors que la recherche classique fonctionnera sur des documents complets qui n'auraient pas été possible de fonctionner dans des scénarios en temps réel.

Flux de travail de Lucene

Avant que Lucene ne puisse réellement rechercher les données, elle doit effectuer des étapes. Visualisons ces étapes pour une meilleure compréhension:

Flux de travail de Lucene

Comme le montre le diagramme, c'est ce qui se passe dans Lucene:

  1. Lucene est nourri les documents et autres sources de données
  2. Pour chaque document, Lucene convertit d'abord ces données en texte brut, puis les analyseurs convertissent cette source en texte brut
  3. Pour chaque terme du texte brut, les indices inversés sont créés
  4. Les indices sont prêts à être recherchés

Avec ce flux de travail, Lucene est un moteur de recherche en texte intégral très fort. Mais c'est la seule partie que Lucene se réalise. Nous devons effectuer notre travail nous-mêmes. Regardons les composants de l'indexation nécessaires.

Composants lucene

Dans cette section, nous décrirons les composants de base et les classes Lucene de base utilisées pour créer des indices:

  • Répertoires: Un index de Lucene stocke les données dans les directeurs de système de fichiers normaux ou en mémoire si vous avez besoin de plus de performances. C'est complètement le choix des applications pour stocker les données où qu'il le souhaite, une base de données, la RAM ou le disque.
  • Documents: Les données que nous nourrissons au moteur Lucene doivent être converties en texte ordinaire. Pour ce faire, nous fabriquons un objet de document qui représente cette source de données. Plus tard, lorsque nous exécuterons une requête de recherche, en conséquence, nous obtiendrons une liste d'objets de document qui satisfont la requête que nous avons réussi.
  • Des champs: Les documents sont peuplés d'une collection de champs. Un champ est simplement une paire de (nom, valeur) articles. Ainsi, lors de la création d'un nouvel objet de document, nous devons le remplir avec ce type de données appariées. Lorsqu'un champ est indexé inversé, la valeur du champ est tokenisée et est disponible pour la recherche. Maintenant, alors que nous utilisons des champs, il n'est pas important de stocker la paire réelle mais uniquement l'indexation inversée. De cette façon, nous pouvons décider quelles données sont consultables uniquement et pas importantes pour être enregistrées. Regardons un exemple ici:

    Indexation des champs

    Dans le tableau ci-dessus, nous avons décidé de stocker certains champs et d'autres ne sont pas stockés. Le champ corporel n'est pas stocké mais indexé. Cela signifie que l'e-mail sera renvoyé en conséquence lorsque la requête pour l'un des termes du contenu corporel est exécuté.

  • Conditions: Les termes représentent un mot du texte. Les termes sont extraits de l'analyse et de la tokenisation des valeurs des champs, donc Le terme est la plus petite unité sur laquelle la recherche est exécutée.
  • Analyseurs: Un analyseur est la partie la plus cruciale du processus d'indexation et de recherche. C'est l'analyseur qui conforme le texte clair en jetons et termes afin qu'ils puissent être recherchés. Eh bien, ce n'est pas la seule responsabilité d'un analyseur. Un analyseur utilise un jetons pour fabriquer des jetons. Un analyseur effectue également les tâches suivantes:
    • Solenming: un analyseur convertit le mot en tige. Cela signifie que les «fleurs» sont converties en mot de tige «fleur». Ainsi, lorsqu'une recherche de «fleur» est exécutée, le document sera retourné.
    • Filtrage: un analyseur filtre également les mots d'arrêt comme «le», «est» etc. Comme ces mots n'attirent aucune question à exécuter et ne sont pas productives.
    • Normalisation: ce processus supprime les accents et autres marques de caractère.

    Ce n'est que la responsabilité normale de StandardAnalyzer.

Exemple d'application

Nous utiliserons l'un des nombreux archétypes Maven pour créer un exemple de projet pour notre exemple. Pour créer le projet, exécutez la commande suivante dans un répertoire que vous utiliserez comme espace de travail:

archétype mvn: générer -dgroupId = com.linuxhint.Exemple -DartifACTID = lh-liceneexample -DarchetyTearFactId = maven-archeType-quickstart -DinterActiveMode = false

Si vous exécutez Maven pour la première fois, il faudra quelques secondes pour accomplir la commande Génération car Maven doit télécharger tous les plugins et artefacts requis pour faire la tâche de génération. Voici à quoi ressemble la sortie du projet:

Configuration du projet

Une fois que vous avez créé le projet, n'hésitez pas à l'ouvrir dans votre IDE préféré. La prochaine étape consiste à ajouter des dépendances Maven appropriées au projet. Voici le pom.Fichier XML avec les dépendances appropriées:



org.apache.lucene
cré de lucene
4.6.0


org.apache.lucene
lucene-analysers-commun
4.6.0

Enfin, pour comprendre tous les pots qui sont ajoutés au projet lorsque nous avons ajouté cette dépendance, nous pouvons exécuter une simple commande maven qui nous permet de voir un arbre de dépendance complet pour un projet lorsque nous y ajoutons des dépendances. Voici une commande que nous pouvons utiliser:

Dépendance MVN: arbre

Lorsque nous exécutons cette commande, elle nous montrera l'arborescence de dépendance suivante:

Enfin, nous créons une classe SimpleIndexer qui fonctionne

package com.linuxhint.exemple;
Importer Java.Io.Déposer;
Importer Java.Io.FileReader;
Importer Java.Io.IoException;
org d'importation.apache.lucene.analyse.Analyseur;
org d'importation.apache.lucene.analyse.standard.StandardAnalyzer;
org d'importation.apache.lucene.document.Document;
org d'importation.apache.lucene.document.Storedfield;
org d'importation.apache.lucene.document.Champ de texte;
org d'importation.apache.lucene.indice.IndexWriter;
org d'importation.apache.lucene.indice.INDEXWRIERCONFIG;
org d'importation.apache.lucene.magasin.FsDirectory;
org d'importation.apache.lucene.user.Version;
classe publique SimpleIndexer
String statique final index indexDirectory = "/ utilisateurs / shubham / where / lh-liceneexample / index";
chaîne finale statique privée dirtobeindexed = "/ utilisateurs / shubham / where / lh-licenexample / src / main / java / com / linuxhint / exemple";
public static void main (String [] args) lève une exception
File indexdir = nouveau fichier (indexDirectory);
Fichier datadir = nouveau fichier (dirtobeindexed);
SimpleIndexer indexer = new SimpleIndexer ();
int numIndexed = indexeur.index (indexdir, datadir);
Système.dehors.println ("Fichiers totaux indexés" + numIndexed);

private int index (file indexdir, fichier datadir) lève ioException
Analyseur analyseur = nouveau standardAnalyzer (version.Lunene_46);
IndexWriterConfig config = new IndexWriterConfig (version.Lunene_46,
analyseur);
IndexWriter indexWriter = new indexwriter (fsDirectory.ouvert (indexdir),
config);
Fichier [] fichiers = datadir.listFiles ();
pour (fichier f: fichiers)
Système.dehors.println ("Fichier d'indexation" + F.getCanonicalPath ());
Document doc = nouveau document ();
doc.Add (new TextField ("Content", nouveau FileReader (F)));
doc.Ajouter (New Storedfield ("FileName", F.getCanonicalPath ()));
indexwriter.addDocument (doc);

int numIndexed = indexwriter.maxdoc ();
indexwriter.fermer();
return numIndexed;

Dans ce code, nous venons de créer une instance de document et ajouté un nouveau champ qui représente le contenu du fichier. Voici la sortie que nous obtenons lorsque nous exécutons ce fichier:

Indexation de fichiers / utilisateurs / shubham / where / lh-liceneexample / src / main / java / com / linuxhint / exemple / SimpleIndexer.Java
Les fichiers totaux indexés 1

De plus, un nouveau répertoire est créé à l'intérieur du projet avec le contenu suivant:

Données indexées

Nous analyserons ce que tous les fichiers sont créés dans ces index dans plus de leçons à venir sur Lucene.

Conclusion

Dans cette leçon, nous avons examiné le fonctionnement d'Apache Lucene et nous avons également fait un exemple simple d'application qui était basée sur Maven et Java.