Inicio rápido con Milvus Lite
Los vectores, el formato de datos de salida de los modelos de redes neuronales, pueden codificar eficazmente la información y desempeñar un papel fundamental en aplicaciones de IA como la base de conocimientos, la búsqueda semántica, la generación aumentada de recuperación (RAG) y más.
Milvus es una base de datos vectorial de código abierto que se adapta a aplicaciones de IA de todos los tamaños, desde la ejecución de un chatbot de demostración en el cuaderno Jupyter hasta la creación de búsquedas a escala web que sirven a miles de millones de usuarios. En esta guía, le mostraremos cómo configurar Milvus localmente en cuestión de minutos y utilizar la biblioteca cliente Python para generar, almacenar y buscar vectores.
Instalar Milvus
En esta guía utilizamos Milvus Lite, una biblioteca python incluida en pymilvus
que puede incrustarse en la aplicación cliente. Milvus también admite el despliegue en Docker y Kubernetes para casos de uso de producción.
Antes de empezar, asegúrate de que tienes Python 3.8+ disponible en el entorno local. Instale pymilvus
que contiene tanto la biblioteca cliente python como Milvus Lite:
$ pip install -U pymilvus
Si está utilizando Google Colab, para habilitar las dependencias que acaba de instalar, es posible que tenga que reiniciar el tiempo de ejecución. (Haga clic en el menú "Runtime" en la parte superior de la pantalla, y seleccione "Reiniciar sesión" en el menú desplegable).
Configurar la base de datos de vectores
Para crear una base de datos vectorial Milvus local, simplemente instale un MilvusClient
especificando un nombre de archivo para almacenar todos los datos, como "milvus_demo.db".
from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db")
Crear una colección
En Milvus, necesitamos una colección para almacenar vectores y sus metadatos asociados. Puede pensar en ella como en una tabla de las bases de datos SQL tradicionales. Al crear una colección, puede definir parámetros de esquema e índice para configurar las especificaciones del vector, como la dimensionalidad, los tipos de índice y las métricas distantes. También hay conceptos complejos para optimizar el índice para el rendimiento de la búsqueda vectorial. Por ahora, centrémonos en lo básico y utilicemos por defecto para todo lo posible. Como mínimo, sólo necesitas establecer el nombre de la colección y la dimensión del campo vectorial de la colección.
if client.has_collection(collection_name="demo_collection"):
client.drop_collection(collection_name="demo_collection")
client.create_collection(
collection_name="demo_collection",
dimension=768, # The vectors we will use in this demo has 768 dimensions
)
En la configuración anterior,
- La clave primaria y los campos vectoriales utilizan sus nombres por defecto ("id" y "vector").
- El tipo de métrica (definición de distancia vectorial) se establece en su valor por defecto(COSINE).
- El campo de clave primaria acepta números enteros y no se incrementa automáticamente (es decir, no utiliza la función auto-id) Alternativamente, puede definir formalmente el esquema de la colección siguiendo esta instrucción.
Preparar los datos
En esta guía, utilizamos vectores para realizar búsquedas semánticas en texto. Necesitamos generar vectores para el texto descargando modelos de incrustación. Esto puede hacerse fácilmente utilizando las funciones de utilidad de la biblioteca pymilvus[model]
.
Representar texto con vectores
En primer lugar, instale la biblioteca de modelos. Este paquete incluye herramientas esenciales de ML como PyTorch. La descarga del paquete puede llevar algún tiempo si su entorno local nunca ha instalado PyTorch.
$ pip install "pymilvus[model]"
Genere incrustaciones vectoriales con el modelo por defecto. Milvus espera que los datos se inserten organizados como una lista de diccionarios, donde cada diccionario representa un registro de datos, denominado como entidad.
from pymilvus import model
# If connection to https://huggingface.co/ failed, uncomment the following path
# import os
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
# This will download a small embedding model "paraphrase-albert-small-v2" (~50MB).
embedding_fn = model.DefaultEmbeddingFunction()
# Text strings to search from.
docs = [
"Artificial intelligence was founded as an academic discipline in 1956.",
"Alan Turing was the first person to conduct substantial research in AI.",
"Born in Maida Vale, London, Turing was raised in southern England.",
]
vectors = embedding_fn.encode_documents(docs)
# The output vector has 768 dimensions, matching the collection that we just created.
print("Dim:", embedding_fn.dim, vectors[0].shape) # Dim: 768 (768,)
# Each entity has id, vector representation, raw text, and a subject label that we use
# to demo metadata filtering later.
data = [
{"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
for i in range(len(vectors))
]
print("Data has", len(data), "entities, each with fields: ", data[0].keys())
print("Vector dim:", len(data[0]["vector"]))
Dim: 768 (768,)
Data has 3 entities, each with fields: dict_keys(['id', 'vector', 'text', 'subject'])
Vector dim: 768
[Alternativa] Usar representación falsa con vectores aleatorios
Si no has podido descargar el modelo por problemas de red, puedes utilizar vectores aleatorios para representar el texto y terminar el ejemplo. Tenga en cuenta que el resultado de la búsqueda no reflejará la similitud semántica, ya que los vectores son falsos.
import random
# Text strings to search from.
docs = [
"Artificial intelligence was founded as an academic discipline in 1956.",
"Alan Turing was the first person to conduct substantial research in AI.",
"Born in Maida Vale, London, Turing was raised in southern England.",
]
# Use fake representation with random vectors (768 dimension).
vectors = [[random.uniform(-1, 1) for _ in range(768)] for _ in docs]
data = [
{"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
for i in range(len(vectors))
]
print("Data has", len(data), "entities, each with fields: ", data[0].keys())
print("Vector dim:", len(data[0]["vector"]))
Data has 3 entities, each with fields: dict_keys(['id', 'vector', 'text', 'subject'])
Vector dim: 768
Insertar datos
Vamos a insertar los datos en la colección:
res = client.insert(collection_name="demo_collection", data=data)
print(res)
{'insert_count': 3, 'ids': [0, 1, 2], 'cost': 0}
Búsqueda semántica
Ahora podemos hacer búsquedas semánticas representando el texto de la consulta de búsqueda como vector, y realizar búsquedas de similitud vectorial en Milvus.
Búsqueda vectorial
Milvus acepta una o varias peticiones de búsqueda vectorial al mismo tiempo. El valor de la variable query_vectors es una lista de vectores, donde cada vector es una matriz de números flotantes.
query_vectors = embedding_fn.encode_queries(["Who is Alan Turing?"])
# If you don't have the embedding function you can use a fake vector to finish the demo:
# query_vectors = [ [ random.uniform(-1, 1) for _ in range(768) ] ]
res = client.search(
collection_name="demo_collection", # target collection
data=query_vectors, # query vectors
limit=2, # number of returned entities
output_fields=["text", "subject"], # specifies fields to be returned
)
print(res)
data: ["[{'id': 2, 'distance': 0.5859944820404053, 'entity': {'text': 'Born in Maida Vale, London, Turing was raised in southern England.', 'subject': 'history'}}, {'id': 1, 'distance': 0.5118255615234375, 'entity': {'text': 'Alan Turing was the first person to conduct substantial research in AI.', 'subject': 'history'}}]"] , extra_info: {'cost': 0}
La salida es una lista de resultados, cada uno de los cuales corresponde a una consulta de búsqueda vectorial. Cada consulta contiene una lista de resultados, donde cada resultado contiene la clave primaria de la entidad, la distancia al vector de consulta y los detalles de la entidad con output_fields
especificado.
Búsqueda vectorial con filtrado de metadatos
También puede realizar una búsqueda vectorial teniendo en cuenta los valores de los metadatos (llamados campos "escalares" en Milvus, ya que escalar se refiere a datos no vectoriales). Esto se hace con una expresión de filtro que especifica ciertos criterios. Veamos cómo buscar y filtrar con el campo subject
en el siguiente ejemplo.
# Insert more docs in another subject.
docs = [
"Machine learning has been used for drug design.",
"Computational synthesis with AI algorithms predicts molecular properties.",
"DDR1 is involved in cancers and fibrosis.",
]
vectors = embedding_fn.encode_documents(docs)
data = [
{"id": 3 + i, "vector": vectors[i], "text": docs[i], "subject": "biology"}
for i in range(len(vectors))
]
client.insert(collection_name="demo_collection", data=data)
# This will exclude any text in "history" subject despite close to the query vector.
res = client.search(
collection_name="demo_collection",
data=embedding_fn.encode_queries(["tell me AI related information"]),
filter="subject == 'biology'",
limit=2,
output_fields=["text", "subject"],
)
print(res)
data: ["[{'id': 4, 'distance': 0.27030569314956665, 'entity': {'text': 'Computational synthesis with AI algorithms predicts molecular properties.', 'subject': 'biology'}}, {'id': 3, 'distance': 0.16425910592079163, 'entity': {'text': 'Machine learning has been used for drug design.', 'subject': 'biology'}}]"] , extra_info: {'cost': 0}
Por defecto, los campos escalares no se indexan. Si necesita realizar una búsqueda filtrada de metadatos en un conjunto de datos de gran tamaño, puede considerar la posibilidad de utilizar un esquema fijo y activar también el índice para mejorar el rendimiento de la búsqueda.
Además de la búsqueda vectorial, también puede realizar otros tipos de búsqueda:
Consulta
Una consulta() es una operación que recupera todas las entidades que coinciden con un criterio, como una expresión de filtro o la coincidencia con algunos ids.
Por ejemplo, recuperar todas las entidades cuyo campo escalar tenga un valor determinado:
res = client.query(
collection_name="demo_collection",
filter="subject == 'history'",
output_fields=["text", "subject"],
)
Recuperar directamente entidades por clave primaria:
res = client.query(
collection_name="demo_collection",
ids=[0, 2],
output_fields=["vector", "text", "subject"],
)
Borrar entidades
Si desea purgar datos, puede eliminar entidades especificando la clave primaria o eliminar todas las entidades que coincidan con una expresión de filtro determinada.
# Delete entities by primary key
res = client.delete(collection_name="demo_collection", ids=[0, 2])
print(res)
# Delete entities by a filter expression
res = client.delete(
collection_name="demo_collection",
filter="subject == 'biology'",
)
print(res)
[0, 2]
[3, 4, 5]
Cargar Datos Existentes
Dado que todos los datos de Milvus Lite se almacenan en un archivo local, puede cargar todos los datos en memoria incluso después de que el programa termine, creando un MilvusClient
con el archivo existente. Por ejemplo, esto recuperará las colecciones del archivo "milvus_demo.db" y continuará escribiendo datos en él.
from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db")
Eliminar la colección
Si desea eliminar todos los datos de una colección, puede eliminar la colección con
# Drop collection
client.drop_collection(collection_name="demo_collection")
Más información
Milvus Lite es ideal para comenzar con un programa python local. Si tiene datos a gran escala o le gustaría usar Milvus en producción, puede aprender sobre el despliegue de Milvus en Docker y Kubernetes. Todos los modos de despliegue de Milvus comparten la misma API, por lo que su código del lado del cliente no necesita cambiar mucho si se mueve a otro modo de despliegue. Simplemente especifique el URI y Token de un servidor Milvus desplegado en cualquier lugar:
client = MilvusClient(uri="http://localhost:19530", token="root:Milvus")
Milvus proporciona API REST y gRPC, con librerías cliente en lenguajes como Python, Java, Go, C# y Node.js.