Introducción a las bases de datos vectoriales y cómo utilizar la IA para SEO

Introducción a las bases de datos vectoriales y cómo utilizar la IA para SEO


Una base de datos vectorial es una colección de datos donde cada dato se almacena como un vector (numérico). Un vector representa un objeto o entidad, como una imagen, persona, lugar, etc. en el espacio abstracto de N dimensiones.

Los vectores, como se explicó en el capítulo anterior, son cruciales para identificar cómo se relacionan las entidades y pueden usarse para encontrar su similitud semántica. Esto se puede aplicar de varias maneras para SEO, como agrupar palabras clave o contenido similares (usando kNN).

En este artículo, aprenderemos algunas formas de aplicar la IA al SEO, incluida la búsqueda de contenido semánticamente similar para enlaces internos. Esto puede ayudarlo a perfeccionar su estrategia de contenido en una era en la que los motores de búsqueda dependen cada vez más de los LLM.

También puede leer un artículo anterior de esta serie sobre cómo encontrar canibalización de palabras clave utilizando las incrustaciones de texto de OpenAI.

Profundicemos aquí para comenzar a construir la base de nuestra herramienta.

Comprensión de las bases de datos vectoriales

Si tiene miles de artículos y desea encontrar la similitud semántica más cercana para su consulta de destino, no puede crear incrustaciones de vectores para todos ellos sobre la marcha para compararlos, ya que es altamente ineficiente.

Para que eso suceda, necesitaríamos generar incrustaciones de vectores solo una vez y mantenerlas en una base de datos que podamos consultar y encontrar el artículo más parecido.

Y eso es lo que hacen las bases de datos vectoriales: son tipos especiales de bases de datos que almacenan incrustaciones (vectores).

Cuando consulta la base de datos, a diferencia de las bases de datos tradicionales, realizan una coincidencia de similitud de coseno y devuelven los vectores (en este caso, artículos) más cercanos a otro vector (en este caso, una frase de palabras clave) que se está consultando.

Esto es lo que parece:

Ejemplo de registro de incrustación de texto en la base de datos vectorial.

En la base de datos de vectores, puede ver los vectores junto con los metadatos almacenados, que podemos consultar fácilmente utilizando el lenguaje de programación de nuestra elección.

En este artículo, usaremos Pinecone debido a su facilidad de comprensión y simplicidad de uso, pero existen otros proveedores como Chroma, BigQuery o Qdrant que quizás quieras consultar.

Vamos a sumergirnos.

1. Cree una base de datos de vectores

Primero, registre una cuenta en Pinecone y cree un índice con una configuración de “text-embedding-ada-002” con ‘coseno’ como métrica para medir la distancia vectorial. Puedes nombrar el índice como quieras, nosotros lo nombraremos.article-index-all-ada‘.

Creando una base de datos vectorial Creando una base de datos vectorial.

Esta interfaz de usuario auxiliar es solo para ayudarlo durante la configuración, en caso de que desee almacenar la incrustación de vectores de Vertex AI, debe configurar las ‘dimensiones’ en 768 en la pantalla de configuración manualmente para que coincida con la dimensionalidad predeterminada y puede almacenar los vectores de texto de Vertex AI (usted Puede establecer un valor de dimensión entre 1 y 768 para ahorrar memoria).

En este artículo aprenderemos a utilizar los modelos ‘text-embedding-ada-002’ de OpenAi y ‘text-embedding-005’ de Vertex AI de Google.

Una vez creada, necesitamos una clave API para poder conectarnos a la base de datos utilizando una URL de host de la base de datos vectorial.

A continuación, necesitará utilizar Jupyter Notebook. Si no lo tiene instalado, siga esta guía para instalarlo y luego ejecute este comando (a continuación) en la terminal de su PC para instalar todos los paquetes necesarios.

pip install openai google-cloud-aiplatform google-auth pandas pinecone-client tabulate ipython numpy

¡Y recuerda que ChatGPT es muy útil cuando tienes problemas durante la codificación!

2. Exporta tus artículos desde tu CMS

A continuación, debemos preparar un archivo de exportación CSV de artículos desde su CMS. Si usa WordPress, puede usar un complemento para realizar exportaciones personalizadas.

Como nuestro objetivo final es crear una herramienta de enlace interno, debemos decidir qué datos deben enviarse a la base de datos vectorial como metadatos. Esencialmente, el filtrado basado en metadatos actúa como una capa adicional de orientación de recuperación, alineándolo con el marco general de RAG mediante la incorporación de conocimiento externo, lo que ayudará a mejorar la calidad de la recuperación.

Por ejemplo, si estamos editando un artículo sobre «PPC» y queremos insertar un enlace a la frase «Investigación de palabras clave», podemos especificar en nuestra herramienta que «Categoría = PPC». Esto permitirá que la herramienta consulte solo artículos dentro de la categoría «PPC», asegurando enlaces precisos y contextualmente relevantes, o es posible que queramos vincular a la frase «actualización más reciente de Google» y limitar la coincidencia solo a artículos de noticias usando ‘Tipo ‘ y publicado este año.

En nuestro caso, estaremos exportando:

  • Título.
  • Categoría.
  • Tipo.
  • Fecha de publicación.
  • Año de publicación.
  • Enlace permanente.
  • Meta descripción.
  • Contenido.

Para ayudar a obtener los mejores resultados, concatenaríamos los campos de título y metadescripciones, ya que son la mejor representación del artículo que podemos vectorizar y son ideales para fines de incrustación y enlaces internos.

El uso del contenido completo del artículo para incrustaciones puede reducir la precisión y diluir la relevancia de los vectores.

Esto sucede porque una única inserción grande intenta representar varios temas cubiertos en el artículo a la vez, lo que lleva a una representación menos enfocada y relevante. Es necesario aplicar estrategias de fragmentación (dividir el artículo en títulos naturales o segmentos semánticamente significativos), pero éstas no son el tema central de este artículo.

Aquí está el archivo de exportación de muestra que puede descargar y usar para nuestro ejemplo de código a continuación.

2. Insertar incrustaciones de texto de OpenAi en la base de datos de vectores

Suponiendo que ya tiene una clave API de OpenAI, este código generará incrustaciones de vectores a partir del texto y las insertará en la base de datos de vectores en Pinecone.

import pandas as pd
from openai import OpenAI
from pinecone import Pinecone
from IPython.display import clear_output

# Setup your OpenAI and Pinecone API keys
openai_client = OpenAI(api_key='YOUR_OPENAI_API_KEY')  # Instantiate OpenAI client
pinecone = Pinecone(api_key='YOUR_PINECON_API_KEY')

# Connect to an existing Pinecone index
index_name = "article-index-all-ada"
index = pinecone.Index(index_name)

def generate_embeddings(text):
    """
    Generates an embedding for the given text using OpenAI's API.
    Returns None if text is invalid or an error occurs.
    """
    try:
        if not text or not isinstance(text, str):
            raise ValueError("Input text must be a non-empty string.")

        result = openai_client.embeddings.create(
            input=text,
            model="text-embedding-ada-002"
        )

        clear_output(wait=True)  # Clear output for a fresh display

        if hasattr(result, 'data') and len(result.data) > 0:
            print("API Response:", result)
            return result.data[0].embedding
        else:
            raise ValueError("Invalid response from the OpenAI API. No data returned.")

    except ValueError as ve:
        print(f"ValueError: {ve}")
        return None
    except Exception as e:
        print(f"An error occurred while generating embeddings: {e}")
        return None

# Load your articles from a CSV
df = pd.read_csv('Sample Export File.csv')

# Process each article
for idx, row in df.iterrows():
    try:
        clear_output(wait=True)
        content = row["Content"]
        vector = generate_embeddings(content)

        if vector is None:
            print(f"Skipping article ID {row['ID']} due to empty or invalid embedding.")
            continue

        index.upsert(vectors=[
            (
                row['Permalink'],  # Unique ID
                vector,            # The embedding
                {
                    'title': row['Title'],
                    'category': row['Category'],
                    'type': row['Type'],
                    'publish_date': row['Publish Date'],
                    'publish_year': row['Publish Year']
                }
            )
        ])
    except Exception as e:
        clear_output(wait=True)
        print(f"Error processing article ID {row['ID']}: {str(e)}")

print("Embeddings are successfully stored in the vector database.")

Debe crear un archivo de cuaderno y copiarlo y pegarlo allí, luego cargar el archivo CSV ‘Sample Export File.csv’ en la misma carpeta.

proyecto jupyterProyecto Jupyter.

Una vez hecho esto, haga clic en el botón Ejecutar y comenzará a insertar todos los vectores de incrustación de texto en el índice. article-index-all-ada Creamos en el primer paso.

Ejecutando el guiónEjecutando el guión.

Verá un texto de registro de salida de vectores integrados. Una vez terminado, mostrará el mensaje al final de que se completó correctamente. Ahora ve y revisa tu índice en Pinecone y verás que tus registros están allí.

3. Encontrar un artículo que coincida con una palabra clave

Bien, ahora intentemos encontrar un artículo que coincida con la palabra clave.

Cree un nuevo archivo de cuaderno y copie y pegue este código.

from openai import OpenAI
from pinecone import Pinecone
from IPython.display import clear_output
from tabulate import tabulate  # Import tabulate for table formatting

# Setup your OpenAI and Pinecone API keys
openai_client = OpenAI(api_key='YOUR_OPENAI_API_KEY')  # Instantiate OpenAI client
pinecone = Pinecone(api_key='YOUR_OPENAI_API_KEY')

# Connect to an existing Pinecone index
index_name = "article-index-all-ada"
index = pinecone.Index(index_name)


# Function to generate embeddings using OpenAI's API
def generate_embeddings(text):
    """
    Generates an embedding for a given text using OpenAI's API.

    """
    try:
        if not text or not isinstance(text, str):
            raise ValueError("Input text must be a non-empty string.")

        result = openai_client.embeddings.create(
            input=text,
            model="text-embedding-ada-002"
        )

        # Debugging: Print the response to understand its structure
        clear_output(wait=True)
        #print("API Response:", result)

        if hasattr(result, 'data') and len(result.data) > 0:
            return result.data[0].embedding
        else:
            raise ValueError("Invalid response from the OpenAI API. No data returned.")

    except ValueError as ve:
        print(f"ValueError: {ve}")
        return None

    except Exception as e:
        print(f"An error occurred while generating embeddings: {e}")
        return None

# Function to query the Pinecone index with keywords and metadata
def match_keywords_to_index(keywords):
    """
    Matches a list of keywords to the closest article in the Pinecone index, filtering by metadata dynamically.
    """
    results = []

    for keyword_pair in keywords:
        try:
            clear_output(wait=True)
            # Extract the keyword and category from the sub-array
            keyword = keyword_pair[0]
            category = keyword_pair[1]

            # Generate embedding for the current keyword
            vector = generate_embeddings(keyword)
            if vector is None:
                print(f"Skipping keyword '{keyword}' due to embedding error.")
                continue

            # Query the Pinecone index for the closest vector with metadata filter
            query_results = index.query(
                vector=vector,  # The embedding of the keyword
                top_k=1,  # Retrieve only the closest match
                include_metadata=True,  # Include metadata in the results
                filter={"category": category}  # Filter results by metadata category dynamically
            )

            # Store the closest match
            if query_results['matches']:
                closest_match = query_results['matches'][0]
                results.append({
                    'Keyword': keyword,  # The searched keyword
                    'Category': category,  # The category used for filtering
                    'Match Score': f"{closest_match['score']:.2f}",  # Similarity score (formatted to 2 decimal places)
                    'Title': closest_match['metadata'].get('title', 'N/A'),  # Title of the article
                    'URL': closest_match['id']  # Using 'id' as the URL
                })
            else:
                results.append({
                    'Keyword': keyword,
                    'Category': category,
                    'Match Score': 'N/A',
                    'Title': 'No match found',
                    'URL': 'N/A'
                })

        except Exception as e:
            clear_output(wait=True)
            print(f"Error processing keyword '{keyword}' with category '{category}': {e}")
            results.append({
                'Keyword': keyword,
                'Category': category,
                'Match Score': 'Error',
                'Title': 'Error occurred',
                'URL': 'N/A'
            })

    return results

# Example usage: Find matches for an array of keywords and categories
keywords = [["SEO Tools", "SEO"], ["TikTok", "TikTok"], ["SEO Consultant", "SEO"]]  # Replace with your keywords and categories
matches = match_keywords_to_index(keywords)

# Display the results in a table
print(tabulate(matches, headers="keys", tablefmt="fancy_grid"))

Estamos intentando encontrar una coincidencia para estas palabras clave:

  • Herramientas SEO.
  • Tik Tok.
  • Consultor SEO.

Y este es el resultado que obtenemos tras ejecutar el código:

Encuentre una coincidencia para la frase de palabras clave en la base de datos de vectoresEncuentre una coincidencia para la frase de palabras clave en la base de datos de vectores

La salida formateada en tabla en la parte inferior muestra las coincidencias de artículos más cercanas a nuestras palabras clave.

4. Inserción de incrustaciones de texto AI de Google Vertex en la base de datos de vectores

Ahora hagamos lo mismo pero con Google Vertex AI’text-embedding-005‘incrustación. Este modelo es notable porque fue desarrollado por Google, impulsa Vertex AI Search y está específicamente capacitado para manejar tareas de recuperación y coincidencia de consultas, lo que lo hace muy adecuado para nuestro caso de uso.

Incluso puedes crear un widget de búsqueda interna y agregarlo a tu sitio web.

Comience iniciando sesión en Google Cloud Console y cree un proyecto. Luego, desde la biblioteca API, busque la API Vertex AI y habilítela.

API de IA de vérticeCaptura de pantalla de Google Cloud Console, diciembre de 2024

Configure su cuenta de facturación para poder utilizar Vertex AI, ya que el precio es de $0,0002 por 1000 caracteres (y ofrece créditos de $300 para nuevos usuarios).

Una vez que lo configure, debe navegar a Servicios API > Credenciales, crear una cuenta de servicio, generar una clave y descargarlas como JSON.

Cambie el nombre del archivo JSON a config.json y cárguelo (mediante el ícono de flecha hacia arriba) en la carpeta de su proyecto Jupyter Notebook.

Captura de pantalla de Google Cloud Console, diciembre de 2024Captura de pantalla de Google Cloud Console, diciembre de 2024

En el primer paso de configuración, cree una nueva base de datos vectorial llamada artículo-índice-vértice configurando la dimensión 768 manualmente.

Una vez creado, puede ejecutar este script para comenzar a generar incrustaciones de vectores a partir del mismo archivo de muestra usando Google Vertex AI. text-embedding-005 modelo (puede elegir text-multilingual-embedding-002 si tiene texto que no está en inglés).

import os
import sys
import time
import numpy as np
import pandas as pd
from typing import List, Optional

from google.auth import load_credentials_from_file
from google.cloud import aiplatform
from google.api_core.exceptions import ServiceUnavailable

from pinecone import Pinecone
from vertexai.language_models import TextEmbeddingModel, TextEmbeddingInput

# Set up your Google Cloud credentials
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "config.json"  # Replace with your JSON key file
credentials, project_id = load_credentials_from_file(os.environ["GOOGLE_APPLICATION_CREDENTIALS"])

# Initialize Pinecone
pinecone = Pinecone(api_key='YOUR_PINECON_API_KEY')  # Replace with your Pinecone API key
index = pinecone.Index("article-index-vertex")       # Replace with your Pinecone index name

# Initialize Vertex AI
aiplatform.init(project=project_id, credentials=credentials, location="us-central1")

def generate_embeddings(
    text: str,
    task: str = "RETRIEVAL_DOCUMENT",
    model_id: str = "text-embedding-005",
    dimensions: Optional[int] = 768
) -> Optional[List[float]]:
    if not text or not text.strip():
        print("Text input is empty. Skipping.")
        return None
    
    try:
        model = TextEmbeddingModel.from_pretrained(model_id)
        input_data = TextEmbeddingInput(text, task_type=task)
        vectors = model.get_embeddings([input_data], output_dimensionality=dimensions)
        return vectors[0].values
    except ServiceUnavailable as e:
        print(f"Vertex AI service is unavailable: {e}")
        return None
    except Exception as e:
        print(f"Error generating embeddings: {e}")
        return None


# Load data from CSV
data = pd.read_csv("Sample Export File.csv")         # Replace with your CSV file path

for idx, row in data.iterrows():
    try:
        permalink = str(row["Permalink"])
        content = row["Content"]
        embedding = generate_embeddings(content)
        
        if not embedding:
            print(f"Skipping article ID {row['ID']} due to empty or failed embedding.")
            continue
        
        print(f"Embedding for {permalink}: {embedding[:5]}...")
        sys.stdout.flush()
        
        index.upsert(vectors=[
            (
                permalink,
                embedding,
                {
                    'category': row['Category'],
                    'title': row['Title'],
                    'publish_date': row['Publish Date'],
                    'type': row['Type'],
                    'publish_year': row['Publish Year']
                }
            )
        ])
        time.sleep(1)  # Optional: Sleep to avoid rate limits
    except Exception as e:
        print(f"Error processing article ID {row['ID']}: {e}")

print("All embeddings are stored in the vector database.")


Verá a continuación los registros de las incrustaciones creadas.

RegistrosCaptura de pantalla de Google Cloud Console, diciembre de 2024

4. Encontrar un artículo que coincida con una palabra clave utilizando Google Vertex AI

Ahora, hagamos la misma coincidencia de palabras clave con Vertex AI. Hay un pequeño matiz, ya que es necesario utilizar ‘RETRIEVAL_QUERY’ frente a ‘RETRIEVAL_DOCUMENT’ como argumento al generar incrustaciones de palabras clave mientras intentamos realizar una búsqueda de un artículo (también conocido como documento) que mejor coincida con nuestra frase.

Los tipos de tareas son una de las ventajas importantes que tiene Vertex AI sobre los modelos de OpenAI.

Garantiza que las incrustaciones capturen la intención de las palabras clave, lo cual es importante para los enlaces internos, y mejora la relevancia y precisión de las coincidencias encontradas en su base de datos vectorial.

Utilice este script para hacer coincidir las palabras clave con los vectores.


import os
import pandas as pd
from google.cloud import aiplatform
from google.auth import load_credentials_from_file
from google.api_core.exceptions import ServiceUnavailable
from vertexai.language_models import TextEmbeddingModel

from pinecone import Pinecone
from tabulate import tabulate  # For table formatting

# Set up your Google Cloud credentials
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "config.json"  # Replace with your JSON key file
credentials, project_id = load_credentials_from_file(os.environ["GOOGLE_APPLICATION_CREDENTIALS"])

# Initialize Pinecone client
pinecone = Pinecone(api_key='YOUR_PINECON_API_KEY')  # Add your Pinecone API key
index_name = "article-index-vertex"  # Replace with your Pinecone index name
index = pinecone.Index(index_name)

# Initialize Vertex AI
aiplatform.init(project=project_id, credentials=credentials, location="us-central1")

def generate_embeddings(
    text: str,
    model_id: str = "text-embedding-005"
) -> list:
    """
    Generates embeddings for the input text using Google Vertex AI's embedding model.
    Returns None if text is empty or an error occurs.
    """
    if not text or not text.strip():
        print("Text input is empty. Skipping.")
        return None

    try:
        model = TextEmbeddingModel.from_pretrained(model_id)
        vector = model.get_embeddings([text])  # Removed 'task_type' and 'output_dimensionality'
        return vector[0].values
    except ServiceUnavailable as e:
        print(f"Vertex AI service is unavailable: {e}")
        return None
    except Exception as e:
        print(f"Error generating embeddings: {e}")
        return None


def match_keywords_to_index(keywords):
    """
    Matches a list of keyword-category pairs to the closest articles in the Pinecone index,
    filtering by metadata if specified.
    """
    results = []

    for keyword_pair in keywords:
        keyword = keyword_pair[0]
        category = keyword_pair[1]

        try:
            keyword_vector = generate_embeddings(keyword)

            if not keyword_vector:
                print(f"No embedding generated for keyword '{keyword}' in category '{category}'.")
                results.append({
                    'Keyword': keyword,
                    'Category': category,
                    'Match Score': 'Error/Empty',
                    'Title': 'No match',
                    'URL': 'N/A'
                })
                continue

            query_results = index.query(
                vector=keyword_vector,
                top_k=1,
                include_metadata=True,
                filter={"category": category}
            )

            if query_results['matches']:
                closest_match = query_results['matches'][0]
                results.append({
                    'Keyword': keyword,
                    'Category': category,
                    'Match Score': f"{closest_match['score']:.2f}",
                    'Title': closest_match['metadata'].get('title', 'N/A'),
                    'URL': closest_match['id']
                })
            else:
                results.append({
                    'Keyword': keyword,
                    'Category': category,
                    'Match Score': 'N/A',
                    'Title': 'No match found',
                    'URL': 'N/A'
                })

        except Exception as e:
            print(f"Error processing keyword '{keyword}' with category '{category}': {e}")
            results.append({
                'Keyword': keyword,
                'Category': category,
                'Match Score': 'Error',
                'Title': 'Error occurred',
                'URL': 'N/A'
            })

    return results

# Example usage: 
keywords = [["SEO Tools", "Tools"], ["TikTok", "TikTok"], ["SEO Consultant", "SEO"]]

matches = match_keywords_to_index(keywords)

# Display the results in a table
print(tabulate(matches, headers="keys", tablefmt="fancy_grid"))


Y verás las puntuaciones generadas:

Puntuaciones de coincidencia de palabras clave producidas por el modelo de incrustación de texto Vertex AIPuntuaciones de coincidencia de palabras clave producidas por el modelo de incrustación de texto Vertex AI

Intente probar la relevancia de la redacción de su artículo

Piense en esto como una forma simplificada (amplia) de comprobar qué tan semánticamente similar es su escritura a la palabra clave principal. Cree una incrustación vectorial de su palabra clave principal y el contenido completo del artículo a través de Vertex AI de Google y calcule una similitud de coseno.

Si su texto es demasiado largo, es posible que deba considerar implementar estrategias de fragmentación.

    Una puntuación cercana (similitud de coseno) a 1,0 (como 0,8 o 0,7) significa que estás bastante cerca de ese tema. Si su puntuación es más baja, es posible que una introducción excesivamente larga y con mucha tontería pueda estar provocando una dilución de la relevancia y cortarla ayuda a aumentarla.

    Pero recuerde, cualquier edición realizada también debe tener sentido desde una perspectiva editorial y de experiencia del usuario.

    Incluso puedes hacer una comparación rápida incorporando contenido de alto rango de un competidor y viendo cómo te comparas.

    Hacer esto le ayudará a alinear con mayor precisión su contenido con el tema objetivo, lo que puede ayudarle a obtener una mejor clasificación.

    Ya existen herramientas que realizan este tipo de tareas, pero aprender estas habilidades significa que puede adoptar un enfoque personalizado adaptado a sus necesidades y, por supuesto, hacerlo de forma gratuita.

    Experimentar por ti mismo y aprender estas habilidades te ayudará a mantenerte a la vanguardia del SEO con IA y a tomar decisiones informadas.

    Como lecturas adicionales, te recomiendo profundizar en estos fantásticos artículos:

    Más recursos:


    Imagen destacada: Aozorastock/Shutterstock

Related Posts
Leave a Reply

Your email address will not be published.Required fields are marked *