Generación de Búsquedas Relacionadas: Coincidencia Semántica de Tres Niveles

Este artículo explica cómo generamos enlaces de búsqueda relacionada para cada página del sitio utilizando una estrategia de tres niveles que equilibra relevancia semántica, distribución de tráfico y diversidad de consultas.

El Problema: Enlaces de Navegación Relevantes

Cada página necesita enlaces de búsqueda relacionada para ayudar a los usuarios a descubrir más contenido. ¿Pero qué consultas deberíamos mostrar?

El desafío es equilibrar múltiples objetivos:

  • Relevancia: Los enlaces deben estar semánticamente relacionados con la página actual

  • Distribución de tráfico: Las consultas de alto tráfico deben aparecer en páginas de alto tráfico

  • Diversidad de consultas: Cada consulta debe aparecer en múltiples páginas (10+ veces)

  • Unicidad de URL: No enlazar dos veces al mismo destino

  • Cobertura: Cada página debe tener 8 enlaces de calidad

Un enfoque ingenuo (similitud semántica pura) podría mostrar las mismas consultas en cada página. Un mejor enfoque utiliza una estrategia de tres niveles con procesamiento consciente del tráfico.

Estrategia de Tres Niveles

Generamos búsquedas relacionadas utilizando tres niveles de relevancia decreciente:

Nivel 1: Búsquedas Relacionadas (Alta Similitud)

Consultas de alta similitud semántica directamente relacionadas con el contenido de la página:

  • Página de ejemplo: "Treo N100 Mini PC"

  • Consultas de ejemplo: "n100 mini pc", "mini pc 8gb", "compact desktop n100"

Estas son las coincidencias más relevantes.

Nivel 2: Búsquedas Populares (Similitud Media)

Consultas de similitud media que están relacionadas temáticamente pero menos específicas:

  • Página de ejemplo: "Treo N100 Mini PC"

  • Consultas de ejemplo: "mini pc", "small computer", "fanless pc"

Estas son consultas más amplias en la misma categoría.

Nivel 3: Búsquedas Tendencia (Respaldo)

Consultas de poder global (más tráfico) utilizadas cuando se agotan las coincidencias semánticas:

  • Página de ejemplo: Cualquier página

  • Consultas de ejemplo: "mini pc", "thin client", "industrial pc", "all in one pc"

Estas son las consultas más populares en todo el sitio.

El Algoritmo: Procesamiento Primero por Tráfico

Paso 1: Recopilar Todas las Páginas

Recopilamos cada página del sitio:

  • Productos (/p/): Desde los datos fuente del Paso 0

  • Partes (/i/): Desde los datos fuente del Paso 0

  • Artículos (/a/): Desde los datos fuente del Paso 0

  • Familias (/f/): Desde los datos fuente del Paso 0

  • Categorías (/c/): Desde los datos fuente del Paso 0

  • Páginas de consulta (/q/): Desde los datos de enrutamiento (Paso 7)

  • Páginas estáticas: Inicio, acerca de, contacto, etc.

Esto típicamente produce ~64,000 páginas.

Paso 2: Cargar Incrustaciones

Cargamos incrustaciones precalculadas para:

  1. Páginas: Reutilizamos del Paso 0 (productos, partes, artículos) y Paso 6 (páginas de consulta)
  2. Consultas: Desde el Paso 3b (todas las 65K consultas)

Reutilizar incrustaciones evita re-incrustar datos sin cambios:

  • Reutilización Paso 0: ~5,000 incrustaciones de producto/parte/artículo

  • Reutilización Paso 6: ~12,500 incrustaciones de páginas de consulta

  • Nuevas incrustaciones: ~46,500 páginas restantes

Paso 3: Cargar Tráfico de Páginas

Consultamos Athena para obtener vistas de página de los últimos 90 días:

traffic_data = generate_all_pages_traffic_index(lookback_days=90)

Esto devuelve un diccionario que mapea URLs a recuentos de vistas:

{
  "/p/Treo-N100-8-256-2H-W6-11P": 5000,
  "/q/mini-pc": 3000,
  "/": 50000
}

Paso 4: Ordenar Páginas por Tráfico

Procesamos las páginas en orden descendente de tráfico:

sorted_pages = sorted(all_pages, key=lambda p: page_traffic[p['url']], reverse=True)

Esto asegura que las páginas de alto tráfico obtengan la primera selección de consultas.

Paso 5: Calcular Similitud (Por Lotes)

Procesamos páginas en lotes de 1,000 para eficiencia de memoria:

batch_page_embeddings = all_page_embeddings[batch_indices]
batch_similarities = util.cos_sim(batch_page_embeddings, query_embeddings)
# ... (detalles de implementación omitidos)

Esto produce una matriz de similitud para el lote.

Paso 6: Seleccionar Consultas (Tres Niveles)

Para cada página, seleccionamos consultas usando la estrategia de tres niveles:

Nivel 1: Alta Similitud

for idx, similarity in enumerate(sorted_similarities):
    if similarity < threshold_high:
        break
# ... (detalles de implementación omitidos)

Nivel 2: Similitud Media (0.60-0.85)

if len(selected_queries) < 8:
    for idx, similarity in enumerate(sorted_similarities):
        if similarity < 0.60:
            break
        if try_add_query(queries[idx]):
            continue

Nivel 3: Consultas de Poder (Respaldo)

if len(selected_queries) < 8:
    for power_query in power_query_list:
        if try_add_query(power_query):
            continue

Paso 7: Aplicar Restricciones

La función try_add_query() aplica múltiples restricciones:

Límite de Uso de Consulta (10 apariciones):

if query_usage[query] >= MAX_APPEARANCES:
    return False

Unicidad de URL (sin destinos duplicados):

url = get_dest_url(query)
if url in selected_urls:
    return False
selected_urls.add(url)

Prevención de Autoenlaces:

selected_urls = {page_url}  # Inicializar con la página actual

Límite de 8 Enlaces:

if len(selected_queries) >= 8:
    return False

Paso 8: Convertir Consultas a URLs

Usamos los datos de enrutamiento del Paso 7 para convertir consultas a URLs de destino:

query_to_url_map = {}
for route in routing_data['routes']:
    for query in route['queries']:
        query_to_url_map[query] = route['destination']

Esto crea una búsqueda rápida O(1) para destinos de consulta.

Paso 9: Propagación de Idioma (Opcional)

Si la propagación de idioma está habilitada, añadimos el idioma de la consulta a la URL:

lang = detect_query_language(query)
if lang != "en":
    url = f"{url}?lang={lang}"

Esto asegura que los usuarios permanezcan en su idioma preferido al hacer clic en búsquedas relacionadas.

Paso 10: Guardar en DynamoDB

Guardamos las búsquedas relacionadas en DynamoDB usando escrituras por lotes:

with RelatedSearchWidget.batch_write() as batch:
    for page in batch_pages:
        widget = RelatedSearchWidget(
            page_url=page['url'],
            links=[...],
            tier_label="Related Searches"
        )
        batch.save(widget)

Las escrituras por lotes proporcionan una mejora significativa de rendimiento sobre escrituras individuales.

Seguimiento del Uso de Consultas

Realizamos un seguimiento de cuántas veces se ha usado cada consulta:

query_usage = {query: 0 for query in all_queries}
MAX_APPEARANCES = 10

A medida que se seleccionan las consultas, incrementamos su uso:

query_usage[query] += 1

Una vez que una consulta alcanza 10 apariciones, se excluye de selecciones futuras:

available_mask[query_idx] = False

Esto asegura la diversidad de consultas en todo el sitio.

Beneficios del Procesamiento Primero por Tráfico

Procesar páginas por tráfico (más alto primero) tiene ventajas:

Las páginas de alto tráfico obtienen las mejores coincidencias:

  • Página de inicio (50K vistas) → Las 8 consultas más relevantes

  • Producto popular (5K vistas) → Las siguientes 8 consultas más relevantes

  • Producto de nicho (100 vistas) → Consultas relevantes restantes

Respaldo automático:

  • Si se agotan las consultas de alta similitud, se usan consultas de similitud media

  • Si se agotan las consultas de similitud media, se usan consultas de poder

Distribución de tráfico:

  • Las consultas de alto tráfico aparecen en páginas de alto tráfico

  • Las consultas de bajo tráfico aparecen en páginas de nicho

  • Maximiza el potencial general de clics

Manejo de Páginas Estáticas

Las páginas estáticas (inicio, acerca de, contacto) omiten el Nivel 1 y el Nivel 2, yendo directamente al Nivel 3:

if page_type == 'static':
    for power_query in power_query_list:
        try_add_query(power_query)
    tier_label = "Trending Searches"

Esto asegura que las páginas estáticas muestren las consultas más populares en todo el sitio.

Estrategia de Reutilización de Incrustaciones

Reutilizamos incrustaciones de pasos anteriores del pipeline:

Paso 0 (Datos Fuente):

  • Productos: /p/Treo-N100-8-256-2H-W6-11P

  • Partes: /i/N100

  • Artículos: /a/mini-pc-guide

Paso 6 (Agrupar Consultas):

  • Páginas de consulta: /q/mini-pc (slug → texto de consulta)

Nuevas Incrustaciones:

  • Páginas restantes no en el Paso 0 o Paso 6

Esto reduce el tiempo de incrustación de ~2 horas a ~20 minutos.

Incrustación Incremental

Para páginas que necesitan nuevas incrustaciones, usamos caché incremental:

new_embeddings = incremental_embed_with_keys(
    items=page_contents,
    keys=page_urls,
    cache_embeddings_path=SEO_PAGE_EMBEDDINGS_PATH,
    cache_keys_path=SEO_PAGE_URLS_PATH,
    model_name='all-mpnet-base-v2'
)

Esto almacena en caché las incrustaciones para ejecuciones futuras. Ver Estrategia de Incrustación para detalles.

Formato de Salida

Las búsquedas relacionadas se almacenan en DynamoDB:

{
  "page_url": "/p/Treo-N100-8-256-2H-W6-11P",
  "tier_label": "Related Searches",
# ... (detalles de implementación omitidos)

La aplicación web consulta esta tabla para mostrar búsquedas relacionadas en cada página.

Características de Rendimiento

En un servidor típico:

  • Tiempo de procesamiento: Varía según el recuento de páginas

  • Uso de memoria: Depende del tamaño de incrustación y tamaño del lote

  • Escrituras en DynamoDB: Escrituras por lotes para todas las páginas

  • Reutilización de incrustaciones: Alto porcentaje desde caché incremental

El proceso está limitado por la CPU durante el cálculo de similitud. Usar NumPy con aceleración BLAS acelera significativamente las operaciones matriciales.

Integración con el Pipeline SEO

La generación de búsquedas relacionadas es el Paso 8 en el pipeline SEO:

  1. Paso 0: Incrustar Datos Fuente - Productos, partes, artículos
  2. Paso 1: Obtener Consultas - GSC, Google Ads, en vivo, Algolia
  3. Paso 2: Combinar Consultas - Fusionar todas las fuentes
  4. Paso 3a: Generar Mapeos de Frase Base - Filtros iniciales
  5. Paso 3b: Incrustar Consultas - Convertir a vectores
  6. Paso 4: Expandir Mapeos de Frase - Encontrar frases similares
  7. Paso 5: Agrupar Consultas - Agrupar en páginas
  8. Paso 6: Emparejar Productos - Emparejamiento consulta-producto
  9. Paso 7: Construir Páginas de Consulta - Generar HTML
  10. Paso 8: Generar Búsquedas Relacionadas ← Usted está aquí
  11. Paso 11: Migrar a Valkey - Cargar en servicio de búsqueda

Ver Descripción General del Pipeline SEO para el flujo completo.

¿Por Qué Tres Niveles?

Nivel 1 (Alta Similitud) proporciona:

  • ✅ Máxima relevancia

  • ✅ Mejor experiencia de usuario

  • ❌ Cobertura limitada (no todas las páginas tienen coincidencias de alta similitud)

Nivel 2 (Similitud Media) proporciona:

  • ✅ Buena relevancia

  • ✅ Cobertura más amplia

  • ❌ Coincidencias menos específicas

Nivel 3 (Consultas de Poder) proporciona:

  • ✅ Cobertura universal (cada página obtiene 8 enlaces)

  • ✅ Alto clic (consultas populares)

  • ❌ Relevancia más baja

Juntos, aseguran que cada página tenga enlaces de calidad con la mejor relevancia posible.

Estadísticas y Monitoreo

Después de la generación, calculamos estadísticas:

  • Páginas totales: Todas las páginas en el sistema

  • Enlaces salientes totales: Páginas × enlaces por página

  • Consultas usadas: Subconjunto de consultas disponibles

  • Distribución de consultas: La mayoría de las consultas aparecen en múltiples páginas

  • Consultas no utilizadas: Consultas de bajo tráfico o baja similitud

También registramos el enlace cruzado de páginas de categoría y familia para análisis.

Referencias

Conceptos Técnicos

Documentación del Modelo

Artículos Relacionados