MinHash 関数
MinHash 関数は、生テキストをドキュメント間の Jaccard 類似度 を近似するバイナリベクトルに変換します。テキストシングリングと複数のハッシュ関数を適用して固定長のシグネチャベクトルを生成し、大規模なニアデュプリケート検出やドキュメントの重複排除を実現します。
MinHash は組み込み関数として Zilliz Cloud 内で実行されるため、外部モデルの推論や前処理は不要です。生テキストを挿入するだけで、Zilliz Cloud が MinHash シグネチャベクトルを自動的に生成します。
制限事項
-
各 MinHash シグネチャは 32 ビットのハッシュ値であるため、出力フィールドは次元が
dim % 32 == 0を満たすBINARY_VECTORである必要があります。 -
バイナリベクトルフィールドの
dimは32 * num_hashesと一致している必要があります。一致しない場合はエラーが発生します。 -
MinHash 関数の出力に対して
MINHASH_LSHインデックスを使用する場合、mh_element_bit_widthを32に設定する必要があります。
MinHash の仕組み
展開して仕組みを確認
MinHash は、集合間の Jaccard 類似度 を推定するための局所性鋭敏ハッシュ手法です。Zilliz Cloud における MinHash 関数のパイプラインは次のとおりです。生テキストを入力すると、中間処理がすべて内部で行われ、Zilliz Cloud からバイナリベクトルが出力されます。
全体のワークフローは、ドキュメントの取り込みとクエリ処理の両方で共通の共有テキスト処理パイプラインと、その後に続く保存・検索用のフェーズ固有の処理で構成されます。

共有テキスト処理パイプライン
ドキュメントの取り込みとクエリ処理のいずれも、生テキストに対して同じ 4 段階の変換処理を行います。
-
テキスト分析:
token_levelが"word"の場合は アナライザー によってテキストが処理され、token_levelが"char"の場合はテキストがそのまま使用されます。単語レベルのトークン化では、入力フィールドに設定されたアナライザーを使用してテキストをタームに分割します。たとえば、"milvus is vector db"は["milvus", "is", "vector", "db"]となります。 -
シングリング: トークンをサイズ
shingle_sizeの重複する n-gram(シングル)に分割します。たとえば、単語レベルの 3-gram の場合、トークン["information", "retrieval", "is", "a", "field"]は["information retrieval is", "retrieval is a", "is a field"]のようなシングルになります。 -
MinHash シグネチャ生成: 複数のハッシュ関数(H1、H2、...、Hn、ここで n =
num_hashes)がシングル集合に適用されます。各ハッシュ関数について、すべてのシングルにわたる最小ハッシュ値が選択されます。これらの最小値のコレクションが MinHash シグネチャを形成します。これは、元のドキュメントの Jaccard 類似度を近似する固定長の表現です。 -
バイナリベクトルへのエンコード: 各シグネチャ値は 32 ビットのハッシュであり、シグネチャ全体が次元
32 * num_hashesのBINARY_VECTORにパックされます。
ドキュメントの取り込み
データの挿入時、共有パイプラインで生成されたバイナリベクトルが MINHASH_LSH インデックスに格納されます。このインデックスは LSH(Locality-Sensitive Hashing)テーブルを管理し、類似したシグネチャを同じバケットにグループ化することで、クエリ時の候補取得を高速化します。
クエリ処理
検索時は、クエリテキストが同じ共有パイプラインを通ってバイナリベクトルに変換されます。このベクトルを用いて MINHASH_LSH インデックス上で LSH ルックアップが行われ、類似性の高い候補ペアが迅速に特定されます。Jaccard リファインメントが無効の場合、Zilliz Cloud は推定 Jaccard 類似度によるランキングを行わずに LSH 候補を返します。有効にすると、Zilliz Cloud が格納済みの生の MinHash シグネチャに基づいて候補を推定 Jaccard 類似度で並べ替え、top-K の結果を返します。
どちらの経路でも同じ変換ロジックが使われるため、内容が大きく重複する 2 つのドキュメントからは類似した MinHash シグネチャが生成されます。これにより、語順、書式、細かな言い回しの違いがあっても、ニアデュプリケートを効果的に検出できます。
事前準備
MinHash 関数を使用する前に、以下の要素を含むようにコレクションスキーマを設計してください。
-
生コンテンツ用のテキストフィールド
コレクションには、生テキストを格納するための
VARCHARフィールドが必要です。このフィールドが MinHash 関数の入力となります。 -
テキストフィールド用のアナライザー(単語レベルのトークン化を使用する場合)
token_levelが"word"(デフォルト)に設定されている場合、テキストフィールドでアナライザーを有効にする必要があります。アナライザーは、シングリング前のテキストのトークン化方法を定義します。デフォルトでは、Zilliz Cloud はstandardアナライザーを使用します。別のアナライザーを設定する場合は、ユースケースに適したアナライザーの選択 を参照してください。 -
MinHash 出力用のバイナリベクトルフィールド
コレクションには、MinHash 関数で生成されるバイナリベクトルを格納するための
BINARY_VECTORフィールドが必要です。次元は32 * num_hashesと一致している必要があります。
ステップ 1: MinHash 関数付きのコレクションを作成する
MinHash 関数を使用するには、コレクション作成時に関数を定義します。この関数はコレクションスキーマの一部となり、データの挿入および検索時に自動的に適用されます。
スキーマフィールドの定義
コレクションスキーマには、少なくとも次の 3 つのフィールドを含める必要があります。
-
プライマリフィールド: コレクション内の各エンティティを一意に識別します。
-
テキストフィールド(
VARCHAR): 生テキストドキュメントを格納します。enable_analyzer=Trueを設定することで、Zilliz Cloud が MinHash シグネチャ生成のためにテキストを処理できるようになります。デフォルトでは、Zilliz Cloud はテキスト分析にstandardアナライザーを使用します。別のアナライザーを設定する場合は、ユースケースに適したアナライザーの選択 を参照してください。 -
バイナリベクトルフィールド(
BINARY_VECTOR): MinHash 関数によって自動生成されたバイナリベクトルを格納します。次元は32 * num_hashesと一致している必要があります。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
from pymilvus import MilvusClient, DataType, Function, FunctionType
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT", token="YOUR_CLUSTER_TOKEN")
schema = client.create_schema()
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="document_content", datatype=DataType.VARCHAR, max_length=9000, enable_analyzer=True)
schema.add_field(field_name="binary_vector", datatype=DataType.BINARY_VECTOR, dim=8192)
// java
// nodejs
// go
# restful
// cpp
MinHash 関数を定義する
MinHash 関数は、解析済みのテキストをバイナリベクトルに変換し、ドキュメント間の Jaccard 類似度を近似します。
関数を定義してスキーマに追加します。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
minhash_function = Function(
name="minhash_function",
input_field_names=["document_content"], # Name of the VARCHAR field containing raw text
output_field_names=["binary_vector"], # Name of the BINARY_VECTOR field for generated signatures
function_type=FunctionType.MINHASH,
params={
"num_hashes": 256, # Number of hash functions; produces dim = 32 * 256 = 8192
"shingle_size": 3, # N-gram size for shingling
}
)
schema.add_function(minhash_function)
// java
// nodejs
// go
# restful
// cpp
設定オプション
MinHash 関数の params 辞書では、以下のパラメーターを指定できます。すべてのパラメーター名は大文字・小文字を区別しません。
パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
| int |
| シグネチャ生成に用いるハッシュ関数の数です。出力されるバイナリベクトルの次元は |
| int |
| シングリングに使用する N-gram のサイズです。単語レベルの場合は 1〜3、文字レベルの場合は 2〜6 が一般的です。 |
| str |
| 使用するハッシュ関数です。選択肢:
|
| str |
| トークン化のレベルです。選択肢:
単語レベルは意味的な強度と効率に優れていますが、言語固有のトークン化に依存します。文字レベルは言語非依存ですが、より高次元のシングルが生成され、意味的な強度は弱くなります。 |
| int |
| MinHash 関数の初期化に使用するランダムシードです。 |
インデックスを設定する
MinHash バイナリベクトルには、インデックスタイプ MINHASH_LSH、メトリックタイプ MHJACCARD の組み合わせが推奨されます。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
index_params = client.prepare_index_params()
index_params.add_index(
field_name="binary_vector",
index_type="MINHASH_LSH",
metric_type="MHJACCARD",
params={
"mh_lsh_band": 128,
"mh_element_bit_width": 32,
"with_raw_data": True,
},
)
// java
// nodejs
// go
# restful
// cpp
検索時に Jaccard リファインメントを使用する場合は、with_raw_data を True に設定してください。LSH ルックアップで得られた候補について推定 Jaccard 類似度を算出するには、生の MinHash シグネチャが必要です。
コレクションを作成する
上記で定義したスキーマとインデックスのパラメーターを使用してコレクションを作成します。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
client.create_collection(
collection_name="dedup_collection",
schema=schema,
index_params=index_params,
)
// java
// nodejs
// go
# restful
// cpp
ステップ 2: ドキュメントを挿入する
コレクションの準備ができたら、テキストデータを挿入します。生のテキストを指定するだけで、MinHash 関数が各ドキュメントのバイナリベクトルを自動的に生成します。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
client.insert(
"dedup_collection",
[
{"document_content": "information retrieval is a field of study that helps users find relevant information in large datasets"},
{"document_content": "information retrieval is a research field focused on helping users find relevant data in large collections"},
{"document_content": "information retrieval is a field of research helping users search for relevant information in large datasets"},
],
)
// java
// nodejs
// go
# restful
// cpp
ステップ 3: MinHash で検索する
データの挿入後、生のテキストクエリを入力して類似ドキュメントを検索できます。Zilliz Cloud が各クエリを MinHash バイナリベクトルに自動変換します。Jaccard リファインメントを有効にすると、推定 Jaccard 類似度に基づいて LSH 候補をランキングできます。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
search_params = {
"metric_type": "MHJACCARD",
"params": {
"mh_search_with_jaccard": True,
"refine_k": 3,
},
}
results = client.search(
collection_name="dedup_collection",
data=["information retrieval is a research field focused on helping users find relevant data in large collections"],
anns_field="binary_vector",
limit=3,
output_fields=["document_content"],
search_params=search_params,
)
for hits in results:
for hit in hits:
print(f"ID: {hit['id']}, Distance: {hit['distance']}")
print(f"Document: {hit['entity']['document_content']}")
// java
// nodejs
// go
# restful
// cpp
Jaccard リファインメントを有効にするには、mh_search_with_jaccard を True に設定します。refine_k はリファインメントに使用する候補プールの容量を制御します。Zilliz Cloud は容量として max(refine_k, limit) を使用しますが、LSH ルックアップの一致数が少ない場合は、実際にリファインメントされる候補数も少なくなることがあります。refine_k を大きくすると、計算コストは増えますが結果の品質を向上できる可能性があります。
次のステップ
-
Full Text Search: 類似重複検出ではなく、BM25 を用いた語彙レベルの関連性ランキングを行います。
-
Analyzer Overview: テキストのトークン化に使用するカスタムアナライザーを設定します。
-
MINHASH_LSH インデックス: 再現率とパフォーマンスのための LSH パラメーターの調整について学びます。