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

Lexical Highlighter

Zilliz Cloud の Highlighter は、テキストフィールド内で一致した用語をカスタマイズ可能なタグで囲んで注釈を付けます。ハイライトは、ドキュメントがクエリに一致した理由の説明、結果の可読性の向上、検索および RAG アプリケーションでのリッチレンダリングのサポートに役立ちます。

ハイライトは、最終的な検索結果セットに対する後処理ステップとして実行されます。候補の取得、フィルタリングロジック、ランキング、スコアリングには影響しません。

Highlighter は、互いに独立した 3 つの制御軸を提供します。

  • ハイライト対象となる用語

    ハイライト対象の用語をどこから取得するかを選択できます。たとえば、BM25 full text search で使用される検索語や、テキストベースのフィルタリング式(TEXT_MATCH 条件など)で指定されたクエリ用語をハイライトできます。

  • ハイライトされた用語のレンダリング方法

    各一致の前後に挿入するタグを設定することで、ハイライト出力内で一致した用語をどのように表示するかを制御できます。たとえば、{} のような単純なマーカーや、リッチレンダリング用の <em></em> のような HTML タグを使用できます。

  • ハイライトされたテキストの返し方

    フラグメントの開始位置、長さ、返されるフラグメント数など、ハイライト結果をフラグメントとして返す方法を制御できます。

以下のセクションでは、これらのシナリオを順に説明します。

BM25 full text search を実行する際、返される結果内で 検索語 をハイライトして、ドキュメントがクエリに一致した理由を説明しやすくできます。BM25 full text search の詳細については、全文検索 を参照してください。

このシナリオでは、ハイライト対象の用語は BM25 full text search で使用された検索語から直接取得されます。Highlighter はこれらの用語を使用して、最終結果内の一致したテキストに注釈を付けます。

次の内容がテキストフィールドに保存されているとします。

plaintext
Milvus supports full text search. Use BM25 for keyword relevance. Filters can narrow results.

Highlighter の設定

BM25 full text search で検索語をハイライトするには、LexicalHighlighter を作成し、BM25 full text search の検索語ハイライトを有効にします。

python
from pymilvus import LexicalHighlighter

highlighter = LexicalHighlighter(
pre_tags=["{"], # Tag inserted before each highlighted term
post_tags=["}"], # Tag inserted after each highlighted term
highlight_search_text=True # Enable search term highlighting for BM25 full text search
)

この例では次のとおりです。

  • pre_tags と post_tags は、出力内でハイライトされたテキストがどのように表示されるかを制御します。この場合、一致した用語は {} で囲まれます(例: {term})。複数のタグをリストとして指定することもできます(例: ["<b>", "<i>"])。複数の用語がハイライトされる場合、タグは順番に適用され、一致シーケンスに応じてローテーションされます。

  • highlight_search_text=True は、BM25 full text search の検索語をハイライト対象の用語のソースとして使用するよう Zilliz Cloud に指示します。

Highlighter オブジェクトを作成したら、その設定を BM25 full text search リクエストに適用します。

python
results = client.search(
...,
data=["BM25"], # Search term used in BM25 full text search
highlighter=highlighter # Pass highlighter config here
)

ハイライト出力

ハイライトが有効な場合、Zilliz Cloud は専用の highlight フィールドにハイライト済みテキストを返します。デフォルトでは、ハイライト出力は最初に一致した用語から始まるフラグメントとして返されます。

この例では、検索語が "BM25" であるため、返された結果内でこれがハイライトされます。

json
{
...,
"highlight": {
"text": [
"{BM25} for keyword relevance. Filters can narrow results."
]
}
}

返されるフラグメントの位置、長さ、数を制御するには、ハイライトされたテキストをフラグメントとして返す を参照してください。

フィルタリングにおけるクエリ用語のハイライト​

検索語のハイライトに加えて、テキストベースのフィルタリング式で使用される用語もハイライトできます。

Notes

現在、クエリ用語のハイライトでサポートされているフィルタリング条件は TEXT_MATCH のみです。詳細については、テキストマッチ を参照してください。

このシナリオでは、ハイライト対象の用語はテキストベースのフィルタリング式から取得されます。フィルタリングはどのドキュメントが一致するかを決定し、Highlighter は一致したテキスト範囲に注釈を付けます。

次の内容がテキストフィールドに保存されているとします。

plaintext
This document explains how text filtering works in Milvus.

Highlighter の設定

フィルタリングで使用されるクエリ用語をハイライトするには、LexicalHighlighter を作成し、フィルタリング条件に対応する highlight_query を定義します。

python
from pymilvus import LexicalHighlighter

highlighter = LexicalHighlighter(
pre_tags=["{"], # Tag inserted before each highlighted term
post_tags=["}"], # Tag inserted after each highlighted term
highlight_query=[{
"type": "TextMatch", # Text filtering type
"field": "text", # Target text field
"text": "text filtering" # Terms to highlight
}]
)

この設定では次のとおりです。

  • pre_tags と post_tags は、出力内でハイライトされたテキストがどのように表示されるかを制御します。この場合、一致した用語は {} で囲まれます(例: {term})。複数のタグをリストとして指定することもできます(例: ["<b>", "<i>"])。複数の用語がハイライトされる場合、タグは順番に適用され、一致シーケンスに応じてローテーションされます。

  • highlight_query は、ハイライト対象とするフィルタリング用語を定義します。

Highlighter オブジェクトを作成したら、同じフィルタリング式と Highlighter 設定を検索リクエストに適用します。

python
results = client.search(
...,
filter='TEXT_MATCH(text, "text filtering")',
highlighter=highlighter # Pass highlighter config here
)

ハイライト出力

フィルタリングでクエリ用語のハイライトが有効な場合、Zilliz Cloud は専用の highlight フィールドにハイライト済みテキストを返します。デフォルトでは、ハイライト出力は最初に一致した用語から始まるフラグメントとして返されます。

この例では、最初に一致した用語は "text" であるため、返されるハイライト済みテキストはその位置から始まります。

json
{
...,
"highlight": {
"text": [
"{text} {filtering} works in Milvus."
]
}
}

返されるフラグメントの位置、長さ、数を制御するには、ハイライトされたテキストをフラグメントとして返す を参照してください。

フラグメントベースのハイライト出力​

デフォルトでは、Zilliz Cloud は最初に一致した用語から始まるフラグメントとしてハイライト済みテキストを返します。フラグメント関連の設定を使用すると、ハイライト対象の用語を変更せずに、フラグメントの返し方をさらに制御できます。

次の内容がテキストフィールドに保存されているとします。

plaintext
Milvus supports full text search. Use BM25 for keyword relevance. Filters can narrow results.

Highlighter の設定

ハイライトフラグメントの形状を制御するには、LexicalHighlighter でフラグメント関連のオプションを設定します。

python
from pymilvus import LexicalHighlighter

highlighter = LexicalHighlighter(
pre_tags=["{"],
post_tags=["}"],
highlight_search_text=True,
fragment_offset=5, # Number of characters to reserve before the first matched term
fragment_size=60, # Max. length of each fragment to return
num_of_fragments=1 # Max. number of fragments to return
)

この設定では次のとおりです。

  • fragment_offset は、最初にハイライトされる用語の前に先行コンテキストを確保します。

  • fragment_size は、各フラグメントに含めるテキスト量を制限します。

  • num_of_fragments は、返されるフラグメント数を制御します。

Highlighter オブジェクトを作成したら、Highlighter 設定を検索リクエストに適用します。

python
results = client.search(
...,
data=["BM25"],
highlighter=highlighter # Pass highlighter config here
)

ハイライト出力

フラグメントベースのハイライトが有効な場合、Zilliz Cloud は highlight フィールド内でハイライト済みテキストをフラグメントとして返します。

json
{
...,
"highlight": {
"text": [
"Use {BM25} for keyword relevance. Filters can narrow results."
]
}
}

この出力では次のとおりです。

  • fragment_offset が設定されているため、フラグメントは {BM25} からちょうど始まるわけではありません。

  • num_of_fragments が 1 であるため、返されるフラグメントは 1 つだけです。

  • フラグメントの長さは fragment_size によって上限が設定されます。

例​

事前準備​

highlighter を使用する前に、コレクションが適切に設定されていることを確認してください。

以下の例では、BM25 full text search と TEXT_MATCH クエリをサポートするコレクションを作成し、その後サンプルドキュメントを挿入します。

コレクションを準備する
python
from pymilvus import (
MilvusClient,
DataType,
Function,
FunctionType,
LexicalHighlighter,
)

client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
COLLECTION_NAME = "highlighter_demo"

# Clean up existing collection
if client.has_collection(COLLECTION_NAME):
client.drop_collection(COLLECTION_NAME)

# Define schema
schema = client.create_schema(enable_dynamic_field=False)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(
field_name="text",
datatype=DataType.VARCHAR,
max_length=2000,
enable_analyzer=True, # Required for BM25
enable_match=True, # Required for TEXT_MATCH
)
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)

# Add BM25 function
schema.add_function(Function(
name="text_bm25",
function_type=FunctionType.BM25,
input_field_names=["text"],
output_field_names=["sparse_vector"],
))

# Create index
index_params = client.prepare_index_params()
index_params.add_index(
field_name="sparse_vector",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={"inverted_index_algo": "DAAT_MAXSCORE", "bm25_k1": 1.2, "bm25_b": 0.75},
)

client.create_collection(collection_name=COLLECTION_NAME, schema=schema, index_params=index_params)

# Insert sample documents
docs = [
"my first test doc",
"my second test doc",
"my first test doc. Milvus is an open-source vector database built for GenAI applications.",
"my second test doc. Milvus is an open-source vector database that suits AI applications "
"of every size from running a demo chatbot to building web-scale search.",
]
client.insert(collection_name=COLLECTION_NAME, data=[{"text": t} for t in docs])
print(f"✓ Collection created with {len(docs)} documents\n")

# Helper for search params
SEARCH_PARAMS = {"metric_type": "BM25", "params": {"drop_ratio_search": 0.0}}

# Expected output:
# ✓ Collection created with 4 documents

この例では、BM25 full text search で検索語をハイライトする方法を示します。

  • BM25 full text search は "test" を検索語として使用します

  • highlighter は "test" のすべての出現箇所を { と } タグで囲みます

python
highlighter = LexicalHighlighter(
pre_tags=["{"],
post_tags=["}"],
highlight_search_text=True, # Highlight BM25 query terms
)

results = client.search(
collection_name=COLLECTION_NAME,
data=["test"],
anns_field="sparse_vector",
limit=10,
search_params=SEARCH_PARAMS,
output_fields=["text"],
highlighter=highlighter,
)

for hit in results[0]:
print(f" {hit.get('highlight', {}).get('text', {}).get('fragments', [])}")
print()
想定される出力
plaintext
['{test} doc']
['{test} doc']
['{test} doc. Milvus is an open-source vector database built for GenAI applications.']
['{test} doc. Milvus is an open-source vector database that suits AI applications of every size from run']

例 2: フィルタリングでクエリ用語をハイライトする​

この例では、TEXT_MATCH フィルタに一致した用語をハイライトする方法を示します。

  • BM25 full text search は "test" をクエリ用語として使用します

  • queries パラメータは "my doc" をハイライト対象リストに追加します

  • highlighter は、一致したすべての用語("my"、"test"、"doc")を { と } で囲みます

python
highlighter = LexicalHighlighter(
pre_tags=["{"],
post_tags=["}"],
highlight_search_text=True, # Also highlight BM25 term
highlight_query=[ # Additional TEXT_MATCH terms to highlight
{"type": "TextMatch", "field": "text", "text": "my doc"},
],
)

results = client.search(
collection_name=COLLECTION_NAME,
data=["test"],
anns_field="sparse_vector",
limit=10,
search_params=SEARCH_PARAMS,
output_fields=["text"],
highlighter=highlighter,
)

for hit in results[0]:
print(f" {hit.get('highlight', {}).get('text', {}).get('fragments', [])}")
print()
想定される出力
plaintext
['{my} first {test} {doc}']
['{my} second {test} {doc}']
['{my} first {test} {doc}. Milvus is an open-source vector database built for GenAI applications.']
['{my} second {test} {doc}. Milvus is an open-source vector database that suits AI applications of every siz']

例 3: ハイライトをフラグメントとして返す​

この例では、クエリが "Milvus" を検索し、以下の設定でハイライトフラグメントを返します。

  • fragment_offset は、最初にハイライトされる範囲の前に最大 20 文字の先行コンテキストを保持します(デフォルトは 0)。

  • fragment_size は、各フラグメントを約 60 文字に制限します(デフォルトは 100)。

  • num_of_fragments は、各テキスト値に対して返されるフラグメント数を制限します(デフォルトは 5)。

python
highlighter = LexicalHighlighter(
pre_tags=["{"],
post_tags=["}"],
highlight_search_text=True,
fragment_offset=20, # Keep 20 chars before match
fragment_size=60, # Max ~60 chars per fragment
)

results = client.search(
collection_name=COLLECTION_NAME,
data=["Milvus"],
anns_field="sparse_vector",
limit=10,
search_params=SEARCH_PARAMS,
output_fields=["text"],
highlighter=highlighter,
)

for i, hit in enumerate(results[0]):
frags = hit.get('highlight', {}).get('text', {}).get('fragments', [])
print(f" Doc {i+1}: {frags}")
print()
想定される出力
plaintext
Doc 1: ['my first test doc. {Milvus} is an open-source vector database ']
Doc 2: ['my second test doc. {Milvus} is an open-source vector database']

例 4: マルチクエリのハイライト​

BM25 full text search で複数のクエリを使用して検索する場合、各クエリの結果はそれぞれ独立してハイライトされます。1 つ目のクエリの結果にはその検索語のハイライトが含まれ、2 つ目のクエリの結果にはその検索語のハイライトが含まれ、以降も同様です。各クエリは同じ highlighter 設定を使用しますが、独立して適用されます。

以下の例では次のとおりです。

  • 1 つ目のクエリは、その結果セット内で "test" をハイライトします

  • 2 つ目のクエリは、その結果セット内で "Milvus" をハイライトします

python
highlighter = LexicalHighlighter(
pre_tags=["{"],
post_tags=["}"],
highlight_search_text=True,
)

results = client.search(
collection_name=COLLECTION_NAME,
data=["test", "Milvus"], # Two queries
anns_field="sparse_vector",
limit=2,
search_params=SEARCH_PARAMS,
output_fields=["text"],
highlighter=highlighter,
)

for nq_idx, hits in enumerate(results):
query_term = ["test", "Milvus"][nq_idx]
print(f" Query '{query_term}':")
for hit in hits:
print(f" {hit.get('highlight', {}).get('text', {}).get('fragments', [])}")
print()
想定される出力
plaintext
Query 'test':
['{test} doc']
['{test} doc']
Query 'Milvus':
['{Milvus} is an open-source vector database built for GenAI applications.']
['{Milvus} is an open-source vector database that suits AI applications of every size from running a dem']

例 5: カスタム HTML タグ​

ハイライトには、Web UI 向けの HTML セーフなタグなど、任意のタグを使用できます。これは、ブラウザーで検索結果をレンダリングする際に便利です。

python
highlighter = LexicalHighlighter(
pre_tags=["<mark>"],
post_tags=["</mark>"],
highlight_search_text=True,
)

results = client.search(
collection_name=COLLECTION_NAME,
data=["test"],
anns_field="sparse_vector",
limit=2,
search_params=SEARCH_PARAMS,
output_fields=["text"],
highlighter=highlighter,
)

for hit in results[0]:
print(f" {hit.get('highlight', {}).get('text', {}).get('fragments', [])}")
print()
想定される出力
plaintext
['<mark>test</mark> doc']
['<mark>test</mark> doc']