Crear consultas con funciones de scoring personalizadas

Video
15 min~4 min lectura

Reproductor de video

Concepto clave

El scoring personalizado en Elasticsearch te permite controlar cómo se calcula la relevancia de los documentos en tus búsquedas full-text. Mientras que el algoritmo por defecto (BM25) funciona bien en muchos casos, hay situaciones donde necesitas ajustar la lógica de ranking según reglas de negocio específicas.

Imagina que trabajas en un e-commerce: quieres que los productos con mejor calificación de usuarios aparezcan primero, incluso si coinciden menos con los términos de búsqueda. O en un sistema de noticias, donde las publicaciones más recientes deben tener prioridad. El Query DSL de Elasticsearch ofrece funciones como function_score que permiten modificar el score original aplicando factores como boost por campo, funciones matemáticas, o incluso scripts personalizados.

El scoring personalizado no reemplaza BM25, sino que lo complementa con lógica de negocio.

Cómo funciona en la práctica

La función principal es function_score, que envuelve una consulta base y aplica una o más funciones de scoring. Cada función puede usar:

  • weight: Multiplica el score por un factor constante
  • field_value_factor: Usa el valor de un campo numérico (ej: rating, popularity)
  • decay functions: Reduce el score basado en distancia (ej: fecha, ubicación)
  • script_score: Cálculo completamente personalizado con Painless scripting

Ejemplo básico: buscar productos electrónicos donde los mejor calificados tengan más relevancia:

{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "category": "electronics"
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field": "user_rating",
            "factor": 1.2,
            "modifier": "sqrt"
          }
        }
      ],
      "boost_mode": "multiply"
    }
  }
}

Aquí, el score original se multiplica por la raíz cuadrada del rating, dando más peso a productos mejor evaluados.

Caso de estudio

Implementemos un sistema de búsqueda para una plataforma de hoteles. Requerimientos:

  1. Los hoteles deben coincidir con términos como "playa" o "centro"
  2. Los mejor calificados (campo rating de 1-5) deben rankear más alto
  3. Los más cercanos a una ubicación (campo distance_km) deben tener ventaja
  4. Los precios más bajos (campo price_night) deben favorecerse moderadamente

Consulta resultante:

{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {
          "query": "playa vista al mar",
          "fields": ["name", "description", "location"]
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field": "rating",
            "factor": 2.0,
            "modifier": "log1p"
          }
        },
        {
          "gauss": {
            "distance_km": {
              "origin": 0,
              "scale": 10
            }
          }
        },
        {
          "script_score": {
            "script": {
              "source": "return 1000 / (doc['price_night'].value + 1)"
            }
          }
        }
      ],
      "score_mode": "sum",
      "boost_mode": "multiply"
    }
  }
}

Esta consulta combina tres funciones: rating con transformación logarítmica, decaimiento gaussiano por distancia, y un script que favorece precios bajos. El score_mode define cómo se combinan las funciones (suma), y boost_mode cómo se aplican al query original (multiplicación).

Errores comunes

  • Usar boost excesivo: Valores como 1000 distorsionan los resultados. Mantén factores entre 1-5 para ajustes sutiles.
  • Ignorar la normalización: Campos como price pueden variar mucho (10 vs 10000). Usa modificadores como log1p o normaliza en el mapping.
  • Combinar funciones incorrectamente: Si usas score_mode: "multiply" con funciones que devuelven 0, el score final será 0. Prefiere "sum" o "avg".
  • Olvidar el impacto en performance: Los scripts y funciones complejas ralentizan búsquedas. Usa "explain": true para depurar y perfilar.
  • No probar con datos reales: Los scores teóricos pueden comportarse distinto con tus datos. Siempre valida con una muestra representativa.

Checklist de dominio

  1. Entiendo la diferencia entre boost_mode y score_mode
  2. Puedo implementar al menos tres tipos de funciones de scoring
  3. Sé cuándo usar field_value_factor vs script_score
  4. He probado mis consultas con "explain": true para validar cálculos
  5. Puedo ajustar parámetros de decaimiento (scale, decay, offset) para casos de uso
  6. He considerado el impacto en performance de mis funciones personalizadas
  7. Sé cómo normalizar campos numéricos para evitar dominancia en el scoring

Optimizar ranking de productos en un e-commerce

Configura una consulta con scoring personalizado para un catálogo de productos. Usa el dataset de ejemplo ecommerce_products con estos campos: name (texto), description (texto), price (float), sales_last_month (integer), rating (float 1-5), in_stock (boolean).

  1. Crea una consulta base que busque en name y description usando multi_match con el query "camara digital 4k"
  2. Añade una función field_value_factor que boostee productos con mayor rating, usando modifier: "log1p" y factor: 1.5
  3. Añade una segunda función que favorezca productos con más ventas recientes (sales_last_month), usando weight: 2.0
  4. Añade una tercera función con script_score que asigne un bonus de 100 puntos si in_stock es true
  5. Configura score_mode: "sum" y boost_mode: "multiply"
  6. Ejecuta la consulta y verifica que los productos mejor rankeados combinen relevancia textual con estos factores de negocio
Pistas
  • Recuerda que weight multiplica el score de la función, no el score total
  • Usa doc['in_stock'].value en el script para acceder al valor booleano
  • Prueba con explain:true para ver cómo contribuye cada función

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.