Introducción a Lucene

Introducción a Lucene
En esta lección, comprenderemos los trabajos detrás de uno de los motores de búsqueda de texto completo más potente, Apache Lucene. Con Apache Lucene, podemos usar las API que expone en muchos lenguajes de programación y construye las características que necesitamos. Lucene es uno de los motores más potentes en el que se construye ElasticSearch. Antes de comenzar con una aplicación que demuestre el funcionamiento de Apache Lucene, entenderemos cómo funciona Lucene y muchos de sus componentes. Empecemos.

¿Por qué se necesita Lucene??

La búsqueda es una de las operaciones más comunes que realizamos varias veces al día. Esta búsqueda puede estar en múltiples páginas web que existen en la web o en una aplicación de música o en un repositorio de código o una combinación de todos estos. Uno podría pensar que una base de datos relacional simple también puede admitir la búsqueda. Esto es correcto. Bases de datos como MySQL admite la búsqueda de texto completo. Pero, ¿qué pasa con la web o una aplicación de música o un repositorio de código o una combinación de todos estos? La base de datos no puede almacenar estos datos en sus columnas. Incluso si lo hiciera, tomará una cantidad inaceptable de tiempo ejecutar la búsqueda en este gran.

Un motor de búsqueda de texto completo es capaz de ejecutar una consulta de búsqueda en millones de archivos a la vez. La velocidad a la que los datos se almacenan en una aplicación hoy es enorme. Ejecutar la búsqueda de texto completo en este tipo de volumen de datos es una tarea difícil. Esto se debe a que la información que necesitamos puede existir en un solo archivo de miles de millones de archivos que se mantienen en la web.

Cómo funciona Lucene?

La pregunta obvia que debería venir a su mente es, ¿cómo es Lucene tan rápida en ejecutar consultas de búsqueda de texto completo?? La respuesta a esto, por supuesto, es con la ayuda de índices que crea. Pero en lugar de crear un índice clásico, Lucene utiliza Índices invertidos.

En un índice clásico, para cada documento, recopilamos la lista completa de palabras o términos que contiene el documento. En un índice invertido, para cada palabra en todos los documentos, almacenamos qué documento y posición se puede encontrar esta palabra/término. Este es un algoritmo de alto nivel que hace que la búsqueda sea muy fácil. Considere el siguiente ejemplo de creación de un índice clásico:

Doc1 -> "this", "is", "simple", "lucene", "muestra", "clásico", "invertido", "índice"
DOC2 -> "Running", "Elasticsearch", "Ubuntu", "actualización"
Doc3 -> "Rabbitmq", "Lucene", "Kafka", "", "Spring", "Boot"

Si usamos el índice invertido, tendremos índices como:

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

Los índices invertidos son mucho más fáciles de mantener. Supongamos que si queremos encontrar a Apache en mis términos, tendré respuestas directas con índices invertidos, mientras que con la búsqueda clásica se ejecutará en documentos completos que podrían no haber sido posibles en escenarios en tiempo real.

Flujo de trabajo de Lucene

Antes de que Lucene pueda buscar los datos, debe realizar pasos. Visitemos estos pasos para una mejor comprensión:

Flujo de trabajo de Lucene

Como se muestra en el diagrama, esto es lo que sucede en Lucene:

  1. Lucene es alimentado con los documentos y otras fuentes de datos
  2. Para cada documento, Lucene primero convierte estos datos en texto plano y luego los analizadores convierten esta fuente en texto sin formato
  3. Para cada término en el texto plano, se crean los índices invertidos
  4. Los índices están listos para ser buscados

Con este flujo de trabajo, Lucene es un motor de búsqueda de texto completo muy fuerte. Pero esta es la única parte que Lucene cumple. Necesitamos realizar el trabajo nosotros mismos. Veamos los componentes de la indexación necesarios.

Componentes de Lucene

En esta sección, describiremos los componentes básicos y las clases básicas de Lucene utilizadas para crear índices:

  • Directorios: Un índice de Lucene almacena datos en el sistema de archivos normal directivos o en la memoria si necesita más rendimiento. Es completamente la opción de aplicaciones almacenar datos donde quiera, una base de datos, la RAM o el disco.
  • Documentos: Los datos que alimentamos al motor Lucene deben convertirse en texto sin formato. Para hacer esto, hacemos un objeto de documento que represente esa fuente de datos. Más tarde, cuando ejecutamos una consulta de búsqueda, como resultado, obtendremos una lista de objetos de documentos que satisfacen la consulta que aprobamos.
  • Campos: Los documentos están poblados con una colección de campos. Un campo es simplemente un par de (Nombre, valor) elementos. Entonces, al crear un nuevo objeto de documento, debemos llenarlo con ese tipo de datos emparejados. Cuando un campo está invertidamente indexado, el valor del campo se toca y está disponible para buscar. Ahora, mientras usamos campos, no es importante almacenar el par real, pero solo el invertido indexado. De esta manera, podemos decidir qué datos se pueden buscar solamente y no es importante que se guarden. Veamos un ejemplo aquí:

    Indexación de campo

    En la tabla arriba, decidimos almacenar algunos campos y otros no se almacenan. El campo del cuerpo no está almacenado sino indexado. Esto significa que el correo electrónico se devolverá como resultado cuando se ejecute la consulta para uno de los términos para el contenido del cuerpo.

  • Términos: Los términos representan una palabra del texto. Los términos se extraen del análisis y la tokenización de los valores de los campos, por lo tanto El término es la unidad más pequeña en la que se ejecuta la búsqueda.
  • Analizadores: Un analizador es la parte más crucial del proceso de indexación y búsqueda. Es el analizador el que conevrts el texto sencillo en tokens y términos para que se puedan buscar. Bueno, esa no es la única responsabilidad de un analizador. Un analizador utiliza un tokenizador para hacer fichas. Un analizador también hace las siguientes tareas:
    • Stemming: un analizador convierte la palabra en un tallo. Esto significa que 'flores' se convierte a la palabra vástago 'flor'. Entonces, cuando se ejecuta una búsqueda de 'flor', el documento se devolverá.
    • Filtrado: un analizador también filtra las palabras de parada como 'el' ',' es ', etc. ya que estas palabras no atraen ninguna consulta para ejecutar y no son productivas.
    • Normalización: este proceso elimina los acentos y otras marcas de personajes.

    Esta es solo responsabilidad normal de StandardAnalyzer.

Aplicación de ejemplo

Usaremos uno de los muchos arquetipos de Maven para crear un proyecto de muestra para nuestro ejemplo. Para crear el proyecto, ejecute el siguiente comando en un directorio que usará como espacio de trabajo:

MVN Archetype: Generar -DgroupId = com.Linuxhint.Ejemplo -DartifactId = LH -LuceExample -DarchetyPeartifactId = maven -archetype -quickstart -dinteractivEmode = false

Si está ejecutando Maven por primera vez, tomará unos segundos lograr el comando Generar porque Maven tiene que descargar todos los complementos y artefactos requeridos para hacer la tarea de generación. Así es como se ve la salida del proyecto:

Configuración del proyecto

Una vez que haya creado el proyecto, no dude en abrirlo en su IDE favorito. El siguiente paso es agregar dependencias de Maven apropiadas al proyecto. Aquí está el Pom.archivo XML con las dependencias apropiadas:



organizar.apache.luceno
núcleo de luceo
4.6.0


organizar.apache.luceno
Lucene-Analyzers-Common
4.6.0

Finalmente, para comprender todos los frascos que se agregan al proyecto cuando agregamos esta dependencia, podemos ejecutar un comando maven simple que nos permite ver un árbol de dependencia completo para un proyecto cuando le agregamos algunas dependencias a él. Aquí hay un comando que podemos usar:

Dependencia de MVN: árbol

Cuando ejecutemos este comando, nos mostrará el siguiente árbol de dependencia:

Finalmente, creamos una clase SimpleIndexer que se ejecuta

paquete com.Linuxhint.ejemplo;
importar java.IO.Archivo;
importar java.IO.FileReader;
importar java.IO.Ioexception;
Org de importación.apache.luceno.análisis.Analizador;
Org de importación.apache.luceno.análisis.estándar.StandardAnalyzer;
Org de importación.apache.luceno.documento.Documento;
Org de importación.apache.luceno.documento.Storedfield;
Org de importación.apache.luceno.documento.Campo de texto;
Org de importación.apache.luceno.índice.Indexwriter;
Org de importación.apache.luceno.índice.IndexwriterConfig;
Org de importación.apache.luceno.almacenar.FSDirectorio;
Org de importación.apache.luceno.utilizar.Versión;
clase pública SimpleIndexer
String Final STATIC STATICD Private IndexDirectory = "/Users/Shubham/Somewhere/LH-LuceExample/Index";
cadena final estática privada DirtobeIndexed = "/Users/Shubham/Somewhere/LH-LuceneExample/Src/Main/Java/Com/Linuxhint/Ejemplo";
public static void main (string [] args) lanza la excepción
Archivo indexDir = nuevo archivo (indexDirectory);
Archivo dataDir = nuevo archivo (DirTObeIndexed);
SimpleIndexer indexer = new SimpleIndexer ();
int numindexed = indexer.índice (indexDir, dataDir);
Sistema.afuera.println ("Total de archivos indexados" + numindexed);

Private int index (File IndexDir, File DataDir) lanza IOException
Analizador analizador = nuevo StandardAnalyzer (versión.Lucene_46);
IndexwriterConfig config = new IndexWriterConfig (versión.Lucene_46,
analizador);
Indexwriter indexwriter = new IndexWriter (FSDirectory.Abrir (indexdir),
config);
Archivo [] archivos = DataDir.listFiles ();
para (archivo f: archivos)
Sistema.afuera.println ("archivo de indexación" + F.getCanonicalPath ());
Documento doc = nuevo documento ();
doc.agregar (nuevo TextField ("Contenido", New FileReader (f)));
doc.add (nuevo storedfield ("nombre de archivo", f.getCanonicalPath ()));
Indexwriter.addDocument (DOC);

int numIndexed = indexWriter.maxdoc ();
Indexwriter.cerca();
devolver numindexed;

En este código, acabamos de hacer una instancia de documento y agregamos un nuevo campo que representa el contenido del archivo. Aquí está la salida que obtenemos cuando ejecutamos este archivo:

Archivo de indexación/usuarios/shubham/en algún lugar/lh-luceneExample/src/main/java/com/linuxhint/ejemplo/simplizindexer.Java
Total de archivos indexados 1

Además, se crea un nuevo directorio dentro del proyecto con el siguiente contenido:

Datos índice

Analizaremos qué se crean todos los archivos en estos índice en más lecciones para venir Lucene.

Conclusión

En esta lección, observamos cómo funciona Apache Lucene y también hicimos una aplicación de ejemplo simple que se basó en Maven y Java.