🚀 Zilliz Cloudを無料で試す、完全管理型のMilvus—10倍の高速パフォーマンスを体験しよう!今すぐ試す>>

milvus-logo
LFAI

使い方

  • Engineering
February 07, 2022
Lichen Wang

Milvus2.0は、バッチとストリームの統合処理とクラウドネイティブアーキテクチャを特徴としており、DELETE機能の開発において、前作よりも大きな挑戦となりました。その先進的なストレージと計算の分離設計と柔軟な公開/サブスクリプションメカニズムのおかげで、我々はそれを実現できたことを誇りに思います。Milvus2.0では、指定されたコレクション内のエンティティを主キーで削除することで、削除されたエンティティが検索やクエリの結果に表示されなくなります。

MilvusのDELETE操作は論理的な削除であり、物理的なデータのクリーンアップはData Compactionで行われることに注意してください。論理削除はI/O速度に制約される検索性能を大幅に向上させるだけでなく、データ復元を容易にします。論理削除されたデータも、タイムトラベル機能を利用することで復元することができます。

使い方

まず、Milvus 2.0のDELETE関数を試してみましょう。(以下の例ではMilvus 2.0.0上のPyMilvus 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)

実装

Milvusインスタンスにおいて、データノードは主にストリーミングデータ(ログブローカ内のログ)を履歴データ(ログスナップショット)としてパッキングし、オブジェクトストレージに自動的にフラッシュする役割を担っています。クエリノードは完全なデータ、すなわちストリーミングデータと履歴データの両方に対して検索要求を実行する。

クラスタ内の並列ノードのデータ書き込み能力を最大限に活用するため、Milvusはプライマリキーハッシングに基づくシャーディング戦略を採用し、書き込み処理を異なるワーカーノードに均等に分散する。つまり、プロキシはエンティティのデータ操作言語(DML)メッセージ(すなわちリクエスト)を同じデータノードとクエリノードにルーティングします。これらのメッセージはDML-Channelを通して公開され、データノードとクエリノードによって別々に消費され、検索とクエリのサービスを一緒に提供します。

データノード

データINSERTメッセージを受信したデータノードは、メモリ内のストリーミングデータを受信するために作成された新しいセグメントである成長セグメントにデータを挿入します。データ行数か成長セグメントの持続時間のいずれかが閾値に達すると、データノードはそれを封印して、データの受信を防ぐ。その後、データノードは、履歴データを含む封印されたセグメントをオブジェクトストレージにフラッシュする。一方、データノードは新しいデータの主キーに基づいてブルームフィルタを生成し、封印されたセグメントと一緒にオブジェクトストレージに流し、セグメントの統計情報を含む統計バイナリログ(binlog)の一部としてブルームフィルタを保存する。

ブルームフィルタは、長いバイナリベクトルと一連のランダムマッピング関数からなる確率的データ構造である。ある要素が集合のメンバーであるかどうかをテストするために使用できるが、偽の正一致を返す可能性がある。 -- ウィキペディア

データ DELETE メッセージが来ると、データノードは対応するシャード内のすべてのブルームフィルタをバッファリングし、メッセージで指定されたプライマリキーと照合して、削除するエンティティを含む可能性のあるすべてのセグメント(成長しているものと封印されたものの両方から)を検索する。対応するセグメントを特定すると、data node はそれらをメモリにバッファリングして、削除操作を記録する Delta binlog を生成し、それらの binlog をセグメントと一緒にオブジェクトストレージにフラッシュします。

Data Node データノード

1つのシャードには1つのDML-Channelしか割り当てられないため、クラスタに追加されたクエリノードはDML-Channelにサブスクライブできません。すべてのクエリノードが DELETE メッセージを受信できるように、データノードは DML-Channel からの DELETE メッセージをフィルタリングし、すべてのクエリノードに削除操作を通知するために Delta-Channel に転送します。

クエリノード

オブジェクトストレージからコレクションをロードする場合、クエリノードはまず各シャードのチェックポイントを取得します。チェックポイントに基づき、クエリノードはすべてのシールされたセグメントをデルタビンログとブルームフィルタとともにロードします。すべてのデータがロードされると、クエリノードはDML-Channel、Delta-Channel、およびQuery-Channelをサブスクライブします。

コレクションがメモリにロードされた後、さらにデータINSERTメッセージが来た場合、クエリノードはまず、メッセージに従って成長しているセグメントをピンポイントで特定し、クエリのみを目的として、メモリ内の対応するブルームフィルタを更新する。これらのクエリ専用のブルームフィルタは、クエリ終了後にオブジェクトストレージにフラッシュされることはありません。

Query Node クエリ・ノード

上述したように、DML-Channel から DELETE メッセージを受信できるのは一定数のクエリ・ノードのみであり、そのクエリ・ノードのみが DELETE リクエストを成長するセグメントで実行できることを意味します。DML-Channel を購読しているクエリノードは、まず成長セグメントの DELETE メッセージをフィルタリングし、提供された主キーと成長セグメントのクエリ専用のブルームフィルタをマッチングさせてエンティティを特定し、対応するセグメントに削除操作を記録する。

DML-Channel をサブスクライブできないクエリノードは、Delta-Channel をサブスクライブし、データノードから転送された DELETE メッセージを受信することしかできないため、密封されたセグメントに対する検索リクエストやクエリリクエストを処理することしかできない。Delta-Channel から密閉されたセグメント内のすべての DELETE メッセージを収集した後、クエリノードは提供された主キーを密閉されたセグメントのブルームフィルターとマッチさせることでエンティティの位置を特定し、対応するセグメントに削除操作を記録する。

最終的に、検索またはクエリにおいて、クエリノードは削除レコードに基づいてビットセットを生成し、削除されたエンティティを省略し、セグメントのステータスに関係なく、すべてのセグメントから残りのエンティティを検索する。最後に、一貫性レベルは削除されたデータの可視性に影響します。強い一貫性レベル (前のコードサンプルで示したとおり) では、削除されたエンティティは削除後すぐに見えなくなります。Bounded Consistency Levelが採用されている場合、削除されたエンティティが見えなくなるまで数秒の待ち時間が発生します。

次は何でしょうか?

2.0新機能シリーズのブログでは、新機能の設計を説明することを目的としています。このブログシリーズの続きを読む

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

続けて読む