Introducción
Lucene es un motor de búsqueda de Apache. Está implementado en Java (http://lucene.apache.org) y es usado en multitud de gestores de contenido.Lucene indexa texto, no trabaja directamente sobre ningún formato de fichero concreto. Por tanto, para indexar "documentos", previamente deberá extraerse su contenido con las librerías adecuadas.
Dado cualquier texto, Luceneindexa por defecto las primeras 1000 palabras.
Algunas librerías típicas para menejar los documentos más comunes son:
PDF. JPedal (http://www.jpedal.org/).
Microsoft Word, Excel, Visio y Power Point. Apache POI (http://poi.apache.org/)
OpenOffice. LIUS (http://www.bibl.ulaval.ca/lius/).
RTF. Swing RTFEditorKit class.
Una vez indexado el contenido de un "documento", se podrán efectuar búsquedas sobre los índices generados. Al efectuarse las búsquedas sobre los índices estas son siempre más rápidas que búsquedas sobre los "documentos".
Componentes de Lucene
En Lucene trabaja con tres conceptos esenciales:- Documentos. Un documento, para Lucene, es una tupla de N campos. Cada campo tiene un nombre y contiene cierto tipo de información.
- Campos. Es cada una de las categorías de información que componen el documento.
- Querys. Para realizar las búsquedas en el índice, Lucene ofrece un lenguaje de consultas, que permite especificar en qué campos buscar, admite comodines, admite AND, OR y NOT, admite búsquedas por proximidad, etc.
- Agenda. En una agenda de contactos, un documento sería cada una de las fichas de la agenda. Los campos serían, por ejemplo, el nombre, el primer apellido, el segundo apellido, el teléfono móvil, el teléfono fijo, etc
- Biblioteca. En una biblioteca, un documento sería cada uno de los libros. Los campos serían, por ejemplo: título, autor, estantería, contenido, ISBN, etc.
- Lista de libros donde el autor sea "Phillip"
- Lista de libros donde el autor sea "Philip K Dick"
- Lista de libros donde el autor sea "Philip K Dick", en el contenido del libro aparezca "ovejas"
Apliación Java de ejemplo
Hemos montado un proyecto Maven2 con las siguientes dependencias:<dependencies>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
Adjuntamos un ejemplo en Java donde se montará el índice de una biblioteca, añadiendo varios documentos y efectuando algunas búsquedas.
import java.io.File;
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.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
public class AppTest {
public static void main(String[] args) throws IOException, ParseException, InvalidTokenOffsetsException {
//Fijamos el analizador para tokenizar, indezar y buscar en textos
final StandardAnalyzer analizador = new StandardAnalyzer(Version.LUCENE_40);
//Creamos el indice en memoria RAM
final Directory indice = new RAMDirectory();
final IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_40, analizador);
//Montamos el generador del índice
final IndexWriter iw = new IndexWriter(indice, config);
//Nuestros documentos serán libros con tres campos: titulo, autor y contenido.
//Añadimos un par de libros, los ficheros txt con el contenido de los mismos están en el classpath
addLibro(iw, "El ingenioso hidalgo Don Quijote de la Mancha", "Miguel de Cervantes y Saavedra", new File("Quijote.txt"));
addLibro(iw, "El Buscón", "Francisco Gómez de Quevedo y Santibáñez Villegas", new File("Buscon.txt"));
//Cerramos el generador de índice
iw.close();
//Lanzamos algunas querys
lanzaConsulta(analizador, indice, "autor:Cervantes");
lanzaConsulta(analizador, indice, "autor:\"de Cervantes y\"");
lanzaConsulta(analizador, indice, "autor:Cervan*");
lanzaConsulta(analizador, indice, "autor:Cervantes AND titulo:hidalgo");
lanzaConsulta(analizador, indice, "autor:Cervantes OR autor:Quevedo");
lanzaConsulta(analizador, indice, "(autor:Cervantes OR autor:Quevedo) AND NOT titulo:Quijote");
//Algunas querys de búsqueda por proximidad, esto es palabras parecidas a la nuestra
//pudiendo diferenciase en N caracteres
lanzaConsulta(analizador, indice, "contenido:Tocoso~1"); //Buscamos a Dulcinea del "Tocoso" sabiendo que es algo parecido
}
private static void addLibro(final IndexWriter iw,
final String titulo,
final String autor,
final File f) throws Exception {
//Montamos el documento
final Document libro = new Document();
//Le añadimos el atributo titulo
libro.add(new TextField("titulo", titulo, Field.Store.YES));
//Le añadimos el atributo autor
libro.add(new TextField("autor", autor, Field.Store.YES));
//Le añadimos el atributo contenido
libro.add(new TextField("contenido", new FileReader(f)));
//Le añadimos la ubicacion del fichero
libro.add(new TextField("fichero", f.getCanonicalPath(), Field.Store.YES));
//Damos de alta el documento
iw.addDocument(libro);
}
private static void lanzaConsulta(final StandardAnalyzer analizador,
final Directory indice,
final String query) throws ParseException, IOException {
//Montamos el parseador de Querys. El segundo parámetro es el campo por defecto donde
//se realizarán las búsquedas si una query no indica ningún campo concreto
final QueryParser queryParser = new QueryParser(Version.LUCENE_40, "titulo", analizador);
final Query q = queryParser.parse(query);
//Montamos el buscador
final IndexReader reader = DirectoryReader.open(indice);
final IndexSearcher searcher = new IndexSearcher(reader);
//Lanzamos la query
final int numMaxResults = 10;
final TopDocs docsEncontrados = searcher.search(q,numMaxResults);
System.out.println("Total hits "+docsEncontrados.totalHits);
//Recuperamos la lista de coincidencias
final ScoreDoc[] docs = docsEncontrados.scoreDocs;
//Mostramos los resultados
System.out.println("-------------------------------------------------------------------");
System.out.println("Encontradas " + docsEncontrados.totalHits + " coincidencias para '"+query);
int idDoc;
int index;
float score;
Document doc;
for(int i=0;i<docs.length;++i) {
idDoc = docs[i].doc;
score = docs[i].score;
index = docs[i].shardIndex;
doc = searcher.doc(idDoc);
System.out.println(String.format("%d. [%f] \t %s \t %s",index,score,doc.get("titulo"),doc.get("autor")));
}
System.out.println("-------------------------------------------------------------------");
}
}
Enlaces de interés
http://wiki.apache.org/lucene-java/LuceneFAQ
http://www.lucenetutorial.com/
No hay comentarios:
Publicar un comentario