Démarrage rapide avec Milvus Lite
Les vecteurs, le format de données de sortie des modèles de réseaux neuronaux, peuvent encoder efficacement des informations et jouer un rôle central dans les applications d'IA telles que les bases de connaissances, la recherche sémantique, la Génération Augmentée de Récupération (RAG) et bien plus encore.
Milvus est une base de données vectorielle open-source qui convient aux applications d'IA de toutes tailles, depuis l'exécution d'un chatbot de démonstration dans un bloc-notes Jupyter jusqu'à la construction d'une recherche à l'échelle du web qui sert des milliards d'utilisateurs. Dans ce guide, nous allons vous expliquer comment installer Milvus localement en quelques minutes et utiliser la bibliothèque client Python pour générer, stocker et rechercher des vecteurs.
Installer Milvus
Dans ce guide, nous utilisons Milvus Lite, une bibliothèque Python incluse dans pymilvus
qui peut être intégrée dans l'application client. Milvus prend également en charge le déploiement sur Docker et Kubernetes pour les cas d'utilisation en production.
Avant de commencer, assurez-vous que vous disposez de Python 3.8+ dans l'environnement local. Installez pymilvus
qui contient à la fois la bibliothèque client python et Milvus Lite :
$ pip install -U pymilvus
Si vous utilisez Google Colab, pour activer les dépendances qui viennent d'être installées, vous devrez peut-être redémarrer le runtime. (Cliquez sur le menu "Runtime" en haut de l'écran, et sélectionnez "Restart session" dans le menu déroulant).
Configuration de la base de données vectorielle
Pour créer une base de données vectorielle locale Milvus, il suffit d'instancier une base de données MilvusClient
en spécifiant un nom de fichier pour stocker toutes les données, par exemple "milvus_demo.db".
from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db")
Création d'une collection
Dans Milvus, nous avons besoin d'une collection pour stocker les vecteurs et leurs métadonnées associées. Vous pouvez l'assimiler à une table dans les bases de données SQL traditionnelles. Lors de la création d'une collection, vous pouvez définir des paramètres de schéma et d'index pour configurer les spécifications des vecteurs telles que la dimensionnalité, les types d'index et les métriques distantes. Il existe également des concepts complexes permettant d'optimiser l'index pour les performances de la recherche vectorielle. Pour l'instant, concentrons-nous sur les principes de base et utilisons les paramètres par défaut dans la mesure du possible. Au minimum, il suffit de définir le nom de la collection et la dimension du champ vectoriel de la collection.
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
)
Dans la configuration ci-dessus,
- La clé primaire et les champs vectoriels utilisent leurs noms par défaut ("id" et "vector").
- Le type de métrique (définition de la distance vectorielle) est défini sur sa valeur par défaut(COSINE).
- Le champ de clé primaire accepte les entiers et ne s'incrémente pas automatiquement (c'est-à-dire qu'il n'utilise pas la fonction auto-id). Vous pouvez également définir formellement le schéma de la collection en suivant cette instruction.
Préparer les données
Dans ce guide, nous utilisons des vecteurs pour effectuer une recherche sémantique sur du texte. Nous devons générer des vecteurs pour le texte en téléchargeant des modèles d'intégration. Ceci peut être facilement réalisé en utilisant les fonctions utilitaires de la bibliothèque pymilvus[model]
.
Représenter un texte avec des vecteurs
Commencez par installer la bibliothèque de modèles. Ce paquetage comprend des outils ML essentiels tels que PyTorch. Le téléchargement du paquet peut prendre un certain temps si votre environnement local n'a jamais installé PyTorch.
$ pip install "pymilvus[model]"
Générer des embeddings vectoriels avec le modèle par défaut. Milvus s'attend à ce que les données soient insérées sous la forme d'une liste de dictionnaires, où chaque dictionnaire représente un enregistrement de données, appelé entité.
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
[Alternative] Utiliser une fausse représentation avec des vecteurs aléatoires
Si vous n'avez pas pu télécharger le modèle en raison de problèmes de réseau, vous pouvez utiliser des vecteurs aléatoires pour représenter le texte et terminer l'exemple. Notez simplement que les résultats de la recherche ne refléteront pas la similarité sémantique puisque les vecteurs sont faux.
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
Insérer les données
Insérons les données dans la collection :
res = client.insert(collection_name="demo_collection", data=data)
print(res)
{'insert_count': 3, 'ids': [0, 1, 2], 'cost': 0}
Recherche sémantique
Nous pouvons maintenant effectuer des recherches sémantiques en représentant le texte de la requête sous forme de vecteur et effectuer une recherche de similarité vectorielle sur Milvus.
Recherche vectorielle
Milvus accepte une ou plusieurs demandes de recherche vectorielle en même temps. La valeur de la variable query_vectors est une liste de vecteurs, où chaque vecteur est un tableau de nombres flottants.
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 sortie est une liste de résultats, chacun correspondant à une requête de recherche vectorielle. Chaque requête contient une liste de résultats, où chaque résultat contient la clé primaire de l'entité, la distance au vecteur de la requête, et les détails de l'entité avec une spécification output_fields
.
Recherche vectorielle avec filtrage des métadonnées
Vous pouvez également effectuer une recherche vectorielle en tenant compte des valeurs des métadonnées (appelées champs "scalaires" dans Milvus, car scalaire fait référence à des données non vectorielles). Cette opération s'effectue à l'aide d'une expression de filtrage spécifiant certains critères. Voyons comment rechercher et filtrer avec le champ subject
dans l'exemple suivant.
# 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}
Par défaut, les champs scalaires ne sont pas indexés. Si vous avez besoin d'effectuer une recherche filtrée de métadonnées dans un grand ensemble de données, vous pouvez envisager d'utiliser un schéma fixe et d'activer l'index pour améliorer les performances de la recherche.
Outre la recherche vectorielle, vous pouvez également effectuer d'autres types de recherche :
Requête
Une requête() est une opération qui permet de récupérer toutes les entités correspondant à un critère, tel qu'une expression de filtre ou certains identifiants.
Par exemple, récupérer toutes les entités dont le champ scalaire a une valeur particulière :
res = client.query(
collection_name="demo_collection",
filter="subject == 'history'",
output_fields=["text", "subject"],
)
Récupérer directement les entités par clé primaire :
res = client.query(
collection_name="demo_collection",
ids=[0, 2],
output_fields=["vector", "text", "subject"],
)
Supprimer des entités
Si vous souhaitez purger des données, vous pouvez supprimer des entités en spécifiant la clé primaire ou supprimer toutes les entités correspondant à une expression de filtre particulière.
# 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]
Charger des données existantes
Comme toutes les données de Milvus Lite sont stockées dans un fichier local, vous pouvez charger toutes les données dans la mémoire même après la fin du programme, en créant un MilvusClient
avec le fichier existant. Par exemple, ceci récupérera les collections du fichier "milvus_demo.db" et continuera à y écrire des données.
from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db")
Supprimer la collection
Si vous souhaitez supprimer toutes les données d'une collection, vous pouvez abandonner la collection à l'aide de la commande
# Drop collection
client.drop_collection(collection_name="demo_collection")
En savoir plus
Milvus Lite est idéal pour démarrer avec un programme python local. Si vous avez des données à grande échelle ou si vous souhaitez utiliser Milvus en production, vous pouvez en savoir plus sur le déploiement de Milvus sur Docker et Kubernetes. Tous les modes de déploiement de Milvus partagent la même API, de sorte que votre code côté client n'a pas besoin de changer beaucoup si vous passez à un autre mode de déploiement. Il suffit de spécifier l'URI et le token d'un serveur Milvus déployé n'importe où :
client = MilvusClient(uri="http://localhost:19530", token="root:Milvus")
Milvus fournit des API REST et gRPC, avec des bibliothèques client dans des langages tels que Python, Java, Go, C# et Node.js.