Carga de embeddings en Pinecone para búsqueda semántica
Clase 24 de 26 • Curso de Embeddings y Bases de Datos Vectoriales para NLP
Resumen
¿Cómo llevar nuestro proyecto a una base de datos vectorial?
Hoy nos sumergimos en el fascinante mundo de las bases de datos vectoriales, una pieza clave en las búsquedas semánticas modernas. Si bien nuestro proyecto ya cuenta con un dataframe completo, necesitamos almacenarlo adecuadamente para realizar consultas eficientes. El objetivo es trasladar datos a una base de datos vectorial usando Pinecone. Aunque elegimos Pinecone específicamente, métodos similares son aplicables a otras plataformas como Chroma o Deep Lake. ¡Así que comencemos!
¿Cómo configuramos Pinecone?
Lo primero es importar Pinecone en nuestro entorno de trabajo, junto con el módulo GetPass para manejar credenciales de manera segura. Este paso es crucial, ya que necesitamos proteger nuestro API Key de Pinecone:
import pinecone
from getpass import getpass
pinecone_api_key = getpass("Enter Pinecone API Key: ")
Dado que el API Key nos ofrece acceso completo a la base de datos, debemos manejarlo con sumo cuidado, compartiéndolo solo con quienes necesiten manipular la base de datos.
¿Cómo inicializamos la instancia de Pinecone?
Una vez tenemos el API Key, procedemos a inicializar Pinecone. Utilizamos la versión gratuita de Google Cloud Platform (GCP) en el entorno US-West4
, que es más que suficiente para el alcance de nuestro proyecto.
pinecone.init(
api_key=pinecone_api_key,
environment='us-west4-gcp'
)
Con la instancia lista, podemos crear o acceder a los índices donde almacenaremos nuestros datos.
¿Cómo creamos o accedemos a un índice en Pinecone?
Crear o utilizar un índice existente en Pinecone es sencillo. Primero, determinamos la dimensionalidad de los embeddings que manejaremos para asegurarnos de adaptar nuestro índice a estas dimensiones:
dimension_embeddings = len(df['embeddings'][0]) # Ejemplo: 384 dimensiones
index_name = "movies_embeddings"
¿Cómo podemos crear un índice si no existe?
Verificar si un índice ya está creado evita errores redundantes. Si el índice no existe, lo creamos especificando las dimensiones y la métrica de similitud que emplearemos. Para búsquedas semánticas, el coseno es una opción común:
if index_name not in pinecone.list_indexes():
pinecone.create_index(
index_name=index_name,
dimension=dimension_embeddings,
metric='cosine'
)
Si el índice ya existe, simplemente accedemos a él:
index = pinecone.Index(index_name)
¿Cómo ingestar datos en Pinecone?
Llegamos al punto crucial: ingresar los datos al índice. Utilizaremos el paquete tqdm
para mostrar una barra de progreso, mientras transferimos los datos en lotes de 64 registros:
from tqdm import tqdm
def ingest_data(df, index):
for i in tqdm(range(0, len(df), 64)):
batch = df.iloc[i:i + 64]
# Extraemos IDs, embeddings y metadata
ids = batch['ids'].tolist()
embeddings = batch['embeddings'].tolist()
metadata = batch[['metadata_col']].to_dict('records')
# Ingestamos los datos en el índice
index.upsert(vectors=list(zip(ids, embeddings, metadata)))
ingest_data(df, index)
Al culminar la ingesta, verificamos que los datos estén correctamente cargados mediante el método describe_index_stats()
:
stats = index.describe_index_stats()
print(stats)
Esta función nos muestra el conteo de registros y asegura que todo funciona perfectamente.
¿Cómo optimizamos nuestro flujo de trabajo?
En la próxima etapa, exploraremos cómo realizar consultas y presentarlas de manera gráfica. Este enfoque es clave para evitar la repetición de consultas similares y facilitar la escalabilidad del proyecto.
El mundo de las bases de datos vectoriales ofrece oportunidades únicas para la búsqueda semántica. Al integrar estos conocimientos, abrimos un abanico de posibilidades para proyectos futuros. No pierdas la oportunidad de seguir perfeccionando tus habilidades y explorando nuevas tecnologías; el aprendizaje constante es clave para el éxito.