メインコンテンツまでスキップ

BM25 関数

BM25 関数は、生のテキストをスパースベクトルに変換し、字句的な関連性に基づいてドキュメントをスコアリングすることで、フルテキスト検索 を可能にします。用語ベースのマッチングと頻度を考慮した重み付けを適用し、クエリ用語に密接に一致するテキストドキュメントを効率的に取得できるようにします。

ローカルテキスト関数として、BM25 関数は Zilliz Cloud 内で実行され、モデル推論や外部統合を必要としません。テキストベースの検索シナリオに対して、決定論的で透過的な取得メカニズムを提供します。

BM25 の仕組み​

BM25 アルゴリズムは、フルテキスト検索で広く使用されている用語ベースの関連性スコアリングアルゴリズムです。Zilliz Cloud では、BM25 はスパース検索パイプラインとして実装されており、テキストを用語の重み表現に変換し、分散スパースインデックスを使用して上位 K 件のドキュメントを取得します。

ワークフロー全体は、ドキュメントの取り込みとクエリテキストの処理という 2 つの対称的なパスで構成され、これらは同じテキスト解析ロジックを共有します。

ドキュメントの取り込み: テキストからスパース表現へ​

ドキュメントが挿入されると、その生のテキストはまず analyzer によって処理され、個々の用語にトークン化されます。

例えば、次のドキュメントを考えます。

plaintext
"We are loving Milvus!"

これは、次の用語に解析できます。

plaintext
["we", "love", "milvus"]

次に、各ドキュメントは、各用語がドキュメント内に何回出現するかを記録する用語頻度(TF)表現として表されます。例えば、次のようになります。

plaintext
{
"we": 1,
"love": 1,
"milvus": 1
}

同時に、Zilliz Cloud はコーパスレベルの統計情報を更新します。これには次のものが含まれます。

  • 各用語のドキュメント頻度(DF)

  • 平均ドキュメント長

  • 各用語を、その用語を含むドキュメントに対応付けるポスティングリスト

ドキュメントの TF 表現はスパース埋め込みに挿入され、用語のポスティングはスケーラブルな取得のためにノード間で分割されます。

クエリテキストの処理: IDF 重み付けの適用​

テキストベースのクエリが発行されると、ドキュメントの取り込み 時と同じ analyzer によって処理され、一貫した用語の分割が保証されます。

例えば、次のクエリを考えます。

plaintext
"who loves Milvus?"

これは、次のように解析できます。

plaintext
["who", "love", "milvus"]

Zilliz Cloud は、各クエリ用語について、コーパス統計からその逆文書頻度(IDF)を参照します。IDF は、データセット全体で用語がどの程度情報量を持つかを表します。希少な用語ほど高い重みを受け取り、一般的な用語ほど低い重みを受け取ります。

概念的には、これにより次のような IDF で重み付けされたクエリ用語のセットが生成されます。

plaintext
{
"who": 0.1,
"love": 0.5,
"milvus": 1.2
}

BM25 スコアリングと上位 K 件の取得​

BM25 は、一致したクエリ用語に基づいて関連性スコアを計算することで、ドキュメントをランク付けします。スコアリングは用語レベルで実行され、ドキュメントレベルで集計されます。

用語レベルのスコアリング

ドキュメントに出現する各クエリ用語について、BM25 は用語レベルのスコアを計算します。

plaintext
term_score =
IDF(term) ×
TF_boost(term, document, k1) ×
length_normalization(document, b)

ここで、

  • IDF(term) は、その用語がコレクション内でどれだけ希少であるかを表します。

  • TF_boost(…, k1) は、用語頻度とともに増加しますが、頻度が高くなるにつれて飽和します。

  • length_normalization(…, b) は、ドキュメント長に基づいてスコアを調整します。

ドキュメントレベルのスコアリングと Top-K 取得

最終的なドキュメントスコアは、一致したすべてのクエリ用語の用語レベルスコアの合計です。

plaintext
document_score =
sum of term_score over all matched query terms

ドキュメントは最終スコアでランク付けされ、スコアの高い上位 K 件のドキュメントが返されます。

事前準備​

BM25 関数を使用する前に、コレクションのスキーマが字句的なフルテキスト検索をサポートするように計画してください。

  • 生のコンテンツ用のテキストフィールド

    コレクションには、生のテキストを格納するための VARCHAR フィールドを含める必要があります。このフィールドは、フルテキスト検索のために処理されるテキストのソースとなります。

  • テキストフィールド用の analyzer

    テキストフィールドでは analyzer を有効にする必要があります。analyzer は、BM25 関数によって字句的な関連性が計算される前に、テキストがどのようにトークン化および正規化されるかを定義します。

    デフォルトでは、Zilliz Cloud は空白と句読点に基づいてテキストをトークン化する組み込みの analyzer を提供します。アプリケーションでカスタムのトークン化や正規化の動作が必要な場合は、カスタム analyzer を定義できます。詳細については、ユースケースに適した Analyzer を選ぶ を参照してください。

  • BM25 出力用のスパースベクトル

    コレクションには、BM25 関数によって生成されるスパース表現を格納するための SPARSE_FLOAT_VECTOR フィールドを含める必要があります。このフィールドは、フルテキスト検索時のインデックス作成と取得に使用されます。

これらのスキーマレベルの検討事項を確認したら、コレクションを作成し、BM25 関数を使用します。

ステップ 1: BM25 関数を使用してコレクションを作成する​

BM25 関数を使用するには、コレクションの作成時に定義する必要があります。この関数はコレクションのスキーマの一部となり、データの挿入時と検索時に自動的に適用されます。

SDK 経由​

スキーマフィールドを定義する​

コレクションのスキーマには、少なくとも 3 つの必須フィールドを含める必要があります。

  • プライマリフィールド: コレクション内の各エンティティを一意に識別します。

  • テキストフィールド (VARCHAR): 生のテキストドキュメントを格納します。Zilliz Cloud が BM25 関連性ランキングのためにテキストを処理できるよう、enable_analyzer=True を設定する必要があります。デフォルトでは、Zilliz Cloud はテキスト解析に standard analyzer を使用します。別の analyzer を設定するには、Analyzer の概要 を参照してください。

  • スパースベクトルフィールド (SPARSE_FLOAT_VECTOR): BM25 関数によって自動的に生成されるスパース埋め込みを格納します。

python
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) # Primary field
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True) # Text field
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR) # Sparse vector field; no dim required for sparse vectors

BM25 関数を定義する​

BM25 関数は、トークン化されたテキストを、BM25 スコアリングをサポートするスパースベクトルに変換します。

関数を定義し、スキーマに追加します。

python
bm25_function = Function(
name="text_bm25_emb", # Function name
input_field_names=["text"], # Name of the VARCHAR field containing raw text data
output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings
function_type=FunctionType.BM25, # Set to `BM25`
)

schema.add_function(bm25_function)

インデックスを構成する​

必要なフィールドと組み込み関数を含むスキーマを定義したら、コレクションのインデックスを設定します。このプロセスを簡素化するには、index_type として AUTOINDEX を使用します。これは、データの構造に基づいて Zilliz Cloud が最適なインデックスタイプを選択して構成できるようにするオプションです。

python
index_params = client.prepare_index_params()

index_params.add_index(
field_name="sparse",
index_type="AUTOINDEX",
metric_type="BM25"
)

コレクションを作成する​

次に、定義したスキーマとインデックスパラメーターを使用してコレクションを作成します。

python
client.create_collection(
collection_name='my_collection',
schema=schema,
index_params=index_params
)

client.load_collection('my_collection')

Web コンソール経由​

または、Zilliz Cloud コンソール で BM25 関数を使用してコレクションを作成することもできます。

BM25 関数を備えたコレクションが作成されたら、テキストを挿入し、テキストクエリに基づく字句検索を実行できます。

ステップ 2: コレクションにテキストデータを挿入する​

コレクションとインデックスを設定したら、テキストデータを挿入する準備が整います。このプロセスでは、生のテキストを指定するだけで済みます。先ほど定義した BM25 関数が、各テキストエントリのスパースベクトルを自動的に生成します。

python
client.insert('my_collection', [
{'text': 'information retrieval is a field of study.'},
{'text': 'information retrieval focuses on finding relevant information in large datasets.'},
{'text': 'data mining and information retrieval overlap in research.'},
])

ステップ 3: テキストクエリで検索する​

コレクションにデータを挿入したら、生のテキストクエリを使用してフルテキスト検索を実行できます。Zilliz Cloud はクエリを自動的にスパースベクトルに変換し、BM25 アルゴリズムを使用して一致した検索結果をランク付けしてから、上位 K 件(limit)の結果を返します。

python
search_params = {
"metric_type": "BM25", # Metric type must be BM25 for full text search
'params': {'level': 10},
}

res = client.search(
collection_name='my_collection',
data=['whats the focus of information retrieval?'],
anns_field='sparse',
output_fields=['text'], # Fields to return in search results; sparse field cannot be output
limit=3,
search_params=search_params
)

print(res)