Crea un motor de recomendación de películas con Milvus y Python
Este artículo se publicó originalmente en The New Stack y se vuelve a publicar aquí con permiso.
Usa herramientas de código abierto para ayudar a las personas a encontrar películas que podrían estar interesadas en ver.
Los sistemas de recomendación o motores de recomendación son sistemas de filtrado de información que buscan predecir y sugerir cosas en las que los usuarios podrían estar interesados. Estos elementos incluyen productos, servicios y contenido como películas, libros, música o artículos de noticias.
Existen varios tipos de sistemas de recomendación, como filtrado colaborativo, filtrado basado en contenido, sistemas de recomendación híbridos y sistemas de recomendación basados en vectores. Los sistemas basados en vectores usan el espacio vectorial para encontrar (recomendar) los elementos más cercanos en la base de datos. Hay varias formas de almacenar estos vectores; una de las más eficientes es usar la base de datos vectorial de código abierto Milvus. Esta base de datos es altamente flexible, rápida y fiable, y permite la adición, eliminación, actualización y búsqueda casi en tiempo real de vectores a escala de billones de bytes.
Este artículo explica cómo crear un recomendador de películas con Milvus y Python. Este sistema usará SentenceTransformers para convertir la información textual en vectores y almacenar estos vectores en Milvus. Milvus permite a los usuarios buscar una película en la base de datos en función de la información textual que proporcionen.
Imagen destacada de Tima Miroshnichenko en Pexels
Configuración del entorno
Para este artículo, necesitarás tener instalados los siguientes requisitos:
Administrador de paquetes de Python (PIP) para instalar paquetes
Jupyter Notebook para escribir código
Un sistema con al menos 32 GB de RAM o una cuenta de Zilliz Cloud
Requisitos de Python
También necesitas instalar un conjunto de bibliotecas que serán necesarias a lo largo de este tutorial. Instala las bibliotecas usando PIP:
$ python -m pip install pymilvus pandas sentence_transformers kaggle
Almacén de datos vectoriales (Milvus)
Usarás la base de datos vectorial Milvus para almacenar las incrustaciones que generarás usando descripciones de películas. El conjunto de datos es relativamente grande, al menos para un servidor que se ejecuta en una computadora personal. Así que quizá quieras usar una instancia de Zilliz Cloud para almacenar estos vectores.
Si prefieres quedarte con una instancia local, puedes descargar una configuración de docker-compose y ejecutarla con:
$ wget https://github.com/milvus-io/milvus/releases/download/v2.3.0/milvus-standalone-docker-compose.yml -O docker-compose.yml
$ docker-compose up -d
Ahora tienes todos los requisitos para crear tu propio sistema de recomendación de películas con Milvus.
Recopilación y preprocesamiento de datos
Para este proyecto, usarás el Movies Dataset de Kaggle que contiene metadatos de 45,000 películas. Puedes descargar este conjunto de datos directamente o usar la API de Kaggle para descargar el conjunto de datos usando Python. Para hacerlo con Python, necesitas descargar el archivo kaggle.json desde la sección de perfil de Kaggle.com y colocarlo en una ubicación donde la API pueda encontrarlo.
A continuación, configura algunas variables de entorno para la autenticación de Kaggle. Para esto, puedes abrir el Jupyter Notebook y escribir las siguientes líneas de código:
%env KAGGLE_USERNAME=username
%env KAGGLE_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
%env TOKENIZERS_PARALLELISM=true
Una vez hecho esto, puedes usar la dependencia de Python de Kaggle para descargar el conjunto de datos desde Kaggle:
# import kaggle dependency
import kaggle
kaggle.api.authenticate()
kaggle.api.dataset_download_files('rounakbanik/the-movies-dataset', path='dataset', unzip=True)
Una vez descargado el conjunto de datos, puedes usar el método read_csv() de pandas para leer el conjunto de datos:
# import pandas
import pandas as pd
# read csv data
movies=pd.read_csv('dataset/movies_metadata.csv',low_memory=False)
# check shape of data
movies.shape
Forma del conjunto de datos
La imagen muestra que tienes 45,466 registros con 24 columnas de metadatos. Revisa todas estas columnas de metadatos con:
# check column names
movies.columns
Columnas del conjunto de datos
Hay muchas columnas que no necesitas para crear el sistema de recomendación. Puedes filtrar las columnas requeridas con:
# filter required columns
trimmed_movies = movies[["id", "title", "overview", "release_date", "genres"]]
trimmed_movies.head(5)
Columnas requeridas
Además, faltan algunos campos en los datos, así que elimina esas filas para producir un conjunto de datos limpio:
unclean_movies_dict = trimmed_movies.to_dict('records')
print('{} movies'.format(len(unclean_movies_dict)))
movies_dict = []
for movie in unclean_movies_dict:
if movie["overview"] == movie["overview"] and movie["release_date"] == movie["release_date"] and movie["genres"] == movie["genres"] and movie["title"] == movie["title"]:
movies_dict.append(movie)
Conectarse a Milvus
Ahora que tienes todas las columnas requeridas, conéctate a Milvus para empezar a cargar los datos. Para conectarte a la instancia en la nube de Milvus, necesitarás el Identificador Uniforme de Recursos (URI) y el token, que puedes descargar desde tu panel de Zilliz Cloud.
Panel de Zilliz
Una vez que tengas tu URI y clave de API, puedes usar el método connect() de PyMilvus para conectarte al servidor Milvus:
# import milvus dependency
from pymilvus import *
# connect to milvus
milvus_uri="YOUR_URI"
token="YOUR_API_TOKEN"
connections.connect("default", uri=milvus_uri, token=token)
print("Connected!")
Generar embeddings para películas
Ahora es momento de calcular los embeddings para los datos de texto en el conjunto de datos de películas. Primero, crea un objeto collection que almacenará el ID de la película y los embeddings para los datos de texto. También crea un campo index para hacer que las búsquedas sean más eficientes:
COLLECTION_NAME = 'film_vectors'
PARTITION_NAME = 'Movie'
# Here's our record schema
"""
"title": Film title,
"overview": description,
"release_date": film release date,
"genres": film generes,
"embedding": embedding
"""
id = FieldSchema(name='title', dtype=DataType.VARCHAR, max_length=500, is_primary=True)
field = FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, dim=384)
schema = CollectionSchema(fields=[id, field], description="movie recommender: film vectors", enable_dynamic_field=True)
if utility.has_collection(COLLECTION_NAME): # drop the same collection created before
collection = Collection(COLLECTION_NAME)
collection.drop()
collection = Collection(name=COLLECTION_NAME, schema=schema)
print("Collection created.")
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {"nlist": 128},
}
collection.create_index(field_name="embedding", index_params=index_params)
collection.load()
print("Collection indexed!")
Ahora que tienes una colección indexada, crea una función para generar los embeddings del texto. Aunque overview es la columna principal utilizada para generar los embeddings, también usarás la información de genre y release data junto con un overview para que los datos sean más lógicos.
Para generar los embeddings, usa SentenceTransformer:
from sentence_transformers import SentenceTransformer
import ast
# function to extract the text from genre column
def build_genres(data):
genres = data['genres']
genre_list = ""
entries= ast.literal_eval(genres)
genres = ""
for entry in entries:
genre_list = genre_list + entry["name"] + ", "
genres += genre_list
genres = "".join(genres.rsplit(",", 1))
return genres
# create an object of SentenceTransformer
transformer = SentenceTransformer('all-MiniLM-L6-v2')
# function to generate embeddings
def embed_movie(data):
embed = "{} Released on {}. Genres are {}.".format(data["overview"], data["release_date"], build_genres(data))
embeddings = transformer.encode(embed)
return embeddings
Esta función usa el método build_genres() para limpiar la columna de género y extraer el texto de ella. Luego crea un objeto SentenceTransformer para ayudar a generar los embeddings a partir del texto. Finalmente, usa el método encode() para generar los embeddings utilizando las características overview, release_date y genre.
Enviar embeddings a Milvus
Ahora puedes crear los embeddings usando el método embed_movie(). Este conjunto de datos es demasiado grande para enviarlo a Milvus en una sola instrucción insert, pero enviar filas de datos una por una crearía tráfico de red innecesario y añadiría demasiado tiempo. Por lo tanto, en su lugar crea lotes (por ejemplo, 5,000 filas) de datos para enviar a Milvus:
# Loop counter for batching and showing progress
j = 0
batch = []
for movie_dict in movies_dict:
try:
movie_dict["embedding"] = embed_movie(movie_dict)
batch.append(movie_dict)
j += 1
if j % 5 == 0:
print("Embedded {} records".format(j))
collection.insert(batch)
print("Batch insert completed")
batch=[]
except Exception as e:
print("Error inserting record {}".format(e))
pprint(batch)
break
collection.insert(movie_dict)
print("Final batch completed")
print("Finished with {} embeddings".format(j))
Nota: Puedes ajustar el tamaño del lote para adaptarlo a tus necesidades y preferencias individuales. Además, algunas películas fallarán por IDs que no pueden convertirse a enteros. Podrías solucionar esto con un cambio de esquema o verificando su formato.
Enviar embeddings a Milvus
Recomendar nuevas películas usando Milvus
Ahora puedes aprovechar la funcionalidad de búsqueda vectorial casi en tiempo real de Milvus para obtener una coincidencia cercana de películas que cumplan con los criterios del espectador. Para esto, crea dos funciones diferentes:
embed_search(): Necesitas un transformer para convertir la cadena de búsqueda del usuario en un embedding. Esta función toma los criterios del espectador y los pasa al mismo transformer que usaste para poblar Milvus.
search_for_movies(): Esta función realiza la búsqueda vectorial real usando la otra función como apoyo.
# load collection memory before search
collection.load()
# Set search parameters
topK = 5
SEARCH_PARAM = {
"metric_type":"L2",
"params":{"nprobe": 20},
}
# convert search string to embeddings
def embed_search(search_string):
search_embeddings = transformer.encode(search_string)
return search_embeddings
# search similar embeddings for user's query
def search_for_movies(search_string):
user_vector = embed_search(search_string)
return collection.search([user_vector],"embedding",param=SEARCH_PARAM, limit=topK, expr=None, output_fields=['title', 'overview'])
El código anterior define los parámetros topK para obtener los cinco vectores similares principales, metric_type como L2 (euclidiana al cuadrado) que calcula la distancia entre dos vectores y nprobe que indica el número de unidades de clúster que se deben buscar. También implementa diferentes funciones para obtener vectores similares a partir de la consulta del usuario (recomendación).
Por último, usa la función search_for_movies() para recomendar películas según la cadena de búsqueda del usuario:
from pprint import pprint
search_string = "A comedy from the 1990s set in a hospital. The main characters are in their 20s and are trying to stop a vampire."
results = search_for_movies(search_string)
# check results
for hits in iter(results):
for hit in hits:
print(hit.entity.get('title'))
print(hit.entity.get('overview'))
print("-------------------------------")
Recomendar películas
Al usar la función de búsqueda vectorial de Milvus, el código recomienda las cinco películas similares principales según la consulta del usuario. Eso es todo: ahora has creado tu propio sistema de recomendación de películas usando Milvus.
Conclusión
Después de leer este artículo, sabes qué es un sistema de recomendación basado en vectores y cómo crear un sistema de recomendación de películas con Milvus. Milvus ayuda a crear un sistema de recomendación de películas eficiente y escalable. Al aprovechar el almacenamiento vectorial y la búsqueda por similitud, Milvus tiene un gran potencial para permitir recomendaciones personalizadas, mejorar la interacción de los usuarios y mostrar el papel de los modelos avanzados basados en vectores en los sistemas de recomendación modernos. Puedes obtener más información al respecto en el sitio web de Milvus.
Sigue leyendo

Why We Built Vector Lakebase: Rethinking Unstructured Data Architecture for AI
Vector Lakebase: a unified, lake-native data foundation for AI workloads — and an answer to what happens after vector databases succeed.

Vector Lakebase: End the AI Data Silo
Learn how Vector Lakebase unifies vector search, data lakes, and AI data operations so teams can serve RAG and agents without copy-and-sync pipelines.

Expanding Our Global Reach: Zilliz Cloud Launches in Azure Central India
Zilliz Cloud expands to Azure Central India. This new region helps customers meet compliance, reduce latency, and optimize cloud costs when building AI applications.



