miércoles, 6 de mayo de 2009

Lucene crear índice y buscar

Ya que he estado trabajando con Lucene, lo mejor será anotar lo aprendido.
Este es un ejemplo básico de Lucene.

* Creación de un índice, en este caso se guarda en el índice la descripción del producto y su Id.


public void crearIndice(File indexDir, Analyzer analyzer, List productos) throws CorruptIndexException, LockObtainFailedException, IOException {
IndexWriter writer = new IndexWriter(indexDir, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
writer.setUseCompoundFile(false);

for (Producto producto : productos) {
Document doc = new Document();
doc.add(new Field("descripcion", producto.getDescripcion(), Field.Store.YES, Field.Index.ANALYZED));
doc.add(new Field("id", producto.getId() + "", Field.Store.YES, Field.Index.NO));
writer.addDocument(doc);
}
writer.optimize();
writer.commit();
writer.close();
}


indexDir: directorio donde se crearán los archivos de Lucene.
Document: el índice esta compuesto por documentos, en este ejemplo, cada documento representa un producto (id, descripción).
analyzer: analizador, en este ejemplo se usa StandarAnalyzer que transforma el texto a minúsculas, elimina los caracteres no alfanuméricos y separa las palabras, ver más abajo ejemplo de StandarAnalyzer.
Field.Store.YES: Se almacena el texto.
Field.Index.ANALYZED: Se analiza el texto, lo que permitirá buscar por una o más palabras del texto.

Ejemplo de StandarAnalyzer:

public class TestStandardAnalyzer {
public static void main(String[] args) throws IOException {
Analyzer analyzer = new StandardAnalyzer();
TokenStream resultado = analyzer.tokenStream("", new StringReader("Éste es un-texto + analizado // por StandarAnalyzer 123"));
Token token = new Token();
while ((token = resultado.next(token)) != null) {
System.out.println("analyzer: " + token.term());
}
}
}

El resultado es:

analyzer: éste
analyzer: es
analyzer: un
analyzer: texto
analyzer: analizado
analyzer: por
analyzer: standaranalyzer
analyzer: 123



* Búsqueda en el índice:


public List buscar(File indexDir, Analyzer analyzer, String texto) throws CorruptIndexException, IOException, ParseException {
List productos = new ArrayList();
IndexSearcher is = new IndexSearcher(FSDirectory.getDirectory(indexDir));
QueryParser qp = new QueryParser("descripcion", analyzer);
qp.setDefaultOperator(QueryParser.AND_OPERATOR);
Query query = qp.parse(texto);
TopDocCollector collector = new TopDocCollector(100);
is.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;

for (int i = 0; i < hits.length; i++) {
int docId = hits[i].doc;
Document doc = is.doc(docId);
Producto p = new Producto();
p.setId(Integer.parseInt(doc.get("id")));
p.setDescripcion(doc.get("descripcion"));
productos.add(p);
}
is.close();
return productos;
}


QueryParser("descripcion", analyzer): indica por cual campo realizaremos la búsqueda, en este ejemplo sólo podemos buscar por "descripción".
qp.setDefaultOperator(QueryParser.AND_OPERATOR): se debe aplicar el operador lógico AND, es decir, si la búsqueda es por dos o más palabras, sólo debe entregar los documentos donde estén todas las palabras.
Query query = qp.parse(texto): Transforma el texto para su búsqueda. Ver más abajo ejemplo de QueryParser.
is.search(query, collector): ejecuta la búsqueda y el resultado queda en collector.

Ejemplo de QueryParser:

public class TestQueryParser {
public static void main(String[] args) throws ParseException {
QueryParser qp = new QueryParser("descripcion", new StandardAnalyzer());
qp.setDefaultOperator(QueryParser.AND_OPERATOR);
Query query = qp.parse("iPod nano");
System.out.println("Con AND_OPERATOR: " + query);
qp.setDefaultOperator(QueryParser.OR_OPERATOR);
query = qp.parse("iPod nano");
System.out.println("Con OR_OPERATOR: " + query);
}
}

El resultado es:

Con AND_OPERATOR: +descripcion:ipod +descripcion:nano
Con OR_OPERATOR: descripcion:ipod descripcion:nano



Ejemplo completo:

public class Indice {
public static void main(String[] args) throws CorruptIndexException, LockObtainFailedException, IOException, ParseException {
File indexDir = new File("/tmp/productos");
Analyzer analyzer = new StandardAnalyzer();
List productos = new ArrayList();
Producto p = new Producto(1, "iPod mini");
productos.add(p);
p = new Producto(2, "iPod shuffle");
productos.add(p);
p = new Producto(3, "iPod touch");
productos.add(p);

Indice indice = new Indice();
indice.crearIndice(indexDir, analyzer, productos);
System.out.println("Indice creado");

List resultado = indice.buscar(indexDir, analyzer, "ipod mini");
System.out.println("Resultado: " + resultado.size() + " producto(s)");
for (Producto producto : resultado) {
System.out.println("id: " + producto.getId() + " producto: " + producto.getDescripcion());
}
}

public void crearIndice(File indexDir, Analyzer analyzer, List productos) throws CorruptIndexException, LockObtainFailedException, IOException {
IndexWriter writer = new IndexWriter(indexDir, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
writer.setUseCompoundFile(false);

for (Producto producto : productos) {
Document doc = new Document();
doc.add(new Field("descripcion", producto.getDescripcion(), Field.Store.YES, Field.Index.ANALYZED));
doc.add(new Field("id", producto.getId() + "", Field.Store.YES, Field.Index.NO));
writer.addDocument(doc);
}
writer.optimize();
writer.commit();
writer.close();
}

public List buscar(File indexDir, Analyzer analyzer, String texto) throws CorruptIndexException, IOException, ParseException {
List productos = new ArrayList();
IndexSearcher is = new IndexSearcher(FSDirectory.getDirectory(indexDir));
QueryParser qp = new QueryParser("descripcion", analyzer);
qp.setDefaultOperator(QueryParser.AND_OPERATOR);
Query query = qp.parse(texto);
TopDocCollector collector = new TopDocCollector(100);
is.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;

for (int i = 0; i < hits.length; i++) {
int docId = hits[i].doc;
Document doc = is.doc(docId);
Producto p = new Producto();
p.setId(Integer.parseInt(doc.get("id")));
p.setDescripcion(doc.get("descripcion"));
productos.add(p);
}
is.close();
return productos;
}
}




Leer más...