
La relevancia semántica en SEO
En el posicionamiento en buscadores (SEO), ya no basta con que la página contenga las mismas palabras clave que la consulta del usuario. Los motores de búsqueda modernos, como Google, intentan entender la intención y el significado detrás de la búsqueda para ofrecer resultados más relevantes. Esto plantea el desafío de medir la relevancia semántica entre una query (consulta) y el contenido de una página, más allá de una simple coincidencia de palabras.
Google, por ejemplo, usa técnicas de machine learning para hacer matching semántico; en documentos del juicio antimonopolio se reveló que Google realiza “semantic matching” entendiendo el significado de las palabras y reemplazándolas con términos análogos, de modo que conceptos sinónimos se traten de forma equivalente. Esto significa que una búsqueda como “hoteles económicos” podría encontrar relevante una página que habla de “alojamientos baratos” aunque no coincidan exactamente las palabras, porque el buscador reconoce la similitud de significado.
Para los SEOs, surge la pregunta: ¿podemos imitar este proceso para analizar nuestros contenidos? La respuesta es sí. Mediante embeddings (vectores semánticos) podemos convertir tanto las consultas como el contenido de las páginas en representaciones numéricas que capturan su significado. Luego, al comparar estas representaciones, obtenemos una medida de qué tan relacionada semánticamente está una página con una determinada query.
En este artículo técnico veremos qué son los embeddings, cómo se calculan las similitudes mediante dot product (producto escalar) y cómo implementar una herramienta SEO casera para vectorizar contenidos y calcular un puntaje de relevancia (que llamaremos G-Score) similar al que utiliza Google.
Fundamentos: embeddings de texto y similitud semántica
Embeddings es el término que se usa para las representaciones vectoriales de texto en espacios de alta dimensión. En palabras sencillas, un embedding convierte una pieza de texto (por ejemplo, una frase, un párrafo o un documento) en un vector de números. Este vector actúa como una “huella digital semántica” del texto: si dos textos significan cosas parecidas, sus vectores estarán cercanos o alineados en el espacio vectorial, aunque las palabras concretas difieran. En cambio, textos sobre temas distintos producirán vectores alejados o orientados en direcciones muy distintas.
Imaginemos un espacio con cientos de dimensiones (difícil de visualizar, pero matemáticamente tratable). Cada palabra o concepto aporta algo a ciertas dimensiones del vector. Un modelo de embedding bien entrenado ubicará, por ejemplo, los vectores de “hotel barato” cerca de “alojamiento económico”, mientras que “hotel barato” estará lejos de “coche deportivo”. Esto ocurre porque el modelo aprende del contexto de millones de ejemplos qué palabras y frases tienen significados relacionados.
Para los motores de búsqueda, los embeddings permiten hacer coincidir resultados más allá de la coincidencia literal de texto. Google introdujo sistemas como RankBrain (en 2015) y más recientemente algoritmos como RankEmbed o MUM, que emplean embeddings y modelos de lenguaje para entender consultas nunca vistas y hacer match con contenidos relevantes aunque no compartan exactamente las mismas palabras.
En el contexto SEO, comprender embeddings es valioso porque nos permite medir la similitud semántica entre la intención de búsqueda y el contenido de nuestra página de manera cuantitativa.
Una vez que tenemos vectores representando tanto la consulta del usuario como el contenido de una página, ¿cómo medimos su parecido? Existen varias formas de calcular la distancia o similitud entre dos vectores, pero las más comunes son: la similitud coseno, la distancia euclídea y el producto escalar (dot product).
En tareas de procesamiento de lenguaje natural, la similitud coseno ha sido muy popular: se calcula el coseno del ángulo entre dos vectores y nos indica qué tan alineados están, ignorando la diferencia de magnitudes.
Sin embargo, en los últimos años se ha descubierto que para ciertas aplicaciones (como búsqueda semántica) el producto escalar puede funcionar mejor. El producto escalar es simplemente la suma de las multiplicaciones de cada componente de los vectores, y equivale a la similitud coseno multiplicada por las longitudes de ambos vectores.
En otras palabras, el producto escalar incorpora no solo la dirección relativa (ángulo) sino también la magnitud de los vectores. Esto implica que si un documento es muy rico en contenido relevante (lo que podría resultar en un vector de mayor magnitud), obtendrá un puntaje más alto con el producto escalar que otro documento más corto aunque tengan dirección similar. Dicho de forma simple: el producto escalar recompensa la amplitud o “peso” del contenido, mientras que la similitud coseno trata por igual a un párrafo corto y a uno largo si hablan exactamente de lo mismo.
¿Por qué importa tanto el uso del producto escalar?
Porque Google, de acuerdo con la información revelada en el juicio antimonopolio, mide la similitud semántica entre consultas y documentos usando el producto escalar en sus sistemas internos, en lugar de la similitud coseno. Su sistema RankEmbed, encargado de estimar la correspondencia entre query y página (especialmente para consultas cortas o genéricas), utiliza esta medida de similitud vectorial. Muchos analistas SEO quizá calculaban la similitud coseno entre textos para evaluar relevancia, pero si Google emplea el dot product, es conveniente que nuestras herramientas también lo hagan para alinearnos mejor con su forma de ponderar el contenido. Con esto en mente, en las siguientes secciones abordaremos cómo construir una herramienta que aplique estos conceptos: obtendremos embeddings de nuestras páginas y consultas, y calcularemos el dot product entre ellos para obtener un puntaje que llamaremos G-Score (en honor a este “Google Score” semántico revelado).
Modelo de embeddings: multi-qa-mpnet-base-dot-v1
(multilingüe y optimizado para dot product)
No es necesario entrenar tu propio modelo de embeddings desde cero; por fortuna existen modelos pre-entrenados de alta calidad que podemos usar. En este proyecto utilizaremos el modelo multi-qa-mpnet-base-dot-v1
, disponible públicamente, el cual ha demostrado un excelente desempeño en tareas de búsqueda semántica. Veamos por qué este modelo es una gran elección:
- Orientado a búsqueda de preguntas y respuestas: Este modelo proviene de la familia Sentence Transformers y fue entrenado específicamente para tareas de semantic search, usando pares de pregunta y respuesta. De hecho, se entrenó con 215 millones de pares (pregunta, respuesta) provenientes de fuentes diversas. Esto significa que ha aprendido a alinear consultas con textos que contienen la respuesta o información relevante, justo lo que necesitamos para medir relevancia entre una query SEO y el contenido de una página. Es un modelo robusto gracias a la enorme cantidad de datos de entrenamiento que respalda su comprensión semántica.
- Vectorizaciones de alta dimensionalidad: El modelo mapea cada texto a un vector denso de 768 dimensiones. Esta dimensionalidad le permite capturar matices sutiles de significado en el lenguaje. Podemos imaginar cada dimensión como una «característica latente» del significado (aunque no interpretables directamente), y con 768 de ellas, el modelo tiene mucho espacio para ubicar conceptualmente cada texto. En la práctica, más dimensiones suelen traducirse en mayor capacidad de representar similitudes/diferencias complejas entre textos.
- Multilingüe: Si bien la base MPNet del modelo fue inicialmente entrenada en inglés, esta variante ha demostrado funcionar en varios idiomas (incluyendo español), lo que es crucial para SEO en entornos multilingües. Su vocabulario y entrenamiento en múltiples fuentes le permiten generar embeddings coherentes para textos en español, inglés y otros idiomas europeos comunes. En la documentación de modelos similares se indica que incorporan soporte para ~15 idiomas (español incluido) en sus datos de entrenamiento. Esto nos da la confianza de que
multi-qa-mpnet-base-dot-v1
podrá representar consultas y páginas en español adecuadamente. Al usar un modelo multilingüe, un SEO puede vectorizar contenido en distintos idiomas con la misma herramienta. - Optimizado para dot product: Un detalle importante es que este modelo está pensado para usar el producto escalar como medida de similitud. De hecho, su nombre lleva “dot” y la tarjeta técnica señala explícitamente que no produce embeddings normalizados (longitud unitaria) y que la función de puntuación recomendada es el dot product. Esto es perfecto para nuestro propósito, ya que queremos calcular la similitud tal como Google lo haría (producto interno). Si usáramos un modelo entrenado para similitud coseno, tendríamos que normalizar los vectores, pero en este caso podemos usar directamente el producto escalar de los vectores crudos como métrica de relevancia.
Extrayendo el contenido de las páginas con Docling
El primer paso para vectorizar y analizar páginas web es obtener su contenido textual de manera limpia, sin el ruido de HTML, menús o anuncios. Para ello utilizaremos la librería Docling, un proyecto de IBM diseñado para parsear documentos de diversos formatos (PDF, Word, HTML, etc.) y extraer su contenido en formato estructurado.
Docling simplifica enormemente el scraping y procesamiento de HTML comparado con hacer expresiones regulares o usar librerías como BeautifulSoup manualmente, ya que identifica el cuerpo principal del documento y lo convierte a texto plano o Markdown preservando la estructura (encabezados, párrafos, listas, tablas, etc.).
Algunas ventajas de usar Docling
soporta múltiples formatos (por si quieres extraer contenido no solo de páginas web sino también de PDFs, DOCXs, etc.), incorpora cierta comprensión de la disposición del documento (por ejemplo, respeta el orden de lectura, títulos, tablas) y puede exportar a JSON o Markdown. En nuestro caso, le daremos la URL de la página web y obtendremos de vuelta su contenido textual listo para vectorizar.
A continuación, un ejemplo de cómo usar Docling para convertir el HTML de una página en texto utilizable:
# Paso 1: Instalar e importar Docling
!pip install docling # (Ejecutar esto si no tienes Docling instalado)
from docling.document_converter import DocumentConverter
# Paso 2: Configurar el convertidor de documentos
converter = DocumentConverter()
# Paso 3: Especificar la URL de la página web que queremos extraer
url = "https://www.ejemplo.com/mi-pagina.html"
# Paso 4: Convertir el contenido de la URL a un documento Docling
result = converter.convert(url)
# Paso 5: Exportar el contenido a texto estructurado (Markdown en este caso)
contenido_markdown = result.document.export_to_markdown()
print(contenido_markdown[:500]) # Imprimimos los primeros 500 caracteres como muestra
En el código anterior: primero instalamos la librería docling
(si es que aún no está instalada) y luego importamos DocumentConverter
. Creamos una instancia de este convertidor, que es el objeto principal para procesar documentos. Con converter.convert(url)
le pasamos la URL de la página que nos interesa; Docling se encargará de descargar el HTML y parsearlo automáticamente. El resultado (result
) contiene un documento procesado del cual podemos extraer distintas representaciones. Usamos export_to_markdown()
para obtener una cadena de texto en formato Markdown que conserva la estructura del contenido (títulos ##
, párrafos, etc.), aunque también podríamos usar export_to_json()
o métodos similares si quisiéramos otro formato.
Tras ejecutar este proceso, la variable contenido_markdown
contiene el texto principal de la página web listo para usarse. Por ejemplo, si la página era un artículo, en el Markdown tendremos sus encabezados y párrafos sin el código HTML molesto. En caso de necesitar solo texto plano, podríamos eliminar la sintaxis Markdown o usar otro método de exportación (por ejemplo, extrayendo solo los nodos de párrafo). Para nuestros fines, el Markdown es útil porque mantiene cierta estructura legible.
Nota: La primera vez que se usa Docling, puede tardar un poco ya que descarga algunos modelos internos para interpretar documentos (por ejemplo, tiene componentes de OCR y otros para PDFs). Pero para páginas HTML simples es bastante rápido. Asegúrate de manejar errores de red (por si la URL no responde) y de tener permiso de scraping según las políticas del sitio que analices.
De texto a vectores: representando la consulta y el contenido
Con el contenido de nuestras páginas en formato de texto limpio, el siguiente paso es convertir tanto ese contenido como la consulta de búsqueda en vectores numéricos (embeddings) utilizando el modelo multi-qa-mpnet-base-dot-v1
. Para facilitar esto usaremos la biblioteca sentence-transformers
, que proporciona una interfaz sencilla para cargar modelos pre-entrenados de Hugging Face y obtener embeddings.
Primero, instalemos e importemos el modelo de embeddings:
!pip install -U sentence-transformers # instalar la biblioteca de Sentence Transformers
from sentence_transformers import SentenceTransformer, util
# Cargar el modelo pre-entrenado (esto descargará los pesos la primera vez)
modelo = SentenceTransformer('sentence-transformers/multi-qa-mpnet-base-dot-v1')
El objeto modelo
ahora contiene la red neuronal lista para generar embeddings. Podemos usar su método encode()
para convertir texto en vectores. Veamos cómo obtener el vector de una consulta de búsqueda y de varias páginas web que hayamos extraído:
# Ejemplo de consulta y contenidos de páginas
consulta = "hoteles baratos en Madrid centro" # una consulta de ejemplo
paginas_texto = [contenido_pagina1, contenido_pagina2, contenido_pagina3] # textos extraídos de 3 páginas
# Paso 1: Obtener el embedding de la consulta
emb_query = modelo.encode(consulta)
# Paso 2: Obtener embeddings de cada página (procesa la lista completa)
emb_paginas = modelo.encode(paginas_texto)
# Verifiquemos dimensiones
print("Dimensión del vector de la consulta:", len(emb_query))
print("Dimensión del vector de la primera página:", len(emb_paginas[0]))
En este fragmento, consulta
es un string con la búsqueda de usuario (por ejemplo, «hoteles baratos en Madrid centro»). Su embedding emb_query
será un vector de 768 dimensiones (cada elemento es un número tipo float) que representa semánticamente el significado de «hoteles baratos en Madrid centro».
Por otro lado, paginas_texto
es una lista con el texto extraído de tres páginas web hipotéticas. Al pasar esa lista a modelo.encode()
, la función procesará cada elemento y nos devolverá una lista (o array de NumPy) con tres vectores, emb_paginas[0]
, emb_paginas[1]
y emb_paginas[2]
, cada uno correspondiente al embedding de la página en la misma posición de la lista original.
Notemos que estamos usando el modelo de manera batch, es decir, codificando varias páginas a la vez. La librería
sentence-transformers
se encarga de hacer esto de forma eficiente (incluso dividiendo en lotes más pequeños si las páginas son muy largas o si la GPU tiene poca memoria). También maneja la tokenización y truncamiento: dado que los modelos basados en transformers tienen un límite de tokens (en este modelo suele ser 512 tokens de entrada), si el contenido de la página es muy extenso, se truncará al límite permitido.
Al imprimir las dimensiones de los vectores, deberíamos ver 768 en ambos casos, confirmando que tanto la consulta como las páginas se representan en el mismo espacio vectorial de 768 dimensiones.
Calculando la similitud semántica: dot product y definición del G-Score
Ahora que tenemos la consulta y las páginas representadas como vectores, necesitamos cuantificar qué tan cerca están entre sí en términos semánticos. Como discutimos en la sección de fundamentos, utilizaremos el producto escalar (dot product) como medida de similitud. Recordemos brevemente la fórmula del producto escalar de dos vectores AA y BB de dimensión n:

Básicamente multiplicamos cada componente del vector AA por la componente correspondiente del vector BB y sumamos todos esos productos. El resultado es un solo número (escalar). Si AA y BB están alineados (es decir, BB contiene en gran medida las mismas “ideas” que AA), muchos de esos productos individuales serán grandes (porque ambas componentes serán altas o ambas bajas pero positivas, etc.), y el total será alto. Si AA y BB hablan de cosas muy distintas, unas componentes podrían cancelarse con otras (positivos con negativos, etc.) y el total tenderá a ser bajo o incluso negativo. En términos de similitud semántica, un producto escalar más alto implica que la consulta y la página comparten más significado en común.
Es importante destacar que, dado que no estamos normalizando los vectores, la magnitud influirá en el resultado: una página más larga o con más contenido relevante puede producir un vector de mayor norma y por tanto un dot product mayor con la consulta, lo cual refleja cierta “importancia” o “popularidad” del contenido en el espacio vectorial. Esto encaja con la filosofía de Google de premiar contenidos de calidad y completos: al usar el producto interno estamos teniendo en cuenta no solo que la página apunte en la dirección temática de la consulta, sino también cuánta “masa” de contenido lleva en esa dirección.
Ahora definiremos el G-Score. Llamaremos G-Score al puntaje de similitud semántica entre una query y una página calculado mediante el producto escalar de sus embeddings. Es decir, para una consulta qq y una página dd:
G-Score(q, d) = embedding(q) · embedding(d)
En nuestro caso, dado que los embeddings son vectores de 768 dimensiones, el G-Score es la suma de 768 productos (cada dimensión de la consulta multiplicada por la dimensión correspondiente de la página). Cuanto mayor sea el G-Score, más relevante consideramos semánticamente esa página para la consulta dada.
¿Por qué lo llamamos G-Score? La G viene de Google. Sabemos que Google calcula algún tipo de score interno para ordenar sus resultados. Según las revelaciones del juicio, una parte de ese score proviene de comparar embeddings (por ejemplo, de la query y los documentos candidatos) usando dot product. Si bien Google combinará este score semántico con muchos otros factores (PageRank, user data, frescura, etc.), podemos interpretar el producto escalar entre query-página como un proxy de ese componente semántico. En nuestra herramienta simplificada, el G-Score será directamente el criterio para decidir qué página es más relevante para una query, emulando esa parte semántica del algoritmo de Google.
Cabe mencionar que el G-Score no está acotado entre 0 y 1 como lo estaría una similitud coseno; sus valores pueden variar ampliamente (dependiendo de las magnitudes de los vectores). Un G-Score alto en valor absoluto indica alta similitud (y si fuera negativo indicaría que probablemente la consulta y el documento están temáticamente opuestos o fuera de contexto uno del otro, lo cual en la práctica es raro si hablamos de temas razonablemente relacionados). Para propósitos de ranking entre varias páginas, el valor relativo es lo que importa: ordenaremos de mayor a menor G-Score.
Veamos cómo calculamos el G-Score con Python a partir de los embeddings obtenidos:
import numpy as np
# Supongamos que ya tenemos emb_query (vector de la consulta)
# y emb_paginas (lista/array de vectores de páginas) del paso anterior.
# Calcular el dot product entre la consulta y cada página
scores = np.dot(emb_paginas, emb_query) # producto matriz-vector: obtendremos un array de scores
# Identificar el índice de la página con mayor score
indice_max = int(np.argmax(scores))
mejor_score = scores[indice_max]
print("G-Score de la consulta con cada página:", scores)
print(f"Índice de la página más relevante: {indice_max} (score = {mejor_score:.4f})")
Aquí usamos numpy.dot para calcular de forma vectorizada el producto escalar entre el vector de la consulta (emb_query) y cada uno de los vectores de páginas en emb_paginas. Si emb_paginas es un array de forma (N, 768) (N páginas, 768 dimensiones cada una) y emb_query es de forma (768,), el resultado scores será un array de forma (N,) donde cada posición i es el dot product entre la consulta y la página i. Alternativamente, podríamos haber calculado cada producto escalar en un bucle, pero aprovechar la operación vectorizada es más conciso y eficiente.
Luego usamos np.argmax(scores)
para obtener el índice con el valor más alto en el array de scores. Esa será la página con mayor similitud semántica a la query, es decir, la página más relevante según el G-Score. Imprimimos los scores para verlos (útil durante pruebas) y señalamos cuál fue el máximo y su valor.
Llegados a este punto, ya tenemos esencialmente implementado el núcleo de la herramienta: dada una query y varias páginas vectorizadas, podemos calcular su G-Score y determinar cuál página “gana” en relevancia semántica para esa consulta.
Integrando todo: ejemplo completo en Python
A continuación, uniremos todos los pasos en un script cohesivo. Este ejemplo asume que tenemos un conjunto de páginas web (URLs) cuyo contenido queremos analizar contra una consulta dada. Mostraremos cómo sería una pequeña herramienta de línea de comandos (CLI) donde el usuario ingresa una query y el programa responde con la página más relevante según el G-Score calculado.
import numpy as np
from docling.document_converter import DocumentConverter
from sentence_transformers import SentenceTransformer
# Inicializar herramientas
converter = DocumentConverter()
modelo = SentenceTransformer('sentence-transformers/multi-qa-mpnet-base-dot-v1')
# Lista de URLs a analizar (ejemplo)
urls = [
"https://www.ejemplo.com/pagina1.html",
"https://www.ejemplo.com/pagina2.html",
"https://www.ejemplo.com/pagina3.html"
]
# 1. Extraer contenido de cada página con Docling
paginas_texto = []
for url in urls:
try:
result = converter.convert(url)
texto_md = result.document.export_to_markdown()
paginas_texto.append(texto_md)
except Exception as e:
print(f"Error extrayendo {url}: {e}")
paginas_texto.append("") # si falla, metemos cadena vacía
# 2. Vectorizar todas las páginas de la lista
emb_paginas = modelo.encode(paginas_texto)
# 3. Pedir al usuario que ingrese una consulta
consulta = input("Por favor, introduce la consulta de búsqueda: ")
# 4. Vectorizar la consulta
emb_query = modelo.encode(consulta)
# 5. Calcular G-Score de la consulta contra cada página
scores = np.dot(emb_paginas, emb_query)
# 6. Identificar la página con mayor G-Score
idx_mejor = int(np.argmax(scores))
mejor_url = urls[idx_mejor]
mejor_score = scores[idx_mejor]
# 7. Mostrar resultado
print(f"\nPágina más relevante para la consulta '{consulta}':")
print(f"- URL: {mejor_url}")
print(f"- G-Score: {mejor_score:.4f}")
Explicación del flujo
Primero definimos la lista de páginas a evaluar (aquí tres URLs de ejemplo, pero podrías cargar decenas o cientos desde un sitemap, un listado de la web, etc.). Luego, para cada URL, usamos Docling para obtener su contenido textual; guardamos ese contenido en la lista paginas_texto
. Manejamos posibles errores en la extracción (por ejemplo, si una URL no responde o Docling encuentra un formato no soportado, capturamos la excepción y continuamos para no abortar todo el proceso).
Con la lista de contenidos lista, pasamos al paso de vectorización: obtenemos los embeddings de todas las páginas de un solo llamado (modelo.encode(paginas_texto)
) y almacenamos el resultado en emb_paginas
.
Después, solicitamos al usuario que introduzca una consulta de búsqueda (usando input()
para simular una sencilla CLI interactiva). Vectorizamos la consulta en emb_query
.
Calculamos los G-Scores con la misma técnica descrita antes (producto escalar entre emb_query y cada vector en emb_paginas). Encontramos el índice del mejor resultado y luego obtenemos la URL correspondiente. Finalmente, imprimimos el resultado: la URL de la página más relevante y el valor de su G-Score.
Demo: Supongamos que las páginas de ejemplo tratan sobre turismo en Madrid, y que sus contenidos son:
- pagina1: Guía de hoteles económicos en Madrid.
- pagina2: Historia de Madrid (contenido no muy relacionado con hoteles).
- pagina3: Listado de hostales baratos en el centro de Madrid.
Si el usuario ingresa la consulta «hoteles baratos en Madrid centro«, es de esperar que la página1 y página3 obtengan G-Scores más altos que la página2, puesto que comparten más vocabulario y contexto semántico con la query. El script devolverá la URL con mayor score, que probablemente sería la página3 (si su contenido está muy enfocado en hostales/hoteles céntricos económicos). Así, el SEO podría confirmar que la página3 es la más alineada con esa intención de búsqueda, y tal vez decidir optimizarla aún más o enlazarla internamente desde otras páginas relevantes.
Next Steps
Hemos construido una herramienta técnica que permite a un SEO medir la relevancia semántica entre una consulta y el contenido de páginas web, utilizando la misma lógica fundamental que emplean los motores de búsqueda modernos. A través de embeddings generados por el modelo multi-qa-mpnet-base-dot-v1
y de la similitud por dot product, obtenemos un puntaje (G-Score) que nos indica qué tan bien responde cada página a la intención detrás de una query. Este enfoque va más allá de la densidad de palabras clave, evaluando la comprensión contextual del texto.
Algunas reflexiones finales y posibles extensiones de este trabajo:
- Interpretación de G-Score: Un G-Score alto sugiere fuerte alineación temática, pero recuerde que en SEO real intervienen muchos factores. Esta herramienta se centra en relevancia de contenido. Podemos usarla para, por ejemplo, detectar qué páginas de nuestro sitio podrían competir por la misma intención (clusters de contenido), o para identificar gaps semánticos (queries para las cuales nuestro contenido tiene G-Score bajo, indicando que quizás nos falta cubrir ese tema en profundidad).
- Optimización multilingüe: Usamos un modelo multilingüe, por lo que la misma metodología se aplica si queremos evaluar páginas en inglés, español u otros idiomas. Podríamos incluso comparar una query en un idioma con contenido en otro, ya que el espacio vectorial es compartido (aunque la calidad de cross-lingual matching no será perfecta, podría dar ideas, por ejemplo, comparar contenido en español vs inglés sobre el mismo tópico).
- Escalabilidad: Para un puñado de páginas la solución es inmediata. Si quisiéramos escanear cientos o miles de páginas, podríamos necesitar optimizar la extracción (usar múltiples hilos o procesos para Docling, o extraer previamente y guardar los textos) y la vectorización (aprovechar GPU, procesar por lotes más pequeños si memoria es un problema, etc.). Afortunadamente, una vez obtenidos los embeddings, comparar con distintas queries es muy rápido (una simple multiplicación de matrices). Esto abre la puerta a integrar esta herramienta en flujos más grandes, como una aplicación web donde se ingresa una query y se devuelve un ranking de páginas de un sitio, o incluso integrar los embeddings en un motor de búsqueda interno con un índice vectorial.
- Mejoras en la métrica: El dot product es una buena métrica según Google y nuestros razonamientos. Si quisiéramos afinar más la relevancia, podríamos combinar el G-Score con otras señales: por ejemplo, dar un pequeño impulso a páginas con autoridad (backlinks) o cuya meta title contenga términos de la query. Sin embargo, eso entra ya en score compuesto. Como experimento aislado, es interesante ver cuánto alineamiento semántico puro podemos capturar con embeddings.