Filtros facetados: como cocinar y con que servir

De qué se trata 



¿Cómo hacer una búsqueda por facetas en una tienda online? ¿Cómo se generan los valores en los filtros de búsqueda por facetas? ¿Cómo afecta la elección de un valor en un filtro a los valores de los filtros adyacentes? En busca de respuestas, llegué a la quinta página de resultados de búsqueda de Google. No encontré información exhaustiva, tuve que averiguarlo yo mismo. El artículo describe:



  1. cómo reacciona la interfaz de usuario cuando el usuario usa filtros;
  2. algoritmo para generar valores de filtro; 
  3. Plantillas de consulta y estructuras de índices de ElasticSearch con explicaciones.


Aquí no hay soluciones listas para usar. No puede copiar y pegar. Para solucionar tu propio problema, tienes que ahondar en.







Conceptos para dejarlo claro 



Búsqueda de texto completo : busque productos por palabra o frase. Para el usuario, este es un campo para ingresar texto con el botón "Buscar", que está disponible en cualquier página del sitio.



Búsqueda por facetas : búsqueda de un producto por varias características: color, tamaño, tamaño de la memoria, precio, etc. Para el usuario, es un conjunto de filtros. Cada filtro está asociado con una sola característica y viceversa. Los valores de filtro son todos los valores posibles para una característica. El usuario ve filtros en la página de sección, categoría, en la página con resultados de búsqueda de texto completo. Cuando el usuario selecciona un valor, el filtro se considera activo.



Comportamiento del filtro facetado 



En resumen, un filtro filtra productos y filtra las opciones de selección en otros filtros. 



Productos de filtros



Es fácil con esto. El usuario seleccionó:



  1. un valor, ve productos que coinciden con el valor;
  2. varios valores en un filtro, ve productos que coinciden con al menos uno;
  3. valores en varios filtros, ve productos que coinciden con el valor de cada filtro.


En términos de álgebra de Boole: hay un "Y" lógico entre los filtros, un "O" lógico entre los valores en el filtro . Lógica simple. 



Opciones de filtros en otros filtros



"Bueno ... ¿qué opciones hay - mostradas, cuáles no - ocultas" - así es como la empresa describe el comportamiento de los filtros. Suena lógico. En la práctica, funciona así:



  1. Vamos al apartado de Teléfonos, vemos filtros por características: Marca, Diagonal, Memoria. Cada filtro contiene valores. 
  2. . . 1.
  3. . , . , 2. 
  4. . . , 3.
  5. «» . 3 ..


El número de valores de filtro depende del número de productos: cuantos más productos con diferentes valores de característica, más valores en el filtro. El usuario redujo la cantidad de productos en la selección para los filtros restantes cuando seleccionó una marca. Esto resultó en una actualización de las listas de valores.



Esto da lugar a una regla universal: los valores de filtro se recuperan de la selección de productos, que está formada por el resto de filtros activos.



Cada filtro activo tiene su propia selección de productos.



Si tenemos N filtros y:



  • no están activos, entonces la muestra es general. Es igual para todos los filtros y coincide con los resultados de la búsqueda;
  • M está activo y M <N, entonces el número de muestras es M + 1, donde 1 es la muestra a la que se aplican todos los filtros activos. Es igual para todos los filtros inactivos y coincide con los resultados de la búsqueda;
  • activo M, y N = M, entonces el número de muestras N. Cada filtro tiene su propia muestra.


Finalmente, cuando el usuario selecciona un valor de filtro de faceta, sucede lo siguiente: 



  1. se forma una selección de búsqueda de productos; 
  2. los valores de los filtros inactivos se recuperan de la selección de búsqueda;
  3. para cada filtro activo, se forma una nueva muestra y de ella se extraen nuevos valores de filtros activos.


Surge la pregunta: ¿cómo implementar esto en la práctica?



Implementación de Elasticsearch (ES)



Las características del producto no son universales, por lo que aquí no encontrará una estructura de índice lista para almacenar productos o consultas listas para usar. En su lugar, habrá enlaces a la documentación que explican cómo crear los índices y consultas "correctos" usted mismo. “Correcto” - basado en mi experiencia y conocimiento. 



Tipos de cuadros de texto "correctos"



En ES, estamos interesados ​​en 2 tipos de datos: 



  • texto para la búsqueda de texto completo. Los campos de este tipo no se pueden utilizar para una comparación, clasificación o agregación exactas;
  • palabra clave para cadenas que están involucradas en las operaciones de comparación exacta, clasificación, agregación.


ES analiza los valores en el campo de texto y crea un diccionario para la búsqueda de texto completo. Los valores en el campo de palabra clave se indexan como se reciben. La agregación y la clasificación solo están disponibles para campos de palabras clave.



El usuario utiliza características en ambos casos: en la búsqueda de texto completo y mediante filtros. ES no le permite asignar 2 tipos a un solo campo, pero ofrece otras soluciones:



campos 

PUT my_index
{
  «mappings»: {
    «properties»: {
      «some_property»: { 
        «type»: «text», // 1
        «fields»: { // 2
          «raw»: { 
            «type»: «keyword»
          }
        }
      }
    }
  }
}


  1. declaramos las características del producto como un campo de tipo  texto
  2. utilizando el parámetro fields, cree un campo virtual secundario de tipo palabra clave . Virtual, porque está presente en el índice y no en la descripción del producto. ES guarda automáticamente los datos en el campo secundario a medida que los recibe.


Así que para cada característica.  



En las consultas para operaciones de comparación, clasificación y agregación exactas, debe utilizar un campo virtual secundario de tipo palabra clave . En el ejemplo, es some_property.raw . Para búsqueda de texto: padre.



copy_to .

PUT my_index
{
  «mappings»: {
    «properties»: {
      «all_properties»: { // 1
        «type»: «text»
      },      «some_property_1»: {
        «type»: «keyword»,
        «copy_to»: «all_properties» // 2 
      },
      «some_property_2»: {
        «type»: «keyword»,
        «copy_to»: «all_properties»
      }
    }
  }


  1. Cree un campo virtual con el tipo de texto en el índice .    
  2. Declare cada característica como una  palabra clave con el parámetro copy_to . Especifique el campo virtual con el valor del parámetro. ES copia el valor de todas las características al campo virtual cuando se guarda el documento. 


Para las operaciones de comparación, clasificación y agregación exactas, debe utilizar el campo de características, para la búsqueda de texto, un campo con los valores de todas las características.



Ambos enfoques crean campos adicionales en el índice que no están presentes en la estructura del documento original. Por lo tanto, para crear una consulta, necesita conocer la estructura del índice.



Prefiero la opción copy_to . Luego, para construir una consulta de búsqueda de texto completo, basta con conocer un campo con una copia de los valores de todas las características. 



Consultas 



Para buscar productos 



Asumiremos que la estructura del índice es la misma que en la variante copy_to . Para la búsqueda de texto completo en ES, se utiliza la construcción de coincidencia , para comparar con los valores de los filtros facetados: consulta de términosLa consulta booleana combina construcciones en una consulta. Será algo como esto:



{
  «query» : { 
    «bool»: {
      «must»: {
        «match»: { 
          «virtual_field_for_fulltext_searching»: {
            «query»: «some text»
          }
        }
      },
      «filter»: { 
        «must»: [
           {«property_1»: [ «value_1_1», …, «value_1_n»]},
          … 
           {«property_n»: [ «value_n_1», …, «value_n_m»]}
        ]
      }
    }
  }
}


query.bool.must.match

consulta de búsqueda de texto completo principal  query.bool.filter filtros para refinar la consulta principal. debe adentro significa lógico "y" entre filtros. La matriz de valores de cada filtro es booleana o.   



Para valores de filtro



La cláusula de agregación de términos agrupa los productos por valor de característica y calcula la cantidad en cada grupo. Esta operación se llama agregación. La dificultad es que para cada filtro activo, la  agregación de términos debe realizarse sobre una selección de productos formada por otros filtros activos. Para filtros inactivos: en una selección que coincide con los resultados de la búsqueda. La construcción de agregación de filtro le permite crear una selección separada para cada agregación y "empaquetar" operaciones en una consulta.



La estructura de la solicitud será así: 

{
  «size»: 0,
  «query» : { 
    «bool»: {
      «must»: {
        «match»: {
          «field_for_fulltext_searching»: {
            «fuzziness»: 2,
            «query»: «some text»
          }
        }
      },
      «filter»: {
      
      }
    }
  },
  «aggs» : {
    «inavtive_filter_agg» : {
      «filter» : {        … 
      },
      «aggs»: {
        «some_inavtive_filter_subagg»: { 
          «terms» : {
            «field» : «some_property»
          }
        },
        ... 
        «some_other_inavtive_filter_subagg»: {
          «terms» : {
            «field» : «some_other_property»
          }
        }
      }
      
    }, 
    «active_filter_1_agg» : {
       «filter»: {
         …        },
       «aggs»: {
          «active_filter_1_subagg»: {
             «terms» : {
                «field»: «property_1»
             }
          }
       }
    },
    …,  
    «active_filter_N_agg» : {
       «filter»: {
         …        
      },
       «aggs»: {
          «active_filter_N_subagg»: {
             «terms» : {
                «field»: «property_N»
             }
          }
       }
    }
  }
}


query.bool : consulta principal, las operaciones de filtrado se realizan en su contexto. Consiste en: 

  • coincidencia: solicitud de búsqueda de texto completo;
  • filtros: filtros por características que no están asociadas con los filtros de facetas y deben estar presentes en cualquier subconjunto. Este puede ser un filtro por in_stock, is_visible, si siempre desea mostrar solo los productos en stock o solo los visibles.


aggs.inavtive_filter_agg: la agregación para filtros de faceta inactivos consta de:

  • filtro -   condiciones por características que están formadas por filtros de facetas activos. Junto con la consulta principal, se forma una selección de bienes, sobre los cuales se realizan las agregaciones secundarias de esta sección; 
  • aggs es un objeto de agregación con nombre para cada filtro inactivo


aggs.active_filter_1_agg: agregación de obtener los valores del primero de los filtros de faceta activos. Cada diseño está asociado con un filtro de facetas. Consiste en: 

  • filtro - condiciones por características que están formadas por filtros de facetas activos, excepto el actual. Junto con la consulta principal, forma una selección de bienes, sobre los que se realiza la agregación secundaria de esta sección;
  • aggs es un objeto de una agregación según la característica del filtro de facetas actualmente activo. 


Es importante especificar "tamaño": 0 ; de lo contrario, obtendrá una lista de productos que coinciden con la consulta principal sin agregaciones. 



Finalmente 



Recibí dos solicitudes:



  1. para los resultados de búsqueda, devuelve productos para mostrarlos al usuario;
  2. para valores de filtro, realiza agregación, devuelve valores de filtro y el número de productos con ese valor.


Cada solicitud es autónoma, por lo que es mejor ejecutarlas de forma asincrónica.   



PD: Admito que existen enfoques y herramientas más "correctos" para resolver el problema de la búsqueda por facetas. Agradecería información adicional y ejemplos en los comentarios.



All Articles