Cassandra e Lucene: trabalhando com banco NOSQL em Java
Veja neste artigo como trabalhar com a API Apache Lucene e o banco de dados Apache Cassandra em projetos Java e como a união dessas duas ferramentas pode ser uma ótima solução para trabalhar com grandes volumes de dados.
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:
- O usuário estará cadastrando o currículo com suas informações.
- A partir dessas informações a analista de recursos humanos estará buscando o profissional.
- 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 precisa ser ú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:
- Solr
- Hibernate Search
- Conhecendo o Lucene, PAULO SIGRIST e WILSON AKIO HIGASHINO, java Magazine 104, devmedia.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo