Indexer Post Processor. ¿Lo conoces?
Liferay tiene innumerables componentes, algunos más conocidos que otros.
Os cuento mi nuevo descubrimiento: Indexer Post Processor.
1. Antecedentes
Como sabemos, Liferay utiliza un motor de búsqueda que por defecto es Elasticsearch.
A grandes rasgos, Elasticsearch usa un Indexador para convertir las entidades de la base de datos en un objeto JSON llamado documento y que usaremos para realizar las búsquedas.
Este Indexador especifica qué campos de nuestra entidad se deben agregar a cada documento.
Aquí tenemos un ejemplo para la entidad JournalArticle
La categoría a la que pertenece un contenido, también aparece en este documento, de la siguiente forma.
2. Requerimiento
Hace poco en un proyecto se nos planteó la necesidad de ordenar los contenidos por categorías. ¿Pero cómo ordenar por un campo que se define como no ordenable? ¿Y si además queremos añadir algún otro criterio?
Imaginaos que necesito ordenar los contenidos de la siguiente forma:
-
Los contenidos que pertenezcan a la categoría 70000 aparezcan en primer lugar.
-
Los contenidos con título testing article en segundo lugar.
-
Los contenidos creados por userName test en último lugar.
3. Solución
Después de valorar las alternativas que teníamos, todas ellas muy costosas, estuve revisando la documentación de Liferay y de pronto me encontré con esto.
Según la documentación,uno de los posibles usos del IndexerPostProcessor es modificar los Documents antes de que sean enviados al motor de búsqueda.
Así que, podría añadir un nuevo parámetro al Document del JournalArticle, para poder usarlo luego en la búsqueda.
4. Implementación
Para añadir un nuevo IndexerPostProcessor hay que seguir estos pasos.
- Implementar la interfaz com.liferay.portal.kernel.search.IndexerPostProcessor
- Publicarlo en OSGI con la propiedad indexer.class.name. En nuestro caso com.liferay.journal.model.JournalArticle.
Esta interfaz sobrescribe varios métodos pero nosotros nos vamos a centrar en el que nos interesa que es este:
@Component(immediate = true,
property = {"indexer.class.name=com.liferay.journal.model.JournalArticle"},
service = IndexerPostProcessor.class)
public class JournalArticlePostProcessor implements IndexerPostProcessor {
@Override
public void postProcessDocument(Document document, Object obj) {
final JournalArticle journalArticle = (JournalArticle) obj;
int order = populateOrder(journalArticle);
document.addNumberSortable("order", order);
}
}
postProcessDocument recibe 2 parámetros:
-
Object: Recibe la entidad que hayas definido como indexer.class.name, en nuestro caso JournalArticle.
-
Document: Será el documento generado al reindexar la entidad.
Calcula el orden de cada journalArticle y lo añade al documento.
Al desplegar el componente comprobamos su funcionamiento cada vez que es necesario llamar al Indexador, por ejemplo, al salvar el contenido. Si queremos que este campo aparezca en todos los documentos tendremos que lanzar una reindexación completa de la entidad.
Una vez reindexado aparecerá este nuevo campo en cada documento:
"order_Number_sortable": 1
Lo único que nos queda es añadir la funcionalidad en el searchContext para implementar el orden.
SearchContext searchContext = SearchContextFactory.getInstance(PortalUtil.getHttpServletRequest(request));
Sort order = new Sort("order_Number_sortable",Sort.INT_TYPE, Boolean.FALSE)
searchContext.setSorts(new Sort[] {order});
4. Conclusión
Conocer todos los componentes que ofrece Liferay además de sus usos, nos permite aportar la solución adecuada en cada momento.
5. Más Información
Podéis encontrar más información en los links en los que me he basado para redactar este post:
https://help.liferay.com/hc/es/articles/360018170871-Indexer-Post-Processor