Qu’est-ce que Pymilvus ?
Introduction
Pymilvus est le SDK Python conçu pour Milvus et Zilliz Cloud. Il s’agit d’un client basé sur gRPC qui utilise un protobuf Milvus commun partagé entre tous les SDK. Pour les nouveaux utilisateurs comme pour les utilisateurs avancés, il donne accès à toutes les fonctionnalités offertes par Milvus et constitue l’un de nos SDK les plus populaires.
Problèmes que nous rencontrions
L’idée clé autour de la base de données vectorielle Milvus est de donner aux utilisateurs autant de leviers que possible pour les aider à affiner le système en fonction de leur cas d’usage spécifique. Cependant, la recherche approximative est, par essence, approximative ; il n’existe pas d’algorithme universel. Chacun des algorithmes excelle selon le calcul, la vitesse ou le rappel/la précision. Plus encore, chacun des algorithmes peut être configuré pour atteindre un équilibre différent entre les catégories précédentes. Par exemple, HNSW vs. IVF-PQ. IVF-PQ est optimisé pour le calcul et la vitesse, réduisant considérablement la charge mémoire et les temps de recherche au prix d’un rappel fortement réduit. HNSW est l’inverse ; HNSW sacrifie le calcul au profit de la vitesse et du rappel. Ce qui est passionnant, c’est que leurs forces peuvent être échangées via la configuration. Toute cette configuration se situe uniquement au niveau de l’index. Au niveau du cluster, des équilibres doivent être trouvés en termes de coût vs vitesse, ce qui est propre à chaque utilisateur. Certains utilisateurs peuvent ne pas se soucier de la haute disponibilité et ne pas vouloir de réplication. Certains utilisateurs peuvent ne pas se soucier de la cohérence et préférer être moins cohérents au bénéfice de la vitesse. Certains utilisateurs peuvent vouloir associer un TTL à leurs données afin de réduire les coûts de stockage, tandis que d’autres souhaitent que chaque opération soit sauvegardée. Bien que cette personnalisation soit excellente pour les grands utilisateurs, pour lesquels l’optimisation de l’équilibre est bénéfique sur des ensembles de données de taille milliardaire, pour les plus petits utilisateurs, tous ces leviers ne font qu’ajouter trop de confusion.
En plus du fait que ces leviers posent problème, à l’heure actuelle, Zilliz Cloud et Milvus ne sont pas interchangeables en raison des index et des paramètres de connexion.
Qu’est-ce que MilvusClient
MilvusClient est une tentative de simplifier l’API pour la plupart des utilisateurs. De nombreux utilisateurs ne veulent pas gérer les connexions, les schémas, l’indexation, le chargement, les paramètres, etc. MilvusClient masque tous ces aspects en enveloppant le SDK Pymilvus avec une API simple, identique pour Milvus et Zilliz. Pour le moment, il propose :
- insert_data()
- upsert_data()
- search_data()
- query_data()
- get_vectors_by_pk()
- delete_by_pk()
- add_partition()
- remove_partition()
Ces fonctions ont été choisies comme étant les fonctions clés dont tout utilisateur de base aurait besoin. À l’heure actuelle, les opérations sont proposées par Pymilvus, mais de nombreuses choses supplémentaires doivent être faites pour garantir qu’elles fonctionnent correctement.
insert_data:
Avec MilvusClient, il n’est pas nécessaire de créer un schéma pour une collection. Le schéma est plutôt généré automatiquement à partir des données insérées. Cela implique de déterminer le FieldSchema requis et la manière de l’organiser. De nombreux utilisateurs considéraient la création de ce schéma comme un point de friction, c’est pourquoi nous le faisons en arrière-plan. Une fois le schéma dynamique pris en charge, nous pourrons modifier l’implémentation sans changement pour l’utilisateur.
def _infer_fields(self, data):
"""Infer all the fields based on the input data."""
# TODO: Assuming ordered dict for 3.7
fields = {}
# Figure out each datatype of the input.
for key, value in data.items():
# Infer the corresponding datatype of the metadata
dtype = infer_dtype_bydata(value)
# Datatype isnt compatible
if dtype in (DataType.UNKNOWN, DataType.NONE):
logger.error(
"Failed to parse schema for collection %s, unrecognized dtype for key: %s",
self.collection_name,
key,
)
raise ValueError(f"Unrecognized datatype for {key}.")
# Create an entry under the field name
fields[key] = {}
fields[key]["name"] = key
fields[key]["dtype"] = dtype
# Area for attaching kwargs for certain datatypes
if dtype == DataType.VARCHAR:
fields[key]["max_length"] = 65_535
return fields
Pour MilvusClient, nous voulions nous en tenir à un format de données similaire à celui d’autres projets dans ce domaine : une liste de dictionnaires. Ce format est facile à comprendre et à utiliser, et il est équivalent aux Documents que l’on trouve dans LlamaIndex et LangChain. Cependant, ce format est incompatible avec pymilvus, car l’insertion de pymilvus prend des données colonnaires sous forme de liste de listes. Ce format de données colonnaire n’est pas facile à utiliser, car il implique d’ordonner vos listes exactement dans l’ordre dans lequel votre schéma a été défini et n’offre aucune flexibilité. En outre, les messages d’erreur reçus pour des données mal formatées pourraient être meilleurs.
for k in data:
for key, value in k.items():
if key in self.fields:
insert_dict.setdefault(key, []).append(value)
for i in self.tqdm(range(0, len(data), batch_size), disable=not progress_bar):
# Convert dict to list of lists batch for insertion
try:
insert_batch = [
insert_dict[key][i : i + batch_size]
for key in self.fields
if key != ignore_pk
]
Avec tous les changements à venir pour le schéma, les JSON, etc., disposer d’un wrapper autour d’une insertion simple nous permettra de nous charger du gros du travail et de laisser une API simple à l’utilisateur.
upsert_data:
Dans la version 2.2, l’upsert n’existe pas dans Milvus. Pour effectuer un upsert, il est nécessaire d’effectuer une suppression -> insertion. Comme de nombreux utilisateurs recherchent cette fonctionnalité, nous avons décidé de l’inclure dans le client. Une fois la fonctionnalité ajoutée à pymilvus, nous pourrons facilement la modifier sans nécessiter de changements dans le code de l’utilisateur.
pks = [x[self.pk_field] for x in data]
self.delete_by_pk(pks, timeout)
ret = self.insert_data(
data=data,
timeout=timeout,
batch_size=batch_size,
partition=partition,
progress_bar=progress_bar,
)
search_data:
Les principales modifications apportées à la commande de recherche étaient les paramètres de recherche par défaut et la conversion des sorties en une sortie sous forme de liste de dictionnaires.
ret = []
for hits in res:
query_result = []
for hit in hits:
ret_dict = {x: hit.entity.get(x) for x in return_fields}
query_result.append({"score": hit.score, "data": ret_dict})
ret.append(query_result)
query_data:
Les principales modifications apportées à la commande de requête étaient la conversion des sorties en une liste de dictionnaires.
get_vectors_by_pk:
L’extraction de vecteurs dans pymilvus se fait au moyen de requêtes. Ce que de nombreux utilisateurs ignorent, c’est que la requête doit être effectuée sur la base d’un filtre de clé primaire. En plus de cela, si une clé primaire varchar est utilisée, l’expression dans la requête devra comporter des guillemets échappés, ce qui est fastidieux et méconnu des utilisateurs.
# Varchar pks need double quotes around the values
if self.fields[self.pk_field] == DataType.VARCHAR:
ids = ['"' + str(entry) + '"' for entry in pks]
expr = f"""{self.pk_field} in [{','.join(ids)}]"""
else:
ids = [str(entry) for entry in pks]
expr = f"{self.pk_field} in [{','.join(ids)}]"
delete_by_pk:
Similaire à get_vectors_by_pk.
add_partition and delete_partition:
Pour la logique de partition, les utilisateurs doivent savoir que la modification des partitions nécessite le déchargement et le chargement d’une collection. Cela est désormais géré en arrière-plan.
Conclusion:
Dans l’ensemble, l’objectif principal de ce client est d’ajouter des opérations faciles à utiliser qui n’existent pas ou ne sont pas optimisées côté pymilvus. À mesure que pymilvus s’améliore, nous pourrons optimiser ces opérations en arrière-plan et conserver une API simple à utiliser.
Continuer à lire

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.

Vector Databases vs. Time Series Databases
Use a vector database for similarity search and semantic relationships; use a time series database for tracking value changes over time.

Selecting the Right ETL Tools for Unstructured Data to Prepare for AI
Learn the right ETL tools for unstructured data to power AI. Explore key challenges, tool comparisons, and integrations with Milvus for vector search.



