スパース・ベクトル
スパース・ベクトルは、ほとんどの要素がゼロで、特定の単語の存在を示す非ゼロの要素が1つだけあるベクトル埋め込みを用いて、単語やフレーズを表現する。SPLADEv2のようなスパース・ベクトル・モデルは、領域外の知識検索、キーワード認識、解釈可能性において、密なモデルを凌駕する。スパースベクトルは情報検索、自然言語処理、推薦システムにおいて特に有用であり、想起のためのスパースベクトルとランキングのためのラージモデルを組み合わせることで、検索結果を大幅に改善することができる。
Milvusでは、スパースベクトルの使用はデンスベクトルと同様のワークフローに従う。スパースベクトル列を持つコレクションを作成し、データを挿入し、インデックスを作成し、類似検索とスカラークエリーを実行します。
このチュートリアルでは、以下の方法を学びます:
- 疎なベクトルの埋め込みを準備する;
- 疎なベクトル・フィールドを持つコレクションを作成する;
- 疎なベクトル埋め込みを持つエンティティの挿入;
- コレクションのインデックスを作成し、スパース・ベクトルで ANN 検索を実行する。
スパースベクトルの動きを見るには、hello_sparse.pyを参照してください。
注釈
現在、スパースベクトルのサポートは2.4.0のベータ機能で、3.0.0で一般的に利用可能になる予定です。スパースベクトルの埋め込みを準備する
Milvusでスパースベクトルを使用するには、サポートされているいずれかのフォーマットでベクトルの埋め込みを準備します:
スパース行列:スパース行列:scipy.sparseクラスファミリーを利用してスパース埋め込みを表現します。この方法は大規模な高次元データを扱うのに効率的です。
辞書のリスト:各スパース埋め込みを辞書として表現します。
{dimension_index: value, ...}
のような構造で,各キーと値のペアは次元インデックスとそれに対応する値を表します。例
{2: 0.33, 98: 0.72, ...}
タプルのイテーブルのリスト.辞書のリストと似ていますが、タプルの反復可能テーブル
[(dimension_index, value)]
を使用して、ゼロでない次元とその値のみを指定します。例
[(2, 0.33), (98, 0.72), ...]
以下の例では、10,000 個のエンティティ(それぞれ 10,000 次元、スパース密度 0.005)について、ランダムなスパース行列を生成して、スパース埋め込みを準備します。
# Prepare entities with sparse vector representation
import numpy as np
import random
rng = np.random.default_rng()
num_entities, dim = 10000, 10000
# Generate random sparse rows with an average of 25 non-zero elements per row
entities = [
{
"scalar_field": rng.random(),
# To represent a single sparse vector row, you can use:
# - Any of the scipy.sparse sparse matrices class family with shape[0] == 1
# - Dict[int, float]
# - Iterable[Tuple[int, float]]
"sparse_vector": {
d: rng.random() for d in random.sample(range(dim), random.randint(20, 30))
},
}
for _ in range(num_entities)
]
# print the first entity to check the representation
print(entities[0])
# Output:
# {
# 'scalar_field': 0.520821523849214,
# 'sparse_vector': {
# 5263: 0.2639375518635271,
# 3573: 0.34701499565746674,
# 9637: 0.30856525997853057,
# 4399: 0.19771651149001523,
# 6959: 0.31025067641541815,
# 1729: 0.8265339135915016,
# 1220: 0.15303302147479103,
# 7335: 0.9436728846033107,
# 6167: 0.19929870545596562,
# 5891: 0.8214617920371853,
# 2245: 0.7852255053773395,
# 2886: 0.8787982039149889,
# 8966: 0.9000606703940665,
# 4910: 0.3001170013981104,
# 17: 0.00875671667413136,
# 3279: 0.7003425473001098,
# 2622: 0.7571360018373428,
# 4962: 0.3901879090102064,
# 4698: 0.22589525720196246,
# 3290: 0.5510228492587324,
# 6185: 0.4508413201390492
# }
# }
注釈
ベクトルの次元は Pythonint
またはnumpy.integer
型でなければならず、値は Pythonfloat
またはnumpy.floating
型でなければなりません。
埋め込みを生成するには、PyMilvus ライブラリに組み込まれたmodel
パッケージを使用することもできます。詳細については、埋め込みを参照してください。
疎なベクトル場を持つコレクションの作成
スパースベクトルフィールドを持つコレクションを作成するには、スパースベクトルフィールドのデータ型を DataType.SPARSE_FLOAT_VECTOR に設定します。密なベクトルとは異なり、疎なベクトルでは次元を指定する必要はありません。
from pymilvus import MilvusClient, DataType
# Create a MilvusClient instance
client = MilvusClient(uri="http://localhost:19530")
# Create a collection with a sparse vector field
schema = client.create_schema(
auto_id=True,
enable_dynamic_fields=True,
)
schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
schema.add_field(field_name="scalar_field", datatype=DataType.DOUBLE)
# For sparse vector, no need to specify dimension
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR) # set `datatype` to `SPARSE_FLOAT_VECTOR`
client.create_collection(collection_name="test_sparse_vector", schema=schema)
一般的なコレクション・パラメータの詳細は、create_collection() を参照してください。
疎ベクトル埋め込みを持つエンティティの挿入
疎なベクトル埋め込みを持つエンティティを挿入するには、単にエンティティのリストを insert()
メソッドに渡します。
# Insert entities
client.insert(collection_name="test_sparse_vector", data=entities)
コレクションのインデックス作成
類似検索の前に、コレクションのインデックスを作成します。インデックスのタイプとパラメータの詳細については、add_index()およびcreate_index() を参照してください。
# Index the collection
# Prepare index params
index_params = client.prepare_index_params()
index_params.add_index(
field_name="sparse_vector",
index_name="sparse_inverted_index",
index_type="SPARSE_INVERTED_INDEX", # the type of index to be created. set to `SPARSE_INVERTED_INDEX` or `SPARSE_WAND`.
metric_type="IP", # the metric type to be used for the index. Currently, only `IP` (Inner Product) is supported.
params={"drop_ratio_build": 0.2}, # the ratio of small vector values to be dropped during indexing.
)
# Create index
client.create_index(collection_name="test_sparse_vector", index_params=index_params)
疎なベクトルに対するインデックス作成では、以下の点に注意してください:
index_type
:構築するインデックスの型。構築するインデックスの型:SPARSE_INVERTED_INDEX
:各次元を非ゼロ・ベクトルに対応付け、検索時に関連データへの直接アクセスを容易にする転置インデックス。疎であるが高次元のデータを持つデータセットに最適。SPARSE_WAND
:Weak-AND(WAND)アルゴリズムを利用して、可能性の低い候補を素早く回避し、より高いランキングの可能性がある候補に評価を集中させる。次元を用語として、ベクトルを文書として扱い、大規模で疎なデータセットの検索を高速化。
metric_type
:疎なベクトルに対しては、IP
(Inner Product) 距離メトリックのみがサポートされる。params.drop_ratio_build
:特にスパースベクトルに使用されるインデックスパラメータ。インデックス作成時に除外される小さなベクトル値の割合を制御します。このパラメータは、インデックスを作成する際に小さな値を無視することで、効率と精度のトレードオフを微調整することができます。例えば、drop_ratio_build = 0.3
の場合、インデックス構築時にすべてのスパース・ベクトルからすべての値が集められ、ソートされる。これらの値のうち最小の30%はインデックスに含まれないため、検索時の計算負荷が軽減される。
詳細については、インメモリ・インデックスを参照のこと。
ANN検索の実行
コレクションがインデックス化され、メモリにロードされたら search()
メソッドを使用して、クエリに基づいて関連文書を検索する。
# Load the collection into memory
client.load_collection(collection_name="test_sparse_vector")
# Perform ANN search on sparse vectors
# for demo purpose we search for the last inserted vector
query_vector = entities[-1]["sparse_vector"]
search_params = {
"metric_type": "IP",
"params": {"drop_ratio_search": 0.2}, # the ratio of small vector values to be dropped during search.
}
search_res = client.search(
collection_name="test_sparse_vector",
data=[query_vector],
limit=3,
output_fields=["pk", "scalar_field"],
search_params=search_params,
)
for hits in search_res:
for hit in hits:
print(f"hit: {hit}")
# Output:
# hit: {'id': '448458373272710786', 'distance': 7.220192909240723, 'entity': {'pk': '448458373272710786', 'scalar_field': 0.46767865218233806}}
# hit: {'id': '448458373272708317', 'distance': 1.2287548780441284, 'entity': {'pk': '448458373272708317', 'scalar_field': 0.7315987515699472}}
# hit: {'id': '448458373272702005', 'distance': 0.9848432540893555, 'entity': {'pk': '448458373272702005', 'scalar_field': 0.9871869181562156}}
検索パラメータを設定する際には、以下の点に注意する:
params.drop_ratio_search
:スパース・ベクトル専用の検索パラメータ。このオプションは、クエリベクトル中の最小値を無視する比率を指定することで、検索処理の微調整を可能にします。検索精度とパフォーマンスのバランスをとるのに役立ちます。drop_ratio_search
に設定する値が小さければ小さいほど、これらの小さな値が最終的なスコアに与える影響は小さくなります。いくつかの小さな値を無視することで、精度への影響を最小限に抑えながら検索パフォーマンスを向上させることができます。
スカラークエリーの実行
ANN検索に加えて、Milvusはスパースベクトルに対するスカラークエリもサポートしています。これらのクエリーでは、スパースベクターに関連付けられたスカラー値に基づいて文書を検索することができます。パラメータの詳細についてはquery()を参照してください。
scalar_field が3 より大きいエンティティをフィルタリングします:
# Perform a query by specifying filter expr
filter_query_res = client.query(
collection_name="test_sparse_vector",
filter="scalar_field > 0.999",
)
print(filter_query_res[:2])
# Output:
# [{'pk': '448458373272701862', 'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}}, {'pk': '448458373272702421', 'scalar_field': 0.9990218525410719, 'sparse_vector': {448: 0.587817907333374, 1866: 0.0994109958410263, 2438: 0.8672442436218262, 2533: 0.8063794374465942, 2595: 0.02122959867119789, 2828: 0.33827054500579834, 2871: 0.1984412521123886, 2938: 0.09674275666475296, 3154: 0.21552987396717072, 3662: 0.5236313343048096, 3711: 0.6463911533355713, 4029: 0.4041993021965027, 7143: 0.7370485663414001, 7589: 0.37588241696357727, 7776: 0.436136394739151, 7962: 0.06377989053726196, 8385: 0.5808192491531372, 8592: 0.8865005970001221, 8648: 0.05727503448724747, 9071: 0.9450633525848389, 9161: 0.146037295460701, 9358: 0.1903032660484314, 9679: 0.3146636486053467, 9974: 0.8561339378356934, 9991: 0.15841573476791382}}]
主キーによるエンティティのフィルタリング:
# primary keys of entities that satisfy the filter
pks = [ret["pk"] for ret in filter_query_res]
# Perform a query by primary key
pk_query_res = client.query(
collection_name="test_sparse_vector", filter=f"pk == '{pks[0]}'"
)
print(pk_query_res)
# Output:
# [{'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}, 'pk': '448458373272701862'}]
制限
Milvus でスパースベクトルを使用する場合、以下の制限を考慮してください:
現在のところ、スパースベクトルではIP距離メトリックのみがサポートされています。
スパースベクタフィールドでは、SPARSE_INVERTED_INDEXと SPARSE_WANDインデックスタイプのみがサポートされています。
よくある質問
スパース・ベクトルはどのような距離メトリックをサポートしていますか?
スパース・ベクトルは高次元のため、L2距離や余弦距離は実用的ではありません。
SPARSE_INVERTED_INDEXとSPARSE_WANDの違いと選択方法を教えてください。
SPARSE_INVERTED_INDEXは伝統的な転置インデックスですが、SPARSE_WANDは Weak-ANDアルゴリズムを使用し、検索中のフルIP距離評価の回数を減らします。SPARSE_WANDは一般的に高速ですが、ベクトル密度が高くなるにつれて性能が低下する可能性があります。どちらかを選択するには、特定のデータセットとユースケースに基づいた実験とベンチマークを実施してください。
drop_ratio_buildとdrop_ratio_searchパラメータはどのように選択すればよいですか?
drop_ratio_buildと drop_ratio_searchの選択は、データの特性と、検索レイテンシー/スループットおよび精度に対する要件に依存します。
スパース埋め込みでサポートされているデータ型は何ですか?
次元部は符号なし32ビット整数、値部は非負の32ビット浮動小数点数です。
スパース埋込みの次元は,uint32空間内の任意の離散値にできますか?
はい,1つの例外があります.スパース埋め込みの次元は,
[0, maximum of uint32)
の範囲内の任意の値にすることができます. つまり,uint32の最大値を使うことはできません.成長しているセグメントの検索は、インデックスを使って行うのですか?
成長中のセグメントを検索するには、セグメントインデックスと同じ型のインデックスを使用します。インデックスが作成される前の新しい成長中のセグメントについては、 総当たり検索を使用します。
1つのコレクションに、疎なベクトルと密なベクトルの両方を持つことは可能ですか?
はい、複数のベクトル型をサポートしているため、疎なベクトル列と密なベクトル列の両方を持つコレクションを作成し、それらに対してハイブリッド検索を実行することができます。
スパース埋め込みを挿入または検索するための条件は何ですか?
スパース埋め込みは少なくとも1つの非ゼロ値を持ち、ベクトルインデックスは非負でなければなりません。