Grails Searchable con No-ORM y varios datasource

Estamos trabajando en un proyecto que tiene algunas peculiaridades, la más interesante de ellas es que convivimos con un modelo en hibernate considerando una estructura de tablas legacy (para lo que definimos un datasource adicional personalizado). El modelo del proyecto es más o menos así:

  • datasource directo a mongodb donde guardaremos todo nuestro modelo basado en documentos
  • datasource_Legacy donde tendremos las tablas antiguas del modelo ORM en una base de datos convencional – en nuestro caso SQL Server.

Nos encontramos, entonces, con la necesidad de hacer búsquedas dinámicas y flexibles. Tenemos experiencia con Searchable (que al día de hoy tiene poco mantenimiento sobre todo porque Lucene, la tecnología en la que se sostiene, es un proyecto ahora abandonado) así que optamos por eso como primera solución. A la larga, sabemos, tendremos que movernos a ElasticSearch o Solr.

En esta ocasión nos sorprendió encontrarnos con un error horrible de searchable cada vez que iniciábamos:

java.lang.IllegalArgumentException: No entities listed to be indexed, have you defined your entities correctly?

Bien, la respuesta fue simple. Configurar los los beans de Spring para que soporten el datasource personalizado adicional que teníamos. Resulta que automáticamente el plugin no recorre todos los datasource configurados. Basándonos en este post, la cosa sigue así.

Modificamos el conf/spring/resources.groovy

// necesario para gestionar un nuevo datasource
import org.compass.gps.device.hibernate.HibernateGpsDevice
// con esto podremos hacer un lookup del sessionFactory generado por grails automáticamente
import grails.plugin.searchable.internal.compass.config.SessionFactoryLookup

beans = {
/* ~ acá todo lo demás que tengamos configurado */
compassGpsDevice(HibernateGpsDevice) { bean ->
  bean.destroyMethod = "stop"
  name = "hibernate"
  sessionFactory = { SessionFactoryLookup sfl ->
    sessionFactory = ref('sessionFactory_datasourceName')
   } // datasourceName será el nombre después del guión bajo que le pusimos a nuestro datasource extra
  fetchCount = 5000
  }
}

Si es el único datasource que queremos indexar (es decir, el único que tiene entidades configuradas para searchable) hasta ahí estaremos bien. Sin embargo, si queremos incluir varios (inclusive el predeterminado) ahí tenemos que indicar unas líneas más.

import org.compass.gps.impl.SingleCompassGps

compassGps(SingleCompassGps) {
  compass = ref('compass')
  gpsDevices = [compassGpsDevice, /* otroUniqueCompassGpsDevice  ~agregar aquí todos los demás */ ]
 }

Al respecto, algunos comentarios importantes:

  • Al parecer, aunque se use el plugin de MongoGORM, este plugin no podrá hacer búsquedas ahí 🙁
  • Cuando se inicializa searchable en un modelo viejo, habrá que esperar el arrancar porque hará el primer indexado y ojo porque si hay muchos datos, cortará en los primeros 5000 y el resto se irán agregando con los diferentes accesos a los datos o, en caso que aplique, al próximo inicio. Es algo progresivo.
  • Las pruebas que yo hice fueron con grails 2.3.4 y searchable 0.6.6 – al día de hoy, las últimas versiones de ambas cosas

Discussion Area - Leave a Comment