Cassandra + Lucene

         Atualmente existem diversas características dos bancos NOSQL, em diferentes arquiteturas, formas de armazenamento de informação e estruturas de dados. No entanto apesar dessa grande variedade no número e variedades eles compartilham uma coisa em comum. Eles normalmente buscam pela chave primária. Apesar de conseguir-se manter altamente disponível, inserir e recuperar informações de forma bastante rápida, o fato de que a maioria dos bancos NOSQL somente recuperem pela chave, torna um pouco difícil adaptar a aplicação para o seu uso, já que nem sempre você consegue buscar apenas pela chave no banco. Para não abrir mão da alta disponibilidade e recuperar informações não apenas em chave, uma boa opção certamente é “terceirizar” esse serviço. Por esse motivo será apresentado o Lucene trabalhando em conjunto com um banco nosql, mais precisamente o Cassandra, juntando o bom de dois mundos em sua aplicação.
O Apache Lucene é uma API de busca e indexação de documentos, escrito em Java. Ele é composto por basicamente duas etapas: indexação e pesquisa. Dado o texto primeiro passo é a indexação que processa os dados originais e gera uma estrutura que facilita a busca e gera palavras-chaves, em seguida vem à busca que visa estar buscando a partir das palavras-chaves indexadas e retorna pela semelhança do texto com a consulta. A vantagem é que o Lucene abstrai ao ponto que não é necessário que o desenvolvedor saiba algoritmo de indexação. Os índices podem ser criados em ambientes distribuídos, aumentando o desempenho e a escalabilidade da ferramenta.
Apresentado um pouco da ferramenta o objetivo agora será apresentar uma prática envolvendo os dois mundos: banco nosql e o Lucene. Para essa parte prática será feita uma aplicação com o objetivo de estar cadastrando currículos. A idéia é bastante simples:

  1. O usuário estará cadastrando o currículo com suas informações.
  2. A partir dessas informações a analista de recursos humanos estará buscando o profissional.
  3. O profissional poderá ser buscado pela palavra chave de uma qualificação técnica, localização, Profissão.
Como o objetivo da aplicação será web, estaremos utilizando a plataforma Java EE em sua versão mais recente, a versão 6.0.
      No Lucene os índices são armazenados a partir da interface Direcoty que no momento que eu escrevo possui basicamente duas implementações: Uma para armazenar na memória RAM e para armazenar no disco rígido. Como o objetivo é garantir uma alta disponibilidade estaremos utilizando a opção de estar trabalhando com os índices na memória RAM, mas para não perdemos tais índices estaremos fazendo um backup no disco rígido. Para fazer tal procedimento, usaremos o recurso schedule do EJB 3.1 para de tempos em temos, jogar o que está na memória para o HD.

@Schedule(minute = "*/1", hour = "*")
public void reindex() {

try {
Directory disco = FSDirectory.open(new File(Constantes.getIndexDirectory()));
luceneManager.backup(directory, disco);

}
catch (Exception e) {
Logger.getLogger(ScheduleService.class.getName()).log(Level.SEVERE,
null, e);
}

}

    

    Desse modo quando a aplicação cair e levantar novamente basta estar carregando as informações do disco para a memória principal novamente. Vale salientar que o diretório precisar único para toda a aplicação.

 
@ApplicationScoped
public class LuceneManager implements Serializable{

private static final long serialVersionUID = -8280220793266559394L;

@Produces
private Directory directory;


@Inject
public void init() {
directory = new RAMDirectory();
try {
levantarServico();
} catch (IOException e) {
Logger.getLogger(LuceneManager.class.getName()).log(Level.SEVERE,
null, e);
}
}

public void levantarServico() throws IOException {
Directory disco = FSDirectory.open(new File(Constantes.getIndexDirectory()));
backup(disco, directory);
}

public void backup(Directory deDiretorio, Directory paraDiretoria) throws IOException {

for (String file : deDiretorio.listAll()) {
deDiretorio.copy(paraDiretoria, file, file); // newFile can be either file, or a new name
}
}

}

    Uma vez criado o diretório e definido onde estarão as informações o próximo passo é criar os índices, conforme falado anteriormente ele será a chave tanto para a inserção quando a busca das informações. Agora o que falta é a criação do Document que representa para a troca de informações entre o Lucene e sua aplicação. Ele é composto por campos que por sua vez por informações. A relação entre o Lucene e a aplicação se dará da seguinte forma:

  • A chave será armazenada e não indexada.
  • O estado não armazenado e não indexado.
  • O conteúdo do currículo será não armazenado e indexado.

  

private Document criarDocumento(Pessoa pessoa) throws IOException {
Document document = new Document();

document.add(new Field(Constantes.ESTADO_INDICE,pessoa.getEndereco().getEstado(), Store.YES,
Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field(Constantes.ID_INDICE,pessoa.getNickName(), Store.YES,
Index.NOT_ANALYZED_NO_NORMS,TermVector.WITH_POSITIONS_OFFSETS));

document.add(new Field(Constantes.TUDO, getConteudoCurriculo(pessoa), Store.NO,
Index.ANALYZED));

return document;
}

Uma vez essa informação armazenada no Cassandra e indexada no Lucene, o ciclo da aplicação se dará da seguinte forma:
  • A seqüência segue um processo simples:
  • O usuário adiciona as informações e envia ao servidor
  • A informação é persistida no Cassandra
  • A informação é indexada e é armazenado o id no Lucene
  • Quando o analista de RH fizer a busca é recuperado um Document que por sua vez retorna a informação da chave, assim poderá se recuperada todas as informações no Cassandra.

         Pronto! Dessa forma quanto a inserção quanto a busca serão feitas de maneiras rápidas, o Cassandra possui o recurso de índices secundários que permite que existam campos de busca além da chave, mas isso faz com que o banco perca velocidade com o crescimento desses campos especiais. Uma outra forma de deixar a busca ainda mais rápida seria deixar os resultados dessa busca em um cachê, mas isso serão cenas para um próximo capítulo.

Falando um pouco mais sobre o Lucene existem alguns frameworks que já se integram com o Lucene. É o caso do hibernate search que é o hiberante, para banco relacional, utilizando o Lucene, solr é um servidor de busca que usa o Lucene como motor de busca e o solandra que é um solr para o Cassandra.
Nesse artigo foi apresentado um problema existente na maioria dos bancos NOSQL, a busca de campos além da chave. Para resolver tal problema foi demonstrado um trabalho em conjunto com o Lucene, ferramenta de indexação de documentos, além de apresentar alguns conceitos da ferramenta.
Referências: 
Conhecendo o Lucene, PAULO SIGRIST e WILSON AKIO HIGASHINO, java Magazine 104, devmedia.

Código Fonte: http://softwarelivre.org/otagonsan/codigofonte/cassandra-lucene.rar

Anúncios

Um comentário sobre “Cassandra + Lucene

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s