Francisco Javier Martínez Páez

Consultor tecnológico de desarrollo de proyectos informáticos.

 Ingeniero Técnico en Telecomunicaciones

Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación

Somos expertos en Java/J2EE

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2009-07-29

Tutorial visitado 5.326 veces Descargar en PDF
Hibernate Search, Analizadores y más

Hibernate Search, Bridges, Analizadores y más

En este tutorial vamos a tratar de comentar algunos detalles un poco más avanzados cuando trabajamos con Hibernate Search. Trataré de explicar qué es un analizador, qué es un filtro, cómo podemos anotar las entidades del modelo con respecto a Hibernate Search para poder buscar en entidades relacionadas, etc...

1. Introducción.

Si estás leyendo este tutorial, probablemente ya tengas nociones acerca de lo que es una base de datos inversa como Lucene y las posibilidades que ofrece. Básicamente podríamos describir una base de datos de este tipo como palabra-céntrica o token-céntrica (terminos que no existen).

Es decir, aunque este tipo de Bases de Datos almacenan lo que denominan Documentos, estos son organizados en referencia a lo que se denominan tokens o términos. Cualquier cosa puede ser considerada un documento siempre que se pueda convertir su información a texto (única cosa que entienden estas bases de datos).

Alguno dirá ¿ Y si no se puede convertir a texto ? Y yo le respondo, ¿ Hay algo que no se pueda describir con palabras ?.

Por lo tanto, lo primero que ha de hacer una base de datos de este tipo es analizar la información que se quiere almacenar, convertirla a texto, tokenizarla o separararla en términos que luego podrán ser usados para las búsquedas y relacionar los documentos con esos términos o tokens. En este proceso de conversión a texto y tokenización o separación en términos de búsqueda es donde entran los bridges, los analizadores y los filtros.

2. Presentación del ejemplo.

Antes de empezar os dejo un zip con los fuentes del tutorial aquí
Dispongo de una base de datos relacional que contiene básicamente Noticias y Autores de esas noticias. Estoy usando actualmente Hibernate trabajar con esta información. A continuación os muestro las entidades que describen este modelo de datos:

Hasta este momento, yo he sido feliz creando, modificando y eliminando noticias y autores. Pero el cliente me ha pedido que si el podría buscar noticias como cuando busca en google. Es decir el pone una palabrita en una cajita de texto y el sistema le devuelve aquellas noticias que contengan esa palabrita en cualquier lugar (cuerpo, entradilla, autor, fecha ...) Evidentemente, tratar de realizar esto a través de HQL (o SQL) puede ser muy lento y probablemente no dé los resultados que espero. ¿ Puedo seguir siendo feliz ?. Espero que si.

3. Maven y sus cosicas

Vamos ahora configurar el proyecto con ayuda de Maven para poder obtener las herramientas que necesitamos. Os muestro el pom.xml:

4. Configuración de Hibernate, el Dao y preparación de las pruebas.

A continuación configuraremos Hibernate (hibernate.cfg.xml)

Vamos ahora a crear una clase de utilidades para cargar los datos al inicio de las pruebas. He creado tres ficheros html que serán el cuerpo de las noticias y que leeré también durante la carga de datos y guardaré en las noticias. Esta clase se apoya en un conjunto de clases que forman el Dao.

A continuación las clases del Dao

El interfaz HibernateCallback.

La clase HibernateDaoImpl que será un Dao un poco limitado. A nosotros, para este tutorial únicamente nos interesa el método findByFullText

HibernateIgniter será la clase que se encargue de inicializar la factoría de sesiones de Hibernate

DaoFactory será la clase encargada de construir Daos.

5. Anotando las clases para la indexación.

Para preparar nuestra clase Noticia para indexación haremos las siguientes cosas:

  1. La marcaremos como @Indexed para indicar a Hibernate Search que nuestra clase es indexable. Desde este momento y al estar en el classpath Hibernate Search, se activarán los listeners de indexación cada vez que se modifique o se guarde una entidad de este tipo.
  2. Seleccionaremos el atributo que queremos marcar como identificador en lucene marcándolo como @DocumentId. Lo normal es que sea el mismo que es el @Id de Hibernate.
  3. Cada atributo que queramos indexar lo marcaremos como @Field. Algunos nos interesarán que sean tokenizados (titular, entradilla y cuerpo) y otros no (fecha).
  4. El atributo fecha ha de ser pasado a String durante la indexación. Usaremos un Bridge de fechas @DateBridge que incluye Hibernate Search y le diremos que queremos sólo indexar como máxima resolución a día (no nos interesa la hora exacta)
  5. Daremos más relevancia a las ocurrencias del titular, después a la entradilla y por último el cuerpo. Esto lo haremos usando el atributo @Boost y entraría en juego si le pidiéramos ordenar por relevancia.
  6. Marcaremos el atributo autor para ser indexado juntamente con Noticia (para poder buscar noticias por autor). Esto lo haremos con la anotación @IndexEmbedded. En el otro lado, en la clase autor, para que Hibernate Search reindexe una noticia cuando un autor sea modificado marcaremos el atributo noticias de la clase autor como @ContainedIn (esto nos obliga a marcar la relación como bidireccional. Si no lo hiciésemos así, deberíamos ser nosotros los encargados de reindexar una noticia cuando un autor sea modificado).
  7. Además definiremos un Analizador que denominaremos "Analizador_Noticia". Nuestro analizador estará formado por un conjunto de Filtros creados por el proyecto solr y lucene-snowbal que complementarán la forma en la que serán indexados nuestros atributos. Nuestro analizador contiene los siguientes filtros:
    • HTMLStripStandardTokenizerFactory: Extrae el texto del HTML. Ideal para el atributo cuerpo que es una página HTML
    • ISOLatin1AccentFilterFactory: Elimina acentos, diéresis etc... durante la tokenización
    • StopFilterFactory: No indexa todas aquellas palabras que contenga el fichero indicado
    • LowerCaseFilterFactory: Pasa a minúsculas todos los textos
    • SnowballPorterFilterFactory: Analiza las palabras para extraer la raíz de la misma y buscar palabras con la misma raíz (gato, gata)
    Todo esto lo haremos con la anotación @AnalyzerDef.
  8. Por último indicaremos en nuestros atributos que use el Analizador definido durante la indexación. Esto lo haremos con la anotación @Analyzer
A continuación muestro como quedan nuestras clases:

6. Probando todo esto.

Vamos ahora a crear una clase de test unitarios que me permita probar todo esto y una clase para inicializar los datos de prueba.

Crearemos tres autores y tres noticias. Los cuerpos de las noticias los he descargado de un periódico de deportes en html y lo leo del disco. La clase que crea los datos de prueba.

Y por último empezaremos con los Tests. Primero inicializaremos Hibernate y crearemos los datos al comienzo de los tests. Luego creamos nuestro primer test para comprobar que realmente se han creado las noticias:

A continuación el resto de los tests que se explican en cada uno de ellos.

Si ejecutáis los tests veréis que la cosa funciona... ... parece que podré seguir siendo feliz...

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Fecha publicación: 2009-07-29-08:18:55

Autor:

[Carlos García] Y por supuesto, una de las cosas buenas que tiene Hibernate Search es que busca sinónimos, palabras con el mismo origen y te corrige las faltas al estilo Google.