Introdução ao Hibernate Search

Veja neste artigo o que é o Hibernate Search e como podemos criar uma aplicação com este framework.

Hibernate Search permite aos desenvolvedores utilizarem facilmente o Apache Lucene com nosso modelo de objetos do Hibernate. Lucene é uma engine de pesquisa de código aberto livremente disponível. O Apache Lucene analisa uma grande quantidade de textos e criar uma pesquisa indexada. O Lucene, por si só, é um componente que provê funcionalidades de pesquisa no seu núcleo principal, incluindo análise, indexação e consulta. Nossa aplicação se integra com o Lucene para fornecer conteúdo para indexação e consultas para executar contra a indexação.

Isso pode ser frustrante quando se trabalha com Hibernate porque há uma incompatibilidade entre Lucene e objetos Java que usam Hibernate, similar a incompatibilidade objeto/relacional. No entanto, o Hibernate Search vem para terminar com essa inconsistência.

Por trás da funcionalidade de pesquisa do Hibernate Search está o Apache Lucene, uma biblioteca de código-fonte aberto para indexação e pesquisa. O Apache Lucene é considerado um projeto Java com uma rica história de inovação, embora ainda possa ser portada para outras linguagens de programação, não se limitando apenas ao Java. O Apache Lucene é adotado em uma grande variedade de projetos na indústria, entre eles se destacam a Disney e o Twitter.

Um projeto inter-relacionado ao Apache Lucene é o Apache Solr, que é um servidor de pesquisa standalone baseado no Lucene.

No restante do artigo veremos mais sobre o Hibernate Search, seu funcionamento, as suas principais características e exemplos.

Funcionamento

O Hibernate Search é um “empacotador magro” ou um thin wrapper que abrange o Lucene e um componente opcional Solr. Ele estende o núcleo principal do Hibernate ORM, o mais utilizado framework de mapeamento objeto/relacional para Persistência Java.

A Figura 1 mostra o relacionamento entre todos esses componentes citados:

Figura 1. Relacionamento entre os componentes.

As últimas versões do Hibernate Search envolvem dois papeis principais:

O Hibernate Search esconde a maior parte do baixo nível realizado através do Lucene.

Aplicação de Exemplo

Para incorporar o Hibernate Search na nossa aplicação precisamos realizar três passos:

  1. Adicionar informação às nossas classes de entidades para que o Lucene saiba como indexa-las.
  2. Escrever uma ou mais consultas nas porções relevantes da aplicação.
  3. Configurar o projeto para que as dependências necessárias e a configuração para o Hibernate Search estejam disponíveis primeiramente.

Portanto, a primeira situação a ser feita é criar uma classe de entidade como mostrada abaixo. A classe de entidade exemplifica um login que exige um nome de usuário e senha. Observe a Listagem 1.

Listagem 1. Exemplo de uma classe de entidade.

package exemplo.hibernatesearch; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; @Entity @Table(name="login", schema="public") public class Login { @Id @GeneratedValue(generator="increment") @GenericGenerator(name="increment", strategy = "increment") private int id; @Column private String usuario; @Column private String senha; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsuario() { return usuario; } public void setUsuario(String usuario) { this.usuario = usuario; } public String getSenha() { return senha; } public void setSenha(String senha) { this.senha = senha; } }

A classe acima diz ao Hibernate para que a classe seja mapeada para uma tabela de uma base de dados.

Agora devemos preparar essa classe de entidade para o Hibernate Search. Dessa forma, o Hibernate Search saberá como gerenciar essa classe com o Lucene.

Para isto, devemos adicionar a anotação @Indexed na classe, conforme mostrado na Listagem 2.

Listagem 2. Adicionando a anotação para o Hibernate Search.

@Entity @Indexed @Table(name="login", schema="public") public class Login { … }

Este exemplo declara que o Lucene deveria construir e usar uma indexação para este classe de entidade. Esta anotação é opcional. Quando escrevermos uma aplicação de larga escala, muitas das classes de entidades podem não ser relevantes para pesquisa. O Hibernate Search apenas necessita dizer ao Lucene sobre esses tipos que serão considerados pesquisáveis.

Após isso, devemos declarar pontos de informações que serão pesquisáveis através da anotação @Field, conforme mostra o exemplo da Listagem 3.

Listagem3.Adicionando a anotação @Field à nossa classe

package exemplo.hibernatesearch; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.search.annotations.Field; import org.hibernate.annotations.GenericGenerator; @Entity @Table(name="login", schema="public") public class Login { @Id @GeneratedValue(generator="increment") @GenericGenerator(name="increment", strategy = "increment") private int id; @Column @Field private String usuario; @Column private String senha; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsuario() { return usuario; } public void setUsuario(String usuario) { this.usuario = usuario; } public String getSenha() { return senha; } public void setSenha(String senha) { this.senha = senha; } }

Podemos notar que apenas o nome de usuário obteve a anotação @Field. Isso ocorre porque não temos o interesse de pesquisar por id ou senha, por isso esses atributos não são anotados.

Para que possamos testar a nossa aplicação criaremos a classe e método que estão na Listagem 4.

Listagem 4. Construindo uma classe de teste inicial.

package exemplo.hibernatesearch; import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; public class TesteHibernate { //método thread-safe private static synchronized Session openSession() { Configuration conf = new Configuration(); conf.configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings (conf.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory = conf.buildSessionFactory(serviceRegistry); Session session = sessionFactory.openSession(); return session; } public void teste() { } }

O método teste conterá a lógica para sessões e manipulação da base de dados. Na Listagem 5 inserimos um dado qualquer na base de dados.

Listagem 5. Inserindo dados na base de dados.

public void insere() { Session session = openSession(); try { session.beginTransaction(); Login p = new Login(); p.setSenha("user1"); p.setUsuario("senha1"); //salva usuario criado acima session.save(p); //comita a transacao session.getTransaction().commit(); } catch ( HibernateException e ) { if ( session.getTransaction() != null ) session.getTransaction().rollback(); } finally { session.close(); } }

Feito isso, podemos agora escrever nosso primeiro código de pesquisa utilizando uma simples página index.html, conforme a Listagem 6.

Listagem 6. Tela de pesquisa para nome de usuário.

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Página de Pesquisa</title> </head> <body> <h1>Bem-vindo à Página de Exemplo</h1> Entre com um nome de usuário para pesquisa: <form action="pesquisa" method="post"> <div id="pesquisa"> <div> <input type="text" name="nomeUsuario" /> <input type="submit" value="Pesquisar" /> </div> </div> </form> </body> </html>

Também podemos fazer uma tela swing com os dados acima chamando o nosso método teste() que será definido abaixo. Não se esqueça de chamar uma vez o método insere() para adicionar alguma informação na base de dados para fins de teste.

Agora podemos executar a nossa consulta para a pesquisa. O código da Listagem 7 demonstra como poderíamos fazer isso.

Listagem 7. Criando uma sessão do Hibernate Search

import org.hibernate.Session; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; //mais códigos Session session = openSession(); FullTextSessionfullTextSession = Search.getFullTextSession(session); fullTextSession.beginTransaction();

Agora que possuímos uma sessão do Hibernate Serach podemos realizar a pesquisa com Lucene Search, conforme a Listagem 8.

Listagem 8. Criando uma pesquisa com Lucene Search.

import org.hibernate.search.query.dsl.QueryBuilder; //Mais códigos String nomeUsuario = request.getParameter("nomeUsuario"); QueryBuilder queryBuilder = fullTextSession.getSearchFactory() .buildQueryBuilder().forEntity(Login.class).get(); org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("usuario").matching (nomeUsuario).createQuery(); //Mais Códigos

QueryBuilder é utilizado para construir consultas invocando uma classe de entidade em particular. No exemplo acima construímos uma consulta do tipo keyword no campo "nomeUsuario" combinando palavras-chave em nomeUsuario.

O objeto org.apache.lucene.search.Query é traduzido pelo Hibernate Search em uma busca do Lucene. Vale salientar que isso ocorre em ambas as direções. Resultados do Lucene pode ser traduzido em um objeto org.hibernate.Query e o mesmo pode ser utilizado como qualquer consulta normal de uma base de dados. Observe a Listagem 9.

Listagem 9. Realizando uma consulta no Hibernate.

org.hibernate.Query hibernateQuery = fullTextSession.createFullTextQuery(luceneQuery, Login.class); List<App> apps = hibernateQuery.list(); request.setAttribute("apps", apps);

No exemplo acima pesquisamos todas as entidades Login que foram encontradas na nossa consulta e colocamos num servlet request.

Por fim, poderíamos exibir os dados encontrados através da JSP presente na Listagem 10.

Listagem 10. Exibindo os resultados.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>Pesquisa Nome de Usuário</title> </head> <body> <h1>Resultados da Pesquisa</h1> <table> <tr> <td><b>Nome de Usuário:</b></td> </tr> <c:forEachvar="app" items="$"> <tr> <td>${app.nomeUsuario}</td> </tr> </c:forEach> </table> </body> </html>

Com isso, neste artigo vimos o que é o Hibernate Search, como se dá o seu funcionamento interno, e quais são seus principais componentes. Por fim fizemos uma pequena aplicação demonstrando o seu uso.

Bibliografia

[1]Hibernate - JBoss Community, disponível em www.hibernate.org/

[2]Documentação de Referência Hibernate, disponível em https://docs.jboss.org/hibernate/core/3.6/reference/pt-BR/html/index.html

[3] Introdução ao Hibernate, disponível em https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/queryhql.html

[4] Jeff Linwood and Dave Minter. An introduction to persistence using Hibernate 3.5, Second Edition. Apress.

[5] Steve Perkins. Hibernate Search by Example: Explore the Hibernate Search system and use its extraordinary search features in your own applications. Packt Publishing.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados