Utilisation
Doté d'un traitement unifié par lots et en continu et d'une architecture cloud-native, Milvus 2.0 représente un défi plus important que son prédécesseur lors du développement de la fonction DELETE. Grâce à sa conception avancée de désagrégation du stockage et du calcul et au mécanisme flexible de publication/abonnement, nous sommes fiers d'annoncer que nous y sommes parvenus. Dans Milvus 2.0, vous pouvez supprimer une entité dans une collection donnée avec sa clé primaire afin que l'entité supprimée ne soit plus répertoriée dans le résultat d'une recherche ou d'une requête.
Veuillez noter que l'opération DELETE dans Milvus se réfère à la suppression logique, alors que le nettoyage physique des données a lieu pendant le compactage des données. La suppression logique permet non seulement d'améliorer considérablement les performances de recherche limitées par la vitesse d'E/S, mais aussi de faciliter la récupération des données. Les données supprimées logiquement peuvent toujours être récupérées à l'aide de la fonction Time Travel.
Utilisation
Essayons d'abord la fonction DELETE dans Milvus 2.0. (L'exemple suivant utilise PyMilvus 2.0.0 sur Milvus 2.0.0).
from pymilvus import connections, utility, Collection, DataType, FieldSchema, CollectionSchema
# Connect to Milvus
connections.connect(
alias="default",
host='x.x.x.x',
port='19530'
)
# Create a collection with Strong Consistency level
pk_field = FieldSchema(
name="id",
dtype=DataType.INT64,
is_primary=True,
)
vector_field = FieldSchema(
name="vector",
dtype=DataType.FLOAT_VECTOR,
dim=2
)
schema = CollectionSchema(
fields=[pk_field, vector_field],
description="Test delete"
)
collection_name = "test_delete"
collection = Collection(
name=collection_name,
schema=schema,
using='default',
shards_num=2,
consistency_level="Strong"
)
# Insert randomly generated vectors
import random
data = [
[i for i in range(100)],
[[random.random() for _ in range(2)] for _ in range(100)],
]
collection.insert(data)
# Query to make sure the entities to delete exist
collection.load()
expr = "id in [2,4,6,8,10]"
pre_del_res = collection.query(
expr,
output_fields = ["id", "vector"]
)
print(pre_del_res)
# Delete the entities with the previous expression
collection.delete(expr)
# Query again to check if the deleted entities exist
post_del_res = collection.query(
expr,
output_fields = ["id", "vector"]
)
print(post_del_res)
Mise en œuvre
Dans une instance Milvus, un nœud de données est principalement responsable de l'empaquetage des données en continu (journaux dans le courtier de journaux) en tant que données historiques (instantanés de journaux) et de leur vidage automatique vers le stockage d'objets. Un nœud d'interrogation exécute les demandes de recherche sur des données complètes, c'est-à-dire à la fois des données en continu et des données historiques.
Pour tirer le meilleur parti de la capacité d'écriture de données des nœuds parallèles d'une grappe, Milvus adopte une stratégie de partage basée sur le hachage de clés primaires afin de répartir uniformément les opérations d'écriture entre les différents nœuds de travail. En d'autres termes, le proxy achemine les messages DML (Data Manipulation Language) (c'est-à-dire les demandes) d'une entité vers le même nœud de données et le même nœud d'interrogation. Ces messages sont publiés via le canal DML et consommés par le nœud de données et le nœud d'interrogation séparément afin de fournir des services de recherche et d'interrogation ensemble.
Nœud de données
Après avoir reçu les messages INSERT de données, le nœud de données insère les données dans un segment croissant, qui est un nouveau segment créé pour recevoir des données en continu dans la mémoire. Si le nombre de lignes de données ou la durée du segment croissant atteint le seuil, le nœud de données le scelle pour empêcher toute entrée de données. Le nœud de données évacue ensuite le segment scellé, qui contient les données historiques, vers le stockage d'objets. Pendant ce temps, le nœud de données génère un filtre bloom basé sur les clés primaires des nouvelles données, et l'envoie dans le stockage d'objets avec le segment scellé, en sauvegardant le filtre bloom dans le journal binaire des statistiques (binlog), qui contient les informations statistiques du segment.
Un filtre de Bloom est une structure de données probabiliste composée d'un long vecteur binaire et d'une série de fonctions de mappage aléatoires. Il peut être utilisé pour tester si un élément est membre d'un ensemble, mais peut renvoyer des résultats faussement positifs. -- Wikipedia
Lorsque des messages de suppression de données arrivent, le nœud de données met en mémoire tampon tous les filtres Bloom dans le shard correspondant, et les fait correspondre aux clés primaires fournies dans les messages pour récupérer tous les segments (à la fois les segments en croissance et les segments scellés) qui pourraient inclure les entités à supprimer. Après avoir repéré les segments correspondants, le nœud de données les met en mémoire tampon pour générer les binlogs Delta afin d'enregistrer les opérations de suppression, puis renvoie ces binlogs ainsi que les segments vers le stockage d'objets.
Nœud de données
Étant donné qu'un canal DML n'est attribué qu'à un seul shard, les nœuds de requête supplémentaires ajoutés au cluster ne pourront pas s'abonner au canal DML. Pour s'assurer que tous les nœuds de requête peuvent recevoir les messages DELETE, les nœuds de données filtrent les messages DELETE du canal DML et les transmettent au canal Delta pour notifier les opérations de suppression à tous les nœuds de requête.
Nœud de requête
Lors du chargement d'une collection à partir du stockage d'objets, le nœud d'interrogation obtient d'abord le point de contrôle de chaque tesson, qui marque les opérations DML depuis la dernière opération de vidage. Sur la base du point de contrôle, le nœud d'interrogation charge tous les segments scellés avec leur binlog Delta et leurs filtres Bloom. Une fois toutes les données chargées, le nœud de requête s'abonne à DML-Channel, Delta-Channel et Query-Channel.
Si d'autres messages INSERT de données arrivent après le chargement de la collection en mémoire, le nœud d'interrogation identifie d'abord les segments croissants en fonction des messages et met à jour les filtres de floraison correspondants en mémoire à des fins d'interrogation uniquement. Ces filtres de floraison dédiés à la requête ne seront pas évacués vers le stockage d'objets une fois la requête terminée.
Nœud de requête
Comme indiqué ci-dessus, seul un certain nombre de nœuds de requête peuvent recevoir des messages DELETE du canal DML, ce qui signifie qu'ils sont les seuls à pouvoir exécuter les requêtes DELETE dans des segments croissants. Les nœuds de requête qui se sont abonnés au canal DML filtrent d'abord les messages DELETE dans les segments croissants, localisent les entités en faisant correspondre les clés primaires fournies avec les filtres de Bloom des segments croissants dédiés aux requêtes, puis enregistrent les opérations de suppression dans les segments correspondants.
Les nœuds de requête qui ne peuvent pas s'abonner au canal DML sont uniquement autorisés à traiter des demandes de recherche ou de requête sur des segments scellés, car ils ne peuvent s'abonner qu'au canal Delta et recevoir les messages DELETE transmis par les nœuds de données. Après avoir collecté tous les messages DELETE dans les segments scellés du canal Delta, les nœuds de requête localisent les entités en faisant correspondre les clés primaires fournies avec les filtres Bloom des segments scellés, puis enregistrent les opérations de suppression dans les segments correspondants.
Enfin, lors d'une recherche ou d'une interrogation, les nœuds d'interrogation génèrent un jeu de bits basé sur les enregistrements de suppression afin d'omettre les entités supprimées et de rechercher parmi les entités restantes de tous les segments, quel que soit l'état du segment. Enfin, le niveau de cohérence influe sur la visibilité des données supprimées. Avec un niveau de cohérence fort (comme le montre l'exemple de code précédent), les entités supprimées sont immédiatement invisibles après la suppression. Si le niveau de cohérence limité est adopté, il y aura plusieurs secondes de latence avant que les entités supprimées ne deviennent invisibles.
Quelles sont les prochaines étapes ?
Dans la série de blogs sur les nouvelles fonctionnalités de la version 2.0, nous nous efforcerons d'expliquer la conception des nouvelles fonctionnalités. En savoir plus sur cette série de blogs !
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word