Búsquedas por facetas con Facet API + Hierarchical Select + Múltiples selecciones

June 18, 2021

Hace un par de días, nos toco usar facetas con el tipo de campo Hierarchical Select el cual hacía referencia a una taxonomía de varios niveles, hasta ahí íbamos bien, pero el cliente también necesitaba el poder seleccionar más de 2 elementos de niveles diferentes...

El ambiente era el siguiente:

  • Taxonomía: Nombre: Colores con los siguientes términos:

    • Colores Primarios
      • rojo.
      • amarillo.
      • azul.
    • Colores Secundarios.
      • violeta.
      • anaranjado.
      • verde.
  • Tipo de campo: Hierarchical Select, no podía ser configurado para guardar el último elemento ya que el usuario podía seleccionar un elemento padre y tendría que obtener como resultado todos los hijos. Conclusión: el campo debe de guardar la lista de términos.

  • La faceta no podía ser configurada como OR, ya que el campo Hierarchical Select guarda toda la lista de padres para poder llegar al término, esto ocasionaría que al seleccionar Azul, también se seleccionaría Colores Primarios, lo que da como consecuencia rojo, amarillo y azul seleccionados.

  • La faceta no podía ser configurada como AND, ya que el usuario necesita seleccionar más de 2 elementos, ya sea del mismo o de diferentes padres.

Interesante cierto? La manera de solucionarlo fue mediante código, es por este motivo el que nos animamos a crear este post, donde tocaremos los siguientes puntos:

  1. Introducción a las facetas.
  2. Configuración básica desde la interface gráfica.
  3. ¿Cómo alterar las facetas desde código mediante HOOK_facet_items_alter?

Para seguir con el post, debemos de tener instalado y previamente configurado Apache Solr Search, Search API y Facet API.

1. Introducción a las facetas

Una de las necesidades de los sitios que tienen búsquedas de productos o servicios ofrecidos(estilo Amazon), son constructores para crear y administrar sus interfaces de búsquedas los cuales deben de estar de manera clara para sus usuarios.

  • ¿A que se llama búsquedas por facetas? Son búsquedas que se basan en campos conocidos como criterios los cuales también son usados como filtros en los resultados de una búsqueda, estas facetas pueden ser cualquier tipo de campo, ejemplo, Titulo, fecha, ubicaciones.

2. Configuración básica desde la interface gráfica

  • ¿Cómo activar esta faceta? Primero vamos a nuestro indexador, para eso seleccionamos en el menú Configuration - Search and Metadata - Search API , y procedemos a seleccionar nuestro indexador, dentro de este vamos a la opción editar.

indexador

Encontramos cinco(5) pestañas, Ver, editar, campos, filtros y facetas. Dentro de campos, veremos todos los campos definidos en nuestros content types, para este ejemplo activaremos el
campo Titulo como se aprecia en la siguiente imagen.

campo

Una vez guardado, nos vamos a la pestaña de facetas, dentro de esta buscamos el campo de Titulo faceta a mano derecha veremos las opciones con las que cuentan todos los campos en las facetas, cada una de ellas nos muestra funciones diferentes:

  • Configure Display: En esta sección podremos seleccionar la manera como se visualizará la faceta, Drupal por default nos trae un par de opciones

display

  • Configure dependiencies: Para configurar las dependencias de estas facetas, ya sea por role, paquetes o por otras facetas.
  • Configure Filters: Nos brinda la opción de configurar si no deseamos mostrar algunos resultados, excluir alguno de ellos, re-describir basándonos en una función callback, limitar los resultados en base a una cantidad mínima de resultados o definir la cantidad de hijos a mostrar.

3. ¿Cómo alterar las facetas desde código?

Para poder realizar este proceso, es necesario configurar la faceta para que pueda ser alterada. Accedemos al listado de facetas(admin/config/search/search_api), buscamos el indexador a usar y seleccionamos editar facetas, una vez ahí buscamos el campo a modificar y seleccionamos editar filtros de faceta. Obtendremos como resultado lo siguiente, una vez ahí nos aseguramos de que la opción de Rewrite facet items vía callback function este seleccionada.

filtros

El siguiente paso es agregar el siguiente hook en nuestro modulo, en el siguiente ejemplo obtendremos el markup de los resultados en mayúsculas.

 
function HOOK_facet_items_alter(&$build, &$settings) {
    if ($settings->facet == "YOUR_FACET_NAME") {
        foreach($build as $key => $item) {
            $build[$key]["#markup"] = drupal_strtoupper($item["#markup"]);
        }
    }
}
  • $settings -> Configuraciones propias de la faceta. settings
  • $build -> Construcción de los resultados de la faceta. build

Validaciones a tener en cuenta

  • Para este ejemplo, la faceta esta configurada como OR y el campo Hierarchical Select guarda todos los elementos.

  • Dentro de $build[$tid]['#query']['f'] se guardan los filtros, ejemplo field_color:61(el cual pertenece a color rojo), esto quiere decir que nuestra búsqueda a realizar contará con ese valor como filtro, el color rojo.

  • Cuando se selecciona un hijo nuestra variable $build[$tid]['#query']['f'] por default nos agrega el filtro del padre, continuando con el ejemplo anterior, si deseamos seleccionar el color azul, veremos que $build[$tid]['#query']['f'] no solo cuenta con field_color:61, sino también con field_color:60 (El término padre: Color primario), esto quiere decir que contaremos con 3 filtros, Rojo, Colores Primarios y el nuevo color a seleccionar. Grave problema, ya que al filtrar por Colores primarios, también filtrará rojo, azul, amarillo.

  • Para poder seleccionar más de 2 elementos de diferentes padres, hay que considerar que se debe eliminar los padres de ambos términos.

  • Si se deselecciona un color, ejemplo: Al deseleccionar amarillo, se debe verificar si algún otro color del mismo padre y de la misma jerarquía están seleccionados, si es así, tenemos 3 opciones.

  • Si existen términos hermanos seleccionados, se debería seguir filtrando por esos.

  • Si el término a deseleccionar es el último, debemos de pasar como nuevo filtro el término padre para que el usuario se mantenga en la búsqueda.

Solución Como se observa, es más que todo un caso de validaciones a considerar para cumplir con las necesidades del cliente. El HOOK_facet_items_alter(&$build, &$settings) nos es de gran utilidad ya que este nos permite agregar o eliminar términos dependiendo de las necesidades:

  • Para eliminar un término.
     
    unset($build[$tid]['#query']['f'][$key_parent]);
    
  • Para agregar un término(ejemplo color azul, cuyo tid es 63):
     
    $build[$tid]['#query']['f'][] =  'field_color:63');
    

Conclusión

Los módulos de Apache Solr Search, Search API y Facet API. son muy amplios y ofrecen una gran flexibilidad para poder alterar/configurar sus propiedades, tanto desde la interfaces gráfica, como desde código. Existen muchos sitios en los cuales podemos ver resultados de este tipo de búsquedas, desde páginas de bienes raíces a sitios de venta de productos. Brindando al usuario final una manera adecuada y óptima al momento de realizar sus filtros.