El presente articulo (uno de varios que espero publicar), muestra como hacer una pequeña introducción a la indexación con Apache Lucene.
Este ejemplo, esta basado en el libro Lucene In Action, pero fue adecuado para funcionar con la versión 3.0 en lugar de la versión 2.0 que se comenta en el libro.
Veamos el siguiente ejemplo y comentemos al respecto:
El ejemplo anterior, muestra la clase IndexerExample. El mismo en términos generales crea un indice invertido, indexando solo archivos extensión .txt, de una carpeta en particular pasada por parámetro y almacenando los segmentos del indice en otro directorio.
La linea 28, simplemente checkea que se envíen al main, dos parámetros, el primero es trata de la carpeta para almacenar el indice y la segunda, la carpeta con los archivos que deseo indexar; el sistema realiza indexación recursiva de directorio.
Seguidamente se invoca al método “makeIndex”, y simplemente se invoca al método de la clase “doIndex”, que retorna la cantidad de archivos indexados.
La siguiente linea, que nos debe interesar es la 76; la misma crea nuestra clase para escribir el indice “IndexWriter”; el primer argumento es un Directory object, el mismo puede tratarse de:
Un directorio en RAM, el cual puede ser útil para indexar unos datos en memoria y consultarlos. Esto por supuesto proporciona mayor velocidad al tener que evitar el acceso al disco duro para leer el archivo, aunque los S.O modernos cuentan con mecanismos de cache, que proporcionan un desempeño bastante aceptable.
También existen dos posibilidades mas, almacenarlo en un directorio en el disco duro (la opción que estamos utilizando) y en base de datos.
El siguiente argumento, se trata del analizador de texto, el mismo sirve para tokenizar, eliminar palabras con poca relevancia o aplicar algoritmos para la optimización del texto, en nuestro caso utilizamos una versión muy sencilla, pero existen analizadores para diferentes idioma o corpus de información para lucene, agregado como contribuciones.
El tercer argumento indica al IndexWriter que se desea o no crear un nuevo indice, en caso que sea false el argumento, el indice será actualizado y no remplazado o creado de cero.
Por ultimo, se indica si deseamos limitar o no, el tamaño de los campos a guardar.
Método DoIndexDirectory
Linea 109, esta linea simplemente obtiene todos los archivos con extensión “txt” o directorios.
A continuación en la linea 118, se iteran todos los archivos, en caso de tratarse de un directorio se indexan los elementos dentro del mismo, de lo contrario se indexa el contenido del archivo “txt”, utilizando para tal objetivo el método: “doIndexFile”.
Método doIndexFile
En la linea 143, se determina si el archivo no es oculto, existe y se puede leer (asunto de permisos)
A continuación creamos el objeto Documento (Document; en Lucene, los objetos indexado son tratados como documentos, el mismo se conceptualiza como una colección de campos, llave, valor, similar a un hash table)
Una vez creado el documento, agregamos al mismo dos campos; 'contents' y 'filename'; el primero es almacenado por defecto como un campo indexado, pero no guardado, lo que quiere decir que el texto indexado no se almacena para su posterior recuperación pero si quedan indexado su contenido, por su lado filename, simplemente se trata de meta información, no es indexada (osea que no se podrá buscar por este campo), pero se volverá parte de los resultado al buscar en contents.
Si seguimos este sencillo flujo y volvemos al método 'doIndex' notaremos los llamados a 'optimize' y 'close'. La invocación del primero permite que Lucene utilice algoritmos de optimizacion sobre el indice, similar a un VACUM en una base de datos, se realiza cuando existen muchas actualizaciones en la base de datos.
El método close, simplemente cierra el indice y probablemente libera algunos recursos que ya no necesitamos utilizar.
Así pues, después de recorrer todo este código y ejecutarlo utilizando alguna colección de archivos de texto veremos que se genera una serie de archivos binarios, en próximos artículos, mostraremos como utilizar estos archivos para hacer búsquedas utilizando varios tipos de consultas.
Este ejemplo, esta basado en el libro Lucene In Action, pero fue adecuado para funcionar con la versión 3.0 en lugar de la versión 2.0 que se comenta en el libro.
Veamos el siguiente ejemplo y comentemos al respecto:
package org.crjug.lucene.example1;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
/**
* Ejemplo sencillo de como utilizar el indexador.
*
* @author jsanca
*
*/
public class IndexerExample {
public static void main(String[] args) throws IOException {
if (2 != args.length) {
System.out.println("Use como: java "
+ IndexerExample.class.getName()
+ "");
} else {
makeIndex(args[0], args[1]);
}
} // main.
public static void makeIndex (String sindexDir, String sdataDir) throws IOException {
File indexDir = null;
File dataDir = null;
int numDocsIndexed = 0;
IndexerExample indexer = new IndexerExample ();
indexDir = new File(sindexDir);
dataDir = new File(sdataDir);
numDocsIndexed = indexer.doIndex(indexDir, dataDir);
System.out.println("Numero de documentos indexados: "
+ numDocsIndexed);
} // makeIndex.
/**
* Indexa un directorio (dataDir) y almacena los segmentos del indice en (indexDir)
* @param indexDir
* @param dataDir
* @return Retorna el numero de documento indexados.
* @throws IOException
*/
private int doIndex(File indexDir, File dataDir) throws IOException {
int numDocsIndexed = 0;
IndexWriter indexWriter = null;
boolean createIndex = true;
// Determino si el directorio a indexar, es realmente
// un directorio y existe.
if (!dataDir.exists() || !dataDir.isDirectory()) {
throw new IOException(dataDir + ", no existe o no es un directorio");
}
indexWriter = new IndexWriter(
// Pueden ser directorios virtuales basado en RAM, BD o Archivos.
new SimpleFSDirectory(indexDir),
// El analizador de texto por defecto.
new StandardAnalyzer(Version.LUCENE_30),
// Deseo crear el indice.
createIndex,
// No me preocupa limitar el tamaNo de los campos.
IndexWriter.MaxFieldLength.UNLIMITED);
indexWriter.setUseCompoundFile(false);
// Indexo el directorio.
this.doIndexDirectory (indexWriter, dataDir);
// Obtengo los archivos indexado (aunque no esten merge)
numDocsIndexed = indexWriter.numDocs();
// Llamo al optimizador.
indexWriter.optimize();
// No voy a escribir, cierro el indice.
indexWriter.close();
return numDocsIndexed;
} // doIndex.
/**
* Indexa un directorio en particular.
* @param indexWriter
* @param dataDir
* @throws IOException
*/
private void doIndexDirectory(IndexWriter indexWriter, File dataDir) throws IOException {
File[] files = dataDir.listFiles(new FileFilter () {
// Filtramos para solo leer archivos txt y directorios
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getName().endsWith(".txt");
}
});
// Recorro archivos y directorios.
for (File file : files) {
if (file.isDirectory()) { // si es un directorio, entro y lo recorro
this.doIndexDirectory(indexWriter, file);
} else {
// Si es un archivo lo leo e indexo.
this.doIndexFile (indexWriter, file);
}
}
} // doIndexDirectory.
/**
* Realiza la indexacion de un archivo plano.
* @param indexWriter
* @param file
* @throws IOException
*/
private void doIndexFile(IndexWriter indexWriter, File file) throws IOException {
Document document = null;
// Si no es un archivo oculto
// si existe
// y puedo leerlo.
if (!file.isHidden() && file.exists() && file.canRead()) {
System.out.println("Indexando: " + file.getCanonicalPath());
document = new Document ();
// Agrega un campo de texto indexado pero no almacenado.
document.add(new Field("contents", new FileReader (file)));
// Es almacenado pero no indexado, sirve viene como parte de los resultados
// pero no se desea hacer busquedas por el nombre del archivo.
document.add(new Field ("filename", file.getCanonicalPath(), Store.YES, Index.NO));
// Finalmente agrego el archivo al indice.
indexWriter.addDocument(document);
}
} // doIndexFile.
} // E:O:F:IndexerExample.
El ejemplo anterior, muestra la clase IndexerExample. El mismo en términos generales crea un indice invertido, indexando solo archivos extensión .txt, de una carpeta en particular pasada por parámetro y almacenando los segmentos del indice en otro directorio.
La linea 28, simplemente checkea que se envíen al main, dos parámetros, el primero es trata de la carpeta para almacenar el indice y la segunda, la carpeta con los archivos que deseo indexar; el sistema realiza indexación recursiva de directorio.
Seguidamente se invoca al método “makeIndex”, y simplemente se invoca al método de la clase “doIndex”, que retorna la cantidad de archivos indexados.
La siguiente linea, que nos debe interesar es la 76; la misma crea nuestra clase para escribir el indice “IndexWriter”; el primer argumento es un Directory object, el mismo puede tratarse de:
Un directorio en RAM, el cual puede ser útil para indexar unos datos en memoria y consultarlos. Esto por supuesto proporciona mayor velocidad al tener que evitar el acceso al disco duro para leer el archivo, aunque los S.O modernos cuentan con mecanismos de cache, que proporcionan un desempeño bastante aceptable.
También existen dos posibilidades mas, almacenarlo en un directorio en el disco duro (la opción que estamos utilizando) y en base de datos.
El siguiente argumento, se trata del analizador de texto, el mismo sirve para tokenizar, eliminar palabras con poca relevancia o aplicar algoritmos para la optimización del texto, en nuestro caso utilizamos una versión muy sencilla, pero existen analizadores para diferentes idioma o corpus de información para lucene, agregado como contribuciones.
El tercer argumento indica al IndexWriter que se desea o no crear un nuevo indice, en caso que sea false el argumento, el indice será actualizado y no remplazado o creado de cero.
Por ultimo, se indica si deseamos limitar o no, el tamaño de los campos a guardar.
Método DoIndexDirectory
Linea 109, esta linea simplemente obtiene todos los archivos con extensión “txt” o directorios.
A continuación en la linea 118, se iteran todos los archivos, en caso de tratarse de un directorio se indexan los elementos dentro del mismo, de lo contrario se indexa el contenido del archivo “txt”, utilizando para tal objetivo el método: “doIndexFile”.
Método doIndexFile
En la linea 143, se determina si el archivo no es oculto, existe y se puede leer (asunto de permisos)
A continuación creamos el objeto Documento (Document; en Lucene, los objetos indexado son tratados como documentos, el mismo se conceptualiza como una colección de campos, llave, valor, similar a un hash table)
Una vez creado el documento, agregamos al mismo dos campos; 'contents' y 'filename'; el primero es almacenado por defecto como un campo indexado, pero no guardado, lo que quiere decir que el texto indexado no se almacena para su posterior recuperación pero si quedan indexado su contenido, por su lado filename, simplemente se trata de meta información, no es indexada (osea que no se podrá buscar por este campo), pero se volverá parte de los resultado al buscar en contents.
Si seguimos este sencillo flujo y volvemos al método 'doIndex' notaremos los llamados a 'optimize' y 'close'. La invocación del primero permite que Lucene utilice algoritmos de optimizacion sobre el indice, similar a un VACUM en una base de datos, se realiza cuando existen muchas actualizaciones en la base de datos.
El método close, simplemente cierra el indice y probablemente libera algunos recursos que ya no necesitamos utilizar.
Así pues, después de recorrer todo este código y ejecutarlo utilizando alguna colección de archivos de texto veremos que se genera una serie de archivos binarios, en próximos artículos, mostraremos como utilizar estos archivos para hacer búsquedas utilizando varios tipos de consultas.
Comentarios