Lucene – Exemplo de indexação e busca

Este exemplo aborda uma forma simples de indexação e busca de documentos utilizando a API do Apache Lucene, na sua atual versão 3.6. Ela pode ser baixada aqui e para utilizar em seu projeto, basta incluir a lib lucene-core-3.6.0.jar em seu classpath.

Criando o índice e definindo os termos dos documentos:

Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);

FSDirectory indexDir = FSDirectory.open(new File("/index"));
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, analyzer);
IndexWriter iw = new IndexWriter(indexDir, iwc);

final String FIELD_LINK = "link";
final String FIELD_POST = "post";

Na primeira linha definimos qual será o analisador tanto para a indexação, quanto a que será utilizada no momento da busca. Neste caso utilizarei a Standard, mas já se tem disponível o analyzer em diversas linguagens e também pode-se criar um próprio, se necessário.

Após é feito a criação e abertura do índice. Neste caso, utilizando um índice gravado em disco através da classe FSDirectory. Dependendo da necessidade, pode-se usar a classe RAMDirectory para trabalhar com o índice todo somente em memória.

FIELD_LINK e FIELD_POST são os dois campos de exemplos deste índice, indicando o link de uma página e o seu conteúdo, respectivamente.

Inserindo um documento no índice:

Document doc1 = new Document();
doc1.add(new Field(FIELD_LINK, "http://www.coffeecode.com.br/?doc=1", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
doc1.add(new Field(FIELD_POST, "teste de busca em um texto livre", Field.Store.YES, Field.Index.ANALYZED));
iw.addDocument(doc1);

Document doc2 = new Document();
doc2.add(new Field(FIELD_LINK, "http://www.coffeecode.com.br/?doc=2", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
doc2.add(new Field(FIELD_POST, "outro texto para busca", Field.Store.YES, Field.Index.ANALYZED));
iw.addDocument(doc2);

iw.commit();

O Lucene trabalha com documentos, então cada entrada de dados será um documento com seus campos. Assim, instanciamos a classe Document e definimos quais serão seus campos, o valor, se este valor será recuperado ou apenas buscável e se ele deve passar pelo analisador.

Feito isto, os dois documentos já estão indexados e prontos para serem buscados. Sendo assim, partimos para a busca!

IndexReader ir = IndexReader.open(indexDir);
IndexSearcher is = new IndexSearcher(ir);

PhraseQuery pq = new PhraseQuery();
pq.add(new Term(FIELD_POST, "livre"));

TopDocs td = is.search(pq, 10);
for(ScoreDoc sdoc : td.scoreDocs) {
	Document d = is.doc(sdoc.doc);
	System.out.println("Link: "+d.get(FIELD_LINK));
	System.out.println("Post: "+d.get(FIELD_POST));
}

Com a classe IndexReader deixamos disponível o índice para leitura e utilizamos a IndexSearcher para passar a query e recuperar os documentos. Aqui podemos usar diversos tipos de implementações da classe Query, como a PhraseQuery, BooleanQuery, MultiPhraseQuery, TermQuery, entre outras.

A busca, neste caso, será pela palavra “livre” em cima do campo indexado post. Ela pode retornar um objeto TopDocs que contém os documentos que bateram com o termo buscado. A partir deles pode-se acessar diretamente o índice e retornar os campos desejados.