Implementar full-text queries con match y multi_match

Lectura
25 min~6 min lectura

Concepto clave

Las consultas match y multi_match son los caballos de batalla del Query DSL de Elasticsearch para búsqueda full-text. Mientras que match busca términos en un único campo analizado, multi_match extiende esta funcionalidad a múltiples campos simultáneamente, permitiendo construir experiencias de búsqueda más ricas y relevantes.

Imagina que estás construyendo un motor de búsqueda para una plataforma de e-commerce. Un usuario busca "zapatillas running Nike". Con match en el campo title, encontrarías productos cuyo título contenga esos términos. Pero ¿qué pasa si la descripción del producto o sus características también son relevantes? Aquí es donde multi_match brilla, permitiendo buscar en title, description y tags al mismo tiempo, mejorando significativamente el recall.

Ambas consultas utilizan el analizador del campo para procesar el texto de búsqueda (tokenización, eliminación de stop words, stemming, etc.) antes de ejecutar la búsqueda. Esto las diferencia de consultas como term que trabajan con términos exactos. La elección entre ellas no es binaria; en sistemas avanzados, se combinan en consultas compuestas para afinar la precisión y el recall según el caso de uso.

Cómo funciona en la práctica

Vamos a desglosar la implementación paso a paso usando un índice de artículos de noticias.

Paso 1: Configuración del índice

PUT /noticias
{
  "mappings": {
    "properties": {
      "titulo": { "type": "text", "analyzer": "spanish" },
      "contenido": { "type": "text", "analyzer": "spanish" },
      "etiquetas": { "type": "text", "analyzer": "keyword_lowercase" },
      "fecha": { "type": "date" }
    }
  }
}

Paso 2: Consulta match básica

Buscar "crisis económica" en el campo contenido:

GET /noticias/_search
{
  "query": {
    "match": {
      "contenido": "crisis económica"
    }
  }
}

Elasticsearch analizará "crisis económica" (posiblemente normalizando a "crisis economica" sin tilde) y buscará documentos donde contenido contenga crisis Y economica (por defecto, operador OR). Puedes cambiar a AND:

"match": {
  "contenido": {
    "query": "crisis económica",
    "operator": "and"
  }
}

Paso 3: Consulta multi_match

Extender la búsqueda a múltiples campos con diferentes pesos:

GET /noticias/_search
{
  "query": {
    "multi_match": {
      "query": "crisis económica",
      "fields": ["titulo^3", "contenido^2", "etiquetas"],
      "type": "best_fields"
    }
  }
}
El símbolo ^ seguido de un número (ej. ^3) asigna un boost o peso a ese campo. Un match en titulo vale 3 veces más que en etiquetas.

El parámetro type controla cómo se combinan los scores. best_fields (por defecto) toma el score más alto de cualquier campo, ideal para campos que se excluyen mutuamente. most_fields suma los scores, útil cuando los campos contienen información similar analizada de forma diferente.

Caso de estudio

Escenario: Un portal de empleo necesita mejorar su búsqueda de vacantes. Los usuarios buscan por puesto, habilidades y ubicación, pero la relevancia actual es baja porque la búsqueda solo considera el título del puesto.

Solución implementada: Se creó una consulta multi_match que busca en:

  • titulo^4 (alto boost, ya que es el campo principal)
  • descripcion^2
  • habilidades (array de texto)
  • ubicacion

Con type: "cross_fields" para tratar los campos como un solo campo grande, lo que ayuda cuando los términos están distribuidos (ej. "desarrollador" en título y "Java" en habilidades).

Consulta de ejemplo:

GET /vacantes/_search
{
  "query": {
    "multi_match": {
      "query": "desarrollador Java remoto",
      "fields": ["titulo^4", "descripcion^2", "habilidades", "ubicacion"],
      "type": "cross_fields",
      "operator": "and"
    }
  }
}

Resultado: Aumento del 40% en la tasa de clics en resultados de búsqueda, ya que las vacantes ahora aparecen cuando coinciden términos clave en cualquier campo relevante, no solo en el título.

Errores comunes

  • Usar match en campos no analizados (keyword): match espera texto analizado. Si se aplica a un campo keyword, buscará coincidencia exacta con la cadena completa, lo que rara vez es útil. Solución: Usar term para keywords o asegurar que el mapping sea correcto.
  • Ignorar el efecto del analizador: Si el analizador del campo elimina stop words o aplica stemming, "crisis económica" podría buscar por "crisis economica" (sin tilde). Esto puede causar confusiones si no se entiende. Solución: Probar consultas con _analyze API para ver cómo se tokeniza.
  • Abusar de multi_match sin boost: Buscar en muchos campos sin pesos puede diluir la relevancia. Un match en un campo secundario podría rankear más alto que uno en el campo principal. Solución: Asignar boosts basados en importancia del campo para el negocio.
  • No considerar el tipo de multi_match: Usar best_fields cuando se necesita most_fields o viceversa puede dar resultados subóptimos. Solución: Entender la semántica de los datos y elegir type acorde: best_fields para campos únicos (título vs cuerpo), most_fields para sinónimos (descripción en inglés y español).
  • Olvidar el operador por defecto (OR): match usa OR por defecto, lo que puede devolver muchos resultados irrelevantes. Solución: Cambiar a "operator": "and" para consultas precisas, o usar minimum_should_match para un balance.

Checklist de dominio

  1. Puedo explicar la diferencia entre match (un campo) y multi_match (múltiples campos) y cuándo usar cada una.
  2. Sé cómo asignar boosts a campos en multi_match usando la sintaxis campo^peso.
  3. Puedo listar y diferenciar al menos tres tipos de multi_match: best_fields, most_fields, y cross_fields.
  4. Entiendo cómo el analizador del campo afecta la tokenización de la consulta en match y multi_match.
  5. Sé cambiar el operador por defecto de OR a AND en una consulta match.
  6. Puedo identificar cuándo no usar match/multi_match (ej., para búsqueda exacta en campos keyword).
  7. He probado consultas con _analyze para depurar problemas de tokenización.

Optimizar búsqueda de productos en un e-commerce con match y multi_match

Eres un Search Engineer en una empresa de e-commerce. El índice productos tiene los campos: nombre (texto, analizador español), descripcion (texto, analizador español), categoria (keyword), marca (keyword), y precio (float). Los usuarios se quejan de que las búsquedas no encuentran productos relevantes cuando usan múltiples términos.

Objetivo:

Implementar y probar consultas match y multi_match para mejorar la relevancia.

Pasos:

  1. Preparar datos de prueba: Inserta al menos 5 documentos en el índice productos con datos variados (ej., "Zapatillas Nike Air Max", "Camiseta Adidas de running", etc.). Usa la API _bulk para eficiencia.
  2. Consulta match básica: Ejecuta una consulta match en el campo nombre para "zapatillas running". Observa los resultados y el scoring. Luego, cambia el operador a AND y compara.
  3. Implementar multi_match: Crea una consulta multi_match que busque "zapatillas running" en los campos nombre (boost 3), descripcion (boost 2), y marca. Usa type: "best_fields". Ejecuta y analiza si los resultados mejoran.
  4. Experimentar con tipos: Cambia el type a most_fields y luego a cross_fields. Para cada uno, ejecuta la consulta con "zapatillas Nike" y observa diferencias en el orden de resultados. Explica brevemente por qué cambia.
  5. Depurar tokenización: Usa la API _analyze para ver cómo se tokeniza "zapatillas running" con el analizador español. Compara con cómo se tokeniza "running shoes" (en inglés) si cambiaras el analizador. Esto te ayudará a entender por qué algunas búsquedas no funcionan como esperas.

Entrega un breve informe con: (a) las consultas usadas, (b) observaciones sobre los resultados, y (c) recomendaciones para producción (ej., qué tipo y boosts usar).

Pistas
  • Recuerda que los campos keyword no se analizan; para incluirlos en multi_match, considera si necesitas búsqueda exacta o full-text.
  • Usa la herramienta Dev Tools de Kibana para ejecutar las consultas y ver los resultados en tiempo real.
  • Prueba con consultas que mezclen términos presentes en diferentes campos (ej., "Nike" en marca y "correr" en descripción) para ver el efecto de cross_fields.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.