Introduzione a Lucene

Introduzione a Lucene
In questa lezione, capiremo il funzionamento dietro uno dei più potenti motori di ricerca full-text, Apache Lucene. Con Apache Lucene, possiamo usare le API che espone in molti linguaggi di programmazione e costruisce le caratteristiche di cui abbiamo bisogno. Lucene è uno dei motori più potenti su cui è costruito Elasticsearch. Prima di iniziare con un'applicazione che dimostra il funzionamento di Apache Lucene, capiremo come funziona Lucene e molti dei suoi componenti. Iniziamo.

Perché Lucene è necessario?

La ricerca è una delle operazioni più comuni che eseguiamo più volte al giorno. Questa ricerca può essere su più pagine Web che esistono sul Web o un'applicazione musicale o un repository di codice o una combinazione di tutti questi. Si potrebbe pensare che un semplice database relazionale possa anche supportare la ricerca. Questo è corretto. Database come MySQL supporta la ricerca full-text. Ma che dire del Web o di un'applicazione musicale o di un repository di codice o di una combinazione di tutti questi? Il database non può archiviare questi dati nelle sue colonne. Anche se lo facesse, ci vorrà un tempo inaccettabile per eseguire la ricerca in questo grande.

Un motore di ricerca full-text è in grado di eseguire una query di ricerca su milioni di file contemporaneamente. La velocità in cui i dati vengono archiviati in un'applicazione oggi è enorme. L'esecuzione della ricerca full-text su questo tipo di volume di dati è un compito difficile. Questo perché le informazioni di cui abbiamo bisogno potrebbero esistere in un singolo file di miliardi di file conservati sul web.

Come funziona Lucene?

La domanda ovvia che dovrebbe venire in mente è: come è Lucene così veloce nel eseguire query di ricerca a full-text? La risposta a questo, ovviamente, è con l'aiuto degli indici che crea. Ma invece di creare un indice classico, Lucene fa uso Indici invertiti.

In un indice classico, per ogni documento, raccogliamo l'elenco completo di parole o termini che il documento contiene. In un indice invertito, per ogni parola in tutti i documenti, archiviamo quale documento e posizioniamo questa parola/termine può essere trovato a. Questo è un algoritmo di alto livello che rende la ricerca molto semplice. Considera il seguente esempio di creazione di un indice classico:

Doc1 -> "this", "is", "semplice", "Lucene", "campione", "classico", "invertito", "indice"
Doc2 -> "Running", "Elasticsearch", "Ubuntu", "Update"
Doc3 -> "RabbitMQ", "Lucene", "Kafka", "", "Spring", "Boot"

Se utilizziamo l'indice invertito, avremo indici come:

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

Gli indici invertiti sono molto più facili da mantenere. Supponiamo che se vogliamo trovare Apache nei miei termini, avrò subito risposte con indici invertiti, mentre con la ricerca classica verrà eseguita su documenti completi che potrebbero non essere stati possibili per essere eseguiti in scenari in tempo reale.

Flusso di lavoro di Lucene

Prima che Lucene possa effettivamente cercare i dati, deve eseguire passaggi. Visualizziamo questi passaggi per una migliore comprensione:

Flusso di lavoro di Lucene

Come mostrato nel diagramma, questo è ciò che accade in Lucene:

  1. Lucene viene alimentato i documenti e altre fonti di dati
  2. Per ogni documento, Lucene converte prima questi dati in testo semplice e quindi gli analizzatori converte questa fonte in testo semplice
  3. Per ogni termine nel testo semplice, vengono creati gli indici invertiti
  4. Gli indici sono pronti per essere cercati

Con questo flusso di lavoro, Lucene è un motore di ricerca a full-text molto forte. Ma questa è l'unica parte che Lucene soddisfa. Dobbiamo svolgere il lavoro noi stessi. Diamo un'occhiata ai componenti dell'indicizzazione necessari.

Componenti Lucene

In questa sezione, descriveremo i componenti di base e le classi di Lucene di base utilizzate per creare indici:

  • Directory: Un indice Lucene memorizza i dati nei normali directorie del file system o in memoria se hai bisogno di ulteriori prestazioni. È completamente la scelta delle app per archiviare i dati ovunque desideri, un database, la RAM o il disco.
  • Documenti: I dati che nutriamo al motore Lucene devono essere convertiti in testo semplice. Per fare ciò, creiamo un oggetto documento che rappresenta quella fonte di dati. Più tardi, quando eseguiamo una query di ricerca, di conseguenza, otterremo un elenco di oggetti di documenti che soddisfano la query che abbiamo superato.
  • Campi: I documenti sono popolati con una raccolta di campi. Un campo è semplicemente un paio di (nome, valore) elementi. Quindi, durante la creazione di un nuovo oggetto documento, dobbiamo riempirlo con quel tipo di dati accoppiati. Quando un campo è indicizzato invertitamente, il valore del campo viene tokenizzato ed è disponibile per la ricerca. Ora, mentre usiamo i campi, non è importante archiviare la coppia effettiva ma solo l'indicizzato invertito. In questo modo, possiamo decidere quali dati sono solo ricercabili e non importanti per essere salvati. Diamo un'occhiata a un esempio qui:

    Indicizzazione del campo

    Nella tabella sopra, abbiamo deciso di archiviare alcuni campi e altri non sono archiviati. Il campo del corpo non è memorizzato ma indicizzato. Ciò significa che l'e -mail verrà restituita di conseguenza quando viene eseguita la query per uno dei termini per il contenuto del corpo.

  • Termini: Termini rappresenta una parola dal testo. I termini vengono estratti dall'analisi e dalla tokenizzazione dei valori dei campi, quindi Il termine è l'unità più piccola su cui viene eseguita la ricerca.
  • Analizzatori: Un analizzatore è la parte più cruciale dell'indicizzazione e del processo di ricerca. È l'analizzatore che convoca il testo semplice in token e termini in modo che possano essere cercati. Bene, questa non è l'unica responsabilità di un analizzatore. Un analizzatore utilizza un tokenizer per fare token. Un analizzatore svolge anche i seguenti compiti:
    • Steming: un analizzatore converte la parola in uno stelo. Ciò significa che i "fiori" vengono convertiti in "Fiore" della parola dello stelo. Quindi, quando viene eseguita una ricerca di "fiore", il documento verrà restituito.
    • Filtro: un analizzatore filtra anche le parole di arresto come "il", "è" ecc. Poiché queste parole non attirano alcuna domanda da eseguire e non sono produttive.
    • Normalizzazione: questo processo rimuove gli accenti e altri segni di carattere.

    Questa è solo la normale responsabilità di StandardAnalizer.

Esempio di applicazione

Useremo uno dei tanti archetipi Maven per creare un progetto di esempio per il nostro esempio. Per creare il progetto eseguire il seguente comando in una directory che utilizzerai come spazio di lavoro:

Archetipo MVN: genera -dGroupid = com.Linuxhint.Esempio -dArtifactId = LH -LuceneExample -DarcheTypeAceFactId = maven -archeType -Quickstart -DinteractiveMode = false

Se stai eseguendo Maven per la prima volta, ci vorranno alcuni secondi per realizzare il comando Genera perché Maven deve scaricare tutti i plugin e gli artefatti richiesti per effettuare l'attività di generazione. Ecco come appare l'output del progetto:

Configurazione del progetto

Una volta creato il progetto, sentiti libero di aprirlo nel tuo IDE preferito. Il prossimo passo è aggiungere dipendenze Maven appropriate al progetto. Ecco il pom.File XML con le dipendenze appropriate:



org.Apache.Lucene
Lucene-core
4.6.0


org.Apache.Lucene
Lucene-Analyzer-Common
4.6.0

Infine, per comprendere tutti i barattoli che vengono aggiunti al progetto quando abbiamo aggiunto questa dipendenza, possiamo eseguire un semplice comando Maven che ci consente di vedere un albero di dipendenza completo per un progetto quando aggiungiamo alcune dipendenze ad esso. Ecco un comando che possiamo usare:

Dipendenza MVN: albero

Quando eseguiamo questo comando, ci mostrerà il seguente albero di dipendenza:

Infine, creiamo una classe SimpleIndexer che funziona

pacchetto com.Linuxhint.esempio;
Importa Java.io.File;
Importa Java.io.Filereader;
Importa Java.io.Ioexception;
Org di importazione.Apache.Lucene.analisi.Analizzatore;
Org di importazione.Apache.Lucene.analisi.standard.Standardanalizer;
Org di importazione.Apache.Lucene.documento.Documento;
Org di importazione.Apache.Lucene.documento.Storedfield;
Org di importazione.Apache.Lucene.documento.Campo di testo;
Org di importazione.Apache.Lucene.indice.Indicewriter;
Org di importazione.Apache.Lucene.indice.IndiceWriteRconfig;
Org di importazione.Apache.Lucene.negozio.FsDirectory;
Org di importazione.Apache.Lucene.util.Versione;
Classe pubblica SimpleIndexer
String finale statico privato INDEXDirectory = "/Users/Shubham/Somewhere/Lh-LuceneExample/Index";
stringa finale statica privata DirToBeIndexed = "/Users/Shubham/Somewhere/Lh-LuceneExample/SRC/Main/Java/Com/Linuxhint/Esempio";
public static void main (string [] args) lancia l'eccezione
File IndexDir = new File (IndexDirectory);
File datadir = nuovo file (dirToBeIndexed);
SimpleIndexer Indexer = new SimpleIndexer ();
int numIndexed = Indexer.indice (indexDir, datadir);
Sistema.fuori.println ("file totali indicizzati" + numindexed);

privato int indice (file indexDir, file datadir) lancia ioexception
Analyzer Analyzer = new StandardAnalizer (versione.Lucene_46);
IndexWriteRconfig config = new IndexWriteRconfig (versione.Lucene_46,
analizzatore);
IndexWriter IndexWriter = new IndexWriter (FSDirectory.Open (IndexDir),
config);
File [] file = datadir.ListFiles ();
per (file f: files)
Sistema.fuori.println ("file di indicizzazione" + f.getCanonicalPath ());
Documento doc = new document ();
doc.Aggiungi (new TextField ("Content", New FileReader (F)));
doc.Aggiungi (New StoredField ("FileName", F.getCanonicalPath ()));
indicewriter.addDocument (doc);

int numIndexed = IndexWriter.maxdoc ();
indicewriter.vicino();
restituire numindexed;

In questo codice, abbiamo appena creato un'istanza del documento e aggiunto un nuovo campo che rappresenta il contenuto del file. Ecco l'output che otteniamo quando eseguiamo questo file:

File di indicizzazione/Utenti/Shubham/Somewhere/Lh-LuceneExample/SRC/Main/Java/Com/LinuxHint/Esempio/SimpleIndexer.Giava
File totali indicizzati 1

Inoltre, all'interno del progetto viene creata una nuova directory con i seguenti contenuti:

Dati indicizzati

Analizzeremo ciò che tutti i file sono creati in questi indice in più lezioni per arrivare su Lucene.

Conclusione

In questa lezione, abbiamo esaminato come funziona Apache Lucene e abbiamo anche fatto una semplice applicazione di esempio basata su Maven e Java.