メインコンテンツまでスキップ
に最終更新

Lance ハイブリッド検索のパフォーマンスに関するベストプラクティス

Lance のベクトル検索や全文検索にスカラー条件を組み合わせる場合は、このガイドを参照してください。フィルタの配置、インデックスセグメントの構成、繰り返し発生するフィルタリング処理の見つけ方を説明します。ここでいうハイブリッド検索とは、検索にスカラーフィルタリングを組み合わせることです。ベクトル検索と全文検索の TVF を別々に呼び出しても、ランキングが自動的に統合されるわけではありません。

注記

Lance Catalog は実験的な機能で、Apache Doris 4.2 以降でサポートされます。まず Lance Catalog でアクセスを設定し、リーダーとライターの互換性要件を確認してください。Doris は既存の Lance インデックスを読み取ります。インデックスの構築と保守には互換性のある Lance ツールを使用してください。最新の Lance SDK やアップストリームの提案にある機能が、使用中の Doris ビルドに同梱されたリーダーでサポートされるとは限りません。

自動 Lance 検索を含む Doris 4.2 ビルドでは、条件を満たす通常の SQL から、明示的な TVF と同じネイティブ検索パスを利用できます。この機能は TVF を直接呼び出す機能とは独立しています。vector_search() が動作するだけで、以前のビルドもこの機能をサポートすると判断しないでください。自動検索専用のセッションスイッチは不要です。

関数の対応関係​

SQL 式必要な並び順Lance のメトリックと SQL の結果
l2_distance_approximateASCl2。ネイティブの L2 距離の二乗ではなく、ユークリッド距離として CAST(sqrt(_distance) AS FLOAT) を返します。
inner_product_approximateDESCdot。内積類似度として 1.0f - _distance を返します。
cosine_distance_approximateASCcosine。ネイティブのコサイン距離を返します。
cosine_similarity_approximateDESCcosine。1.0f - _distance を返します。
hamming_distance_approximateASChamming。異なるビットの数を返します。
score() と MATCH_ANY、MATCH_ALL、または MATCH_PHRASEDESCLance BM25。それぞれ Match OR、Match AND、Phrase に対応します。

cosine_distance()、cosine_similarity()、hamming_distance を含む厳密な距離・類似度関数は、引き続きスカラー関数として実行されます。l1_distance() もスカラー関数のままです。同梱の Lance ベクトル検索 API は L1 メトリックを公開していません。

ベクトル検索と BM25 の例​

Catalog の設定後、lance_catalog.default.items に id、category、content、4 次元の Float32 固定長リスト embedding、および 3 バイトの UInt8 固定長リスト binary_embedding があるとします。インデックスによる高速化が必要な場合は、互換性のあるベクトルインデックスと、content に対するコミット済み FTS インデックスを Lance ツールで構築してください。

SELECT id, cosine_distance_approximate(embedding, [0.1,0.2,0.3,0.4]) AS distance
FROM lance_catalog.default.items
WHERE category = 'book'
ORDER BY distance ASC LIMIT 10 OFFSET 5;

SELECT id, cosine_similarity_approximate(embedding, [0.1,0.2,0.3,0.4]) AS similarity
FROM lance_catalog.default.items
ORDER BY similarity DESC LIMIT 10;

SELECT id, hamming_distance_approximate(binary_embedding, [0,255,170]) AS distance
FROM lance_catalog.default.items
ORDER BY distance ASC LIMIT 10;

SELECT id, score() AS relevance
FROM lance_catalog.default.items
WHERE content MATCH_ALL 'storage engine' AND category = 'book'
ORDER BY relevance DESC LIMIT 10;

最初のクエリは、候補を絞り込む前に category = 'book' に一致する範囲を検索します。各 split は offset をゼロとして 15 件の候補を要求し、Doris が候補をマージして最終的な OFFSET 5 LIMIT 10 を適用します。ほかのクエリは、それぞれの並び順で近傍または BM25 の一致結果を最大 10 件返します。インデックスを使用した検索は近似的な場合があり、要求した件数より少ない行が返ることがあります。互換性のある既存インデックスは再利用され、インデックスでカバーされないデータには既存の Flat Search パスが使用されます。BM25 には既存の FTS インデックスが必要です。

適用条件とフォールバック​

  • クエリには、Lance Catalog テーブルの直接スキャン、省略可能なフィルタ、射影、および検索用の並び替えキーを一つだけ持つ、正の LIMIT を指定した Top-N が必要です。JOIN/EXISTS、二次ソートキー、DISTINCT、テーブルサンプリング、移動できない射影式があると、この書き換えは適用されません。
  • 浮動小数点メトリックには、物理型が Float32 の固定長リストベクトルが必要です。Hamming には、物理型が UInt8 の固定長リストベクトルが必要です。クエリベクトルは次元が一致する定数配列でなければなりません。Float16/Float64、マルチベクトル列、要素の値を任意に変えるキャストは自動書き換えの対象外です。UInt8 は Doris では SMALLINT として公開され、Hamming 関数の BIGINT 引数への拡張は安全です。
  • サポート対象外の残余述語、逆向きの検索順序、ネイティブメタデータの欠落、またはネイティブのベクトル・スキーマ検証による拒否があるベクトルクエリでは、スカラー評価が維持されます。書き換えを行うには、LIMIT + OFFSET がネイティブの UINT32 候補数の上限に収まる必要があります。この上限は通常のスカラー SQL を制限しません。
  • BM25 には、直接参照する文字列列に対するサポート対象の最上位 MATCH 述語を一つ、リテラルのクエリ、インデックスに保存されたアナライザー、および降順の score() が必要です。残りのスカラー述語はすべてプッシュダウン可能でなければなりません。score() > literal と score() >= literal は残余の下限条件としてサポートされます。上限条件やその他のスコア述語は拒否されます。サポート対象外のスコア付きクエリの形では、score() を暗黙にスカラー評価する代わりにエラーが報告されます。
  • スコアは Lance に保存されたアナライザーとインデックス、およびスナップショット全体の統計から得られます。別途インデックスを構築した Doris 内部テーブルのスコアと数値が一致するとは限りません。ファジー検索、アナライザーの上書き、複数列の SEARCH() 式は、この書き換えでは有効になりません。サポートされるマルチベクトルクエリや、nprobes、refine_factor、ef などの調整には、明示的な TVF を使用してください。

ネイティブの近似検索セマンティクス​

_approximate 接尾辞を使うと、条件を満たす Top-N クエリでネイティブの Lance 候補選択セマンティクスが選択されます。書き換えが行われない場合、関数はスカラーカーネルとして実行されます。網羅的なランキングや、保存されたすべての行に対するスカラー検証が必要な場合は、近似関数を使用しないでください。

入力スカラー評価対象となるネイティブ検索
保存された NULL ベクトルエラー候補から除外されます。
NaN 距離を生じる保存済みベクトルNaN を返す場合があります除外されるため、返される行数が少なくなる場合があります。
NULL のベクトル要素エラーサポートされるネイティブ入力の範囲外です。要素に NULL が含まれないようにしてください。
保存されたノルムがゼロのコサインベクトル距離 2、類似度 0未定義または NaN のネイティブ距離を生じる場合は除外されます。
ノルムがゼロまたは有限でないコサインのクエリベクトル。Float32 で計算したノルムの二乗のオーバーフロー・アンダーフローを含むスカラー関数の動作自動書き換えがスキップされます。
Hamming 入力各要素が [0,255] の範囲にある整数配列物理型が UInt8 のベクトルと、有効なバイト値のクエリが必要です。

コサインのネイティブ演算やインデックスによる推定値は、スカラー関数の結果と異なる場合があります。Hamming が数えるのは値が異なるバイトの数ではなく、異なるビットの数です。hamming_distance([0,255,170], [255,0,85]) は 24 を返します。Hamming は、暗黙のキャスト前に浮動小数点、decimal、LARGEINT の配列を拒否し、バイト値への変換前に範囲外の値を拒否します。厳密な関数は引き続きスカラー実行に使用できます。

WHERE プレフィルタと JOIN の境界​

Lance テーブルに対して完全にプッシュダウン可能な述語は、検索前に、同じ固定されたスナップショットに対して評価されます。Doris はまず行 ID のみを読み取るスキャンを試み、完成した許可リストをクエリ内の検索リーダー間で共有します。空のリストは、選択される行がないことを示します。ID が 65,536 件を超えると、Doris は部分的なリストを破棄し、完全なネイティブ述語によるプレフィルタを維持します。一時的なリストとキャッシュされたリストの容量は、どちらもクエリのメモリ制限に算入されます。停止または失敗した収集結果はキャッシュされません。これは、通常のスキャンに対する JOIN Runtime Filter のプッシュダウンとは別の仕組みです。

この ACL の例では、internal.auth.allowed_items に item_id と principal_id があるとします。

SELECT d.id,
l2_distance_approximate(d.embedding, [0.1,0.2,0.3,0.4]) AS distance
FROM lance_catalog.default.items d
WHERE EXISTS (
SELECT 1 FROM internal.auth.allowed_items a
WHERE a.item_id = d.id AND a.principal_id = 42
)
ORDER BY distance ASC
LIMIT 10;

このクエリでは、JOIN、スカラー距離評価、およびグローバル Top-N が維持されます。書き換えは ACL のセミ JOIN を越えず、業務上の ID を Lance のネイティブな _rowid に対応付けることもありません。ACL フィルタリングの前にフィルタなしの Top-K を選ぶと、権限のある行のうち最も近いものを見落とす可能性があります。二次ソートキーを追加した場合も、自動書き換えは行われません。

実際のクエリに EXPLAIN を使用し、externalSearchType=VECTOR と lanceMetric=l2|dot|cosine|hamming、または externalSearchType=FULL_TEXT を確認してください。LanceRowIdPrefilterTime、LanceRowIdPrefilterRows、LanceRowIdPrefilterCacheHits、LanceRowIdPrefilterFallbacks は、Doris による許可リスト処理を示します。これらは後述のネイティブな行 ID ローダーのメトリックとは異なります。検索の調整や、このルールの対象外でもサポートされるクエリの形には、明示的な TVF を使用してください。書き換えられた検索では、その適用条件を満たす場合、既存の二段階の出力読み取りを使用できます。

1. 候補のフィルタを検索の内側に配置する​

整数の id、文字列の category と content、および 4 次元ベクトルの embedding を含む設定済みテーブルでは、候補生成に反映すべき条件を TVF の filter パラメータに指定します。ベクトルインデックスは次元とメトリックが一致している必要があり、テキスト列にはコミット済みの FTS インデックスが必要です。

SELECT id, _distance
FROM vector_search(
"table" = "lance_catalog.default.items",
"column" = "embedding",
"query_vector" = "[0.1,0.2,0.3,0.4]",
"metric" = "l2",
"top_k" = "20",
"filter" = "category = 'book'",
"use_index" = "true"
)
ORDER BY _distance ASC, id;

これは、一致する行の中から最大 20 件の近傍を検索します。近似検索であるため、20 行が返っても再現率が保証されるわけではありません。フィルタ付き全文検索の場合は次のようにします。

SELECT id, _score
FROM full_text_search(
"table" = "lance_catalog.default.items",
"column" = "content",
"query" = "storage engine",
"query_type" = "match",
"operator" = "and",
"top_k" = "20",
"filter" = "category = 'book'",
"coverage_mode" = "strict"
)
ORDER BY _score DESC, id;

これは、一致するドキュメントを BM25 の順位順に最大 20 件返します。外側の WHERE category = 'book' は異なるセマンティクスを持ちます。Doris は、Lance が候補を生成した後、グローバル TopN の前に候補をフィルタリングします。除外された候補が自動的に補充されることはありません。EXPLAIN で条件が Doris の Scan オペレーター内に表示される場合でも、TVF の外側には検索後の適用を意図した条件だけを置いてください。

2. 並列処理の単位を理解する​

Query snapshot
-> FE plans physical search-index segment splits
-> Each split: scalar Prefilter -> vector or full-text candidates
-> Doris residual filtering -> local TopN -> global TopN
-> Optional deferred fetch of output columns
クエリのパスsplit の基準影響
インデックスを使用したベクトル検索選択された物理ベクトルインデックスセグメント。カバーされないフラグメントには Flat Search の split を割り当てますスカラーインデックスセグメントの数だけでベクトルクエリの split 数は決まりません。インデックスのないデータがレイテンシの主因になる場合があります。
全文検索選択された物理 FTS インデックスセグメントデフォルトの strict カバレッジでは、カバーされないフラグメントがあると拒否されます。index_only ではそれらが省略されます。全文検索に Flat Search のフォールバックはありません。
通常のスカラースキャンスカラーインデックスセグメントやフラグメントグループを使う可能性がある、独自のスキャン計画スカラーのみのクエリプランから、フィルタ付きベクトルクエリの並列度を推測しないでください。

lance_fragments_per_split が制御するのは通常のフラグメントスキャンのグループ化であり、物理ベクトルインデックスセグメントの数ではありません。パイプラインインスタンスやスキャナーの同時実行数を増やしても、プランナーが生成した数を超えるベクトルセグメントの split は作れません。Lance スキャナーの内部でも処理が並列に実行される場合があるため、Doris のスキャナー一つが CPU スレッド一つに相当するわけではありません。

検索 split が S 個ある場合、それぞれが返せる候補は最大 top_k + offset 件です。したがって、残余フィルタリングとグローバル TopN の前にマージされる候補数の上限は S * (top_k + offset) です。セグメントを増やすと処理を分散しやすくなる一方で、セグメントごとの準備、フィルタリング、候補のマージ、および同時使用するメモリの負担が増えます。

3. セグメント数ではなくフラグメントのカバレッジを揃える​

フラグメントはデータの単位です。インデックスセグメントは、フラグメントの集合をカバーする自己完結したインデックスです。論理インデックスは、一つのインデックス名の下に物理セグメントをまとめます。IVF パーティション、BTree ページ、FTS の posting block はインデックス内部の単位であり、いずれも Doris の検索 split を定義しません。

次の例では、8 個のデータフラグメントを使用します。

レイアウトベクトルのカバレッジスカラーのカバレッジフラグメント単位のスカラーリーダーにおけるフィルタリングへの影響
揃っているV0={0,1,2,3}, V1={4,5,6,7}B0={0,1,2,3}, B1={4,5,6,7}各ベクトル split に必要なのは、対応するスカラーセグメントだけです。
スカラー側が細かい上記と同じフラグメントごとに一つずつ、8 個のセグメント各 split は四つのスカラーセグメントを選びます。ベクトル側の境界をまたぐものはありません。
スカラー側が粗い上記と同じB0={0,1,2,3,4,5,6,7}両方のベクトル split が同じスカラーセグメントを照会する場合があります。
数は同じだが境界をまたぐ上記と同じB0={0,1,4,5}, B1={2,3,6,7}両方のスカラーセグメントが両方のベクトル split と重なります。数が同じでも、カバレッジが揃うとは限りません。

フラグメント単位の枝刈りでは、重なりのないスカラーセグメントがスキップされます。一部でも重なれば、そのセグメントは残されます。述語を評価する前に、より小さい BTree を自動的に再構築したり、すべての posting list を切り分けたりするわけではありません。繰り返し実行されるクエリでは、キャッシュされたインデックスの内容を再利用できても、検索や行 ID 集合の構築は繰り返される場合があります。残されたセグメントでも、BTree の検索が必ず全ページを走査するわけではありません。コストは述語と一致結果によって異なります。

important

この利点は、実際に使われるリーダーのパスに依存します。フラグメント単位でスカラーインデックスを読み込む Lance の V2 filtered-read パスでは、無関係なスカラーセグメントを検索前に除外できます。従来の V1 データファイルのパスでは、論理スカラーインデックスをより広い範囲で評価してから行 ID を絞り込む場合があります。ここでの V1/V2 は データファイル形式 を指し、Doris のリリースやベクトルインデックスの種類を指すものではありません。すべてのリーダーバージョンや FTS パスで同じ枝刈りが行われると想定せず、クエリの種類ごとにプランとプロファイルを確認してください。

組み合わせて使うことが多い列では、ベクトル、スカラー、FTS のインデックス構築に同じフラグメントグループを使用してください。スカラーセグメントは、それが対象とする検索セグメントの内側に収まるなら、より細かくしてもかまいません。ベクトルと FTS のセグメントで異なるサイズが必要な場合は、共通の基本グループをそれぞれまとめる方法を検討し、両方の境界をまたがないようにスカラーセグメントを配置してください。これは重なりの可能性を減らすためのレイアウト方針であり、すべての実行パスがその利点を活用する保証ではありません。

最初に試す粒度を選ぶ​

セグメントあたりの行数やバイト数に、普遍的な最適値はありません。まずワークロードを処理できる BE の数を基準にし、再現率と目標同時実行数を固定したうえで、BE あたりバランスの取れた検索セグメントを一つ置く構成と、BE あたり少数のセグメントを置く構成を比較してください。これらは実験の出発点であり、必須の比率ではありません。

ワークロード構築時の優先事項測定すべき主なトレードオフ
レイテンシが重要なフィルタ付きベクトル検索バランスの取れたベクトルグループと、その内側に収まるスカラーのカバレッジ最も遅い split と、繰り返されるフィルタリングや候補数の増加との関係
同時実行数の多い検索クエリあたりの split 数を増やしすぎず、再利用可能なパーティションを維持するQPS、P95 レイテンシ、CPU キュー、ピークメモリを合わせて評価する
対象範囲の広いスカラーフィルタや一般的な FTS 語句グループを均等にする際、一致件数、テキスト長、posting のサイズを考慮する行数が同じでも、フィルタリングや検索のコストは異なり得る
頻繁な追記新しい同一のフラグメントグループに対して、関連するすべてのインデックスを構築する新しいデータのカバレッジと、小さなセグメントの蓄積との関係
個々のフラグメントが非常に大きいインデックス構築前にデータファイルのサイズを計画するフラグメント単位のカバレッジでは、一つのフラグメントを複数の互いに重ならないカバレッジグループに分割できない

行数に加え、エンコードされたベクトルやグラフのサイズ、スカラー値の分布、テキストや posting のサイズを測定してください。各ベクトルセグメントで、その IVF/PQ 設定に十分な学習データを確保してください。nlist(IVF パーティション数)と物理セグメント数は別々に決める項目です。一方を変更しても、もう一方は自動的には調整されません。

4. 一つのグループ化計画から関連インデックスを構築する​

Doris には、列をまたいでインデックスを自動的に揃えるパラメータはありません。互換性のある SDK がサポートする場合は、Lance の分散構築 API を使用してください。以下は処理を調整するためのパターンであり、そのまま実行できるデータセット生成ツールやベンチマーク設定ではありません。

# ds is an existing LanceDataset at the chosen build snapshot.
# groups contains non-empty, disjoint lists of actual fragment IDs.
# vector_params and fts_params are validated for the schema and SDK version.
# Keep writes and compaction paused for this simple coordinator example.
visible = {fragment.fragment_id for fragment in ds.get_fragments()}
assigned = [fragment_id for group in groups for fragment_id in group]
assert groups and all(groups)
assert len(assigned) == len(set(assigned))
assert set(assigned) == visible

specs = [
("embedding_idx", "embedding", "IVF_PQ", vector_params),
("category_idx", "category", "BTREE", {}),
("content_idx", "content", "INVERTED", fts_params),
]
segments = {name: [] for name, _, _, _ in specs}
for fragment_ids in groups:
for name, column, index_type, params in specs:
segment = ds.create_index_uncommitted(
column,
index_type,
name=name,
fragment_ids=fragment_ids,
**params,
)
segments[name].append(segment)

# These are three separate commits, not an atomic multi-index publication.
for name, column, _, _ in specs:
ds.commit_existing_index_segments(name, column, segments[name])

次のように入力を準備し、検証してください。

  1. 構築計画を固定する。 一つのスナップショットから実際のフラグメント ID を列挙します。ID が連続している必要はありません。行数と推定インデックスサイズに基づいてグループのバランスを取ります。関連するすべての列に、まったく同じグループを再利用します。分散ワーカーはすべて同じ構築バージョンを開く必要があります。
  2. 互換性のある設定を選ぶ。 IVF_PQ には、ベクトルの次元とサンプルサイズに適したメトリック、num_partitions、num_sub_vectors を指定します。一つの論理インデックス内では設定を一貫させてください。FTS ではアナライザーとトークナイザーの設定を揃え、フレーズ検索が必要な場合は with_position を有効にします。
  3. ベクトルモデルの構築方針を選ぶ。 サポートされる複数セグメントの構築では、セグメントごとに独立して学習できます。後で物理的なマージに共通モデルが必要になる場合は、同じ IVF セントロイドと PQ コードブックをワーカーに渡してください。独立して学習したセグメントを無条件にマージしたり、HNSW グラフがマージ後も維持されると想定したりせず、SDK がサポートする手順を確認してください。
  4. 構築してから公開する。 各構築処理は、固有の UUID を持つ物理セグメントを返します。成功した出力を集め、カバレッジと互換性を検証してから論理インデックスごとにコミットしてください。異なる列やワーカーの出力に同じ物理 UUID を割り当てないでください。この例は新しい論理インデックス名を前提とします。置き換え、再試行、失敗時のクリーンアップには別途コーディネーターの方針が必要です。
  5. 生成されたマニフェストを検証する。 各インデックスについて、実際のセグメントとフラグメントの対応範囲を計画したグループと比較し、欠落や重複がないか確認します。セグメント数が一致するだけでは不十分です。Lance のインデックスメタデータを使用してください。Filesystem Catalog テーブルに対する Doris の SHOW INDEX は論理インデックス名、種類、フィールドの確認に役立ちますが、このカバレッジ監査の代わりにはなりません。

グループ化計画を共有するために、すべてのワーカーの出力を一つのセグメントにマージする必要はありません。そのようなマージをすると、維持したい境界が失われます。構築・コミット API とサポートされるマージ手順については、Lance Distributed Indexing を参照してください。

保守中も配置を揃える​

  • 同じ新しいフラグメントグループを使って、関連するベクトル、スカラー、FTS のセグメントを追記します。公開のたびに、クエリのスナップショットにおけるカバレッジを確認してください。データの追記からインデックス公開の完了までの間は、FTS の strict モードでクエリが拒否される場合があります。
  • コンパクション、書き換え、インデックス最適化はレイアウト変更として扱ってください。操作やリーダーバージョンによって、インデックスが再マッピングまたは再構築される場合があります。以前の境界が残ると想定せず、変更後のカバレッジを調べてください。
  • 一つのレイアウト計画に従って小さなグループをまとめます。混合クエリの性能が配置の整合性に依存する場合は、各インデックスを個別に最適化して無関係なグループにしないでください。
  • オンライン保守には、スナップショットと競合の処理、および復旧に対応するコーディネーターを使用してください。インデックスごとの個別のコミットでは、すべての列を一括で切り替えることはできません。TVF は最新の main スナップショットを読み取ります。TVF の table 引数では、過去のバージョンやタグを選択できません。

論理インデックスとアップストリームの計画​

Lance の インデックス形式 では、論理インデックスと物理セグメントが定義されています。分散インデックスに関する追跡 issue では、インデックス種別間で共有されるセグメントのライフサイクルが追跡されています。このモデルは、異なる列に同一のフラグメント境界を 強制しません。列をまたぐグループ化と保守は、引き続きオーケストレーション側の責任です。アップストリームのロードマップを、Doris の自動配置機能として扱わないでください。

5. フィルタとメモリを併せて調整する​

観察された状況次に試すこと正しさまたはリソース上の制約
選択性が非常に高いフィルタで、ベクトルの結果が少なすぎる、または再現率が低いフィルタの配置とインデックスのカバレッジを確認し、範囲を限定したデータセットで probe の設定と厳密検索の基準結果を比較するレイテンシを下げるために probe を減らすと、再現率が低下する場合があります。probe を増やしても、フィルタに一致しない行は候補になりません。
対象範囲の広いフィルタで大きな Prefilter 集合が生成される配置を揃えたレイアウトと、スカラー述語の実際の選択性を比較するインデックスを使用しても、一致する行 ID を多数具体化するコストはなくなりません。
ベクトル split 数の増加に伴いスカラー処理が繰り返されるセグメントのカバレッジの重なりとリーダーのパスを比較するキャッシュが温まっていても、split を増やすとフィルタリングが増幅される場合があります。
コールドクエリが遅い代表的なベクトルと語句を使って、コールド時とウォーム時のプロファイルを比較する一つのクエリのウォームアップでは、本番環境で使用されるデータ全体はカバーされません。
ウォーム状態の混合トラフィックが遅くなる目標同時実行数で、共有キャッシュのミスと CPU キューを測定するスカラー、ベクトル、FTS のインデックス内容が、BE 上で同じセッションのインデックスキャッシュ容量を奪い合う場合があります。
大きな top_k、深い offset、または幅の広い出力セマンティクスが許す範囲で要求する候補数を減らし、遅延フェッチを調べる候補ヒープ、行 ID マスク、精緻化処理、フェッチバッファもクエリメモリを消費します。

再利用されるインデックスの 合計 ワーキングセットに合わせて容量を設定し、同時実行されるクエリのメモリ用に余裕を残してください。キャッシュ容量はプロセスメモリの上限ではなく、メタデータキャッシュを増やしてもインデックスキャッシュは増えません。インデックスごとのペイロード計算式、HNSW グラフのコスト、キャッシュの適用範囲、Doris BE の設定例については、Lance Query Best Practices を参照してください。

6. プランとプロファイルで検証する​

同じクエリ群、データセットのスナップショット、インデックスの種類と設定、top_k、再現率の目標を使って比較します。変更するレイアウトまたはパラメータは一度に一つにしてください。選択性が高いフィルタと対象範囲の広いフィルタ、多様なベクトルと語句、コールド時とウォーム時の実行、想定する同時実行数を含めます。P50/P95、スループット、結果件数、再現率、BE ごとのピークメモリを記録してください。

段階確認する情報解釈
FE のメタデータと計画Execution Summary → Lance Metadata Metrics:MetadataReadTime、IndexMetadataReadTime、SplitPlanningTime と、それぞれに対応する CallsCatalog のメタデータアクセスと split の計画を、BE の検索から分けて確認します。メタデータの合計時間には各内訳が含まれます。
計画とカバレッジEXPLAIN:lanceSearchIndexSegments、lanceSearchIndexFragments、lanceSearchUnindexedFragments。LanceSearchPlan:LancePlannedIndexSegmentCount、LancePlannedIndexedFragmentCount、LancePlannedFlatSearchFragmentCount計画・割り当てられた検索処理を示すもので、完了した検索ではありません。Flat Search の件数はベクトルクエリに適用され、FTS には適用されません。
リーダーの準備とバッチ読み取りLanceTiming:LanceDatasetOpenTime、LanceScannerConfigureTime、LanceScannerNextTime、LanceArrowToDorisBlockTimeオープンと設定、Lance の読み取り、Doris への変換を区別します。バッチ読み取り時間には、内部検索、I/O、デコード、待機が含まれます。
行 ID PrefilterLanceScan:RowIdPrefilterLoads、RowIdPrefilterInputRows、RowIdPrefilterInputBatches、RowIdPrefilterIds、RowIdPrefilterLoadTime、RowIdPrefilterInputTime、RowIdPrefilterBuildTime入力の待機・読み取りとマスク構築は、総ロード時間の内訳です。これらは行 ID ローダーについて示すもので、すべてのスカラー述語や最終的な候補集合を示すものではありません。
スカラーセグメントのパスLanceScalarIndex:LanceScalarIndexSegmentsRequested、LanceScalarIndexSegmentsSearched、LanceScalarIndexSegmentFallbacks、LanceScalarIndexCandidateRows、LanceScalarIndexCandidateEvaluationTime、LanceScalarIndexSegmentSearchTime候補評価にはセグメント検索が含まれます。候補数はフラグメントによる制限と完全なフィルタリングより前の値です。処理が繰り返されると候補が再度数えられる場合があり、カーディナリティを取得できないとゼロのままになる場合もあります。
インデックスの再利用と I/OLanceIndex:LanceIndexCacheHits、LanceIndexCacheMisses、LanceIndexObjectLoads、LanceIndexComponentsLoaded、LanceIndexComparisons。LanceIO:LanceIOReadBytes、LanceIOReadOps、LanceIOReadRequestsオブジェクトやコンポーネントのロード、キャッシュの参照、検索処理を区別します。ロード回数はミス回数ではなく、実行時の I/O はリモート通信量の全体を表すものではありません。
ベクトルパーティションの選択と検索LanceIVFPartitionsConsidered、LanceIVFPartitionSelectionTime、LanceIndexPartitionsSearched、LanceVectorIndexDeltasSearched、LanceIndexPartitionLoadTime、LanceIndexSearchTime、LanceIndexDistanceTopKTimeパーティションの選択と実際の検索を区別します。距離計算と Top-K の時間にはフィルタリングとヒープ処理が含まれ、検索時間と重複します。FTS でも検索したパーティション数が報告されます。
待機と同時実行LanceIndexPrefilterWaitTime、LanceIndexCpuQueueWaitTime、LanceScanTaskWaitTimeインデックスの Prefilter の待機、CPU タスクキューの待機、FilteredRead タスクの待機を区別します。いずれも I/O 待機時間や Doris のスケジューリング時間の全体ではありません。
出力のフェッチ行 ID の Fetch/Materialization 情報:LanceRowIdFetchCalls、LanceRowIdFetchRows、LanceRowIdFetchTotalTime、LanceRowIdTakeReadTime、LanceArrowToDorisBlockTime、およびデータキャッシュのバイト数カウンターフェッチの合計には読み取りと変換の内訳が含まれ、別の統計パスを使用します。エクスポートされた同じ値を、独立した処理として再度加算しないでください。
クエリ全体のレイテンシ最も遅い Scanner、依存関係の待機、FE の wait/fetch/write、およびクライアント側の経過時間重複するオペレーターの時間や、並列に動くすべての Scanner の時間を足し合わせてクエリのレイテンシとしないでください。

メトリックの定義と適用範囲については Lance Query Profile のリファレンス を、Dataset のデータキャッシュのバイト数と BE 全体の Session メトリックについては キャッシュの有効性の確認 を参照してください。クエリ単位のインデックスキャッシュカウンターは、Session の合計値の差分ではありません。

プロファイルの詳細は、実行中の FE/BE と同梱の Lance インストルメンテーションに依存します。Scanner のメトリックは事前登録されているため、ゼロはネイティブパスがそのメトリックを報告しなかったことを意味する場合があります。実行時のコールバックにはストリームの完了も必要です。そのため、失敗、キャンセル、早期終了したスキャンでは、件数が不完全な場合があります。値の欠落やゼロだけで、インデックスやフィルタが使われなかったと断定しないでください。LanceScannerNextTime は内部検索や待機のタイマーと重複します。この値が大きいだけでは、ストレージがボトルネックであるとはいえません。これらのメトリックで読み取り時間を説明できない場合は、残りの時間をストレージに起因すると判断する前に CPU/I/O のトレースを収集してください。

フィルタなしのベクトルクエリでは、セグメント単位の最適化を備えたリーダーは、選択したインデックスセグメントがスキャン対象のフラグメント範囲に完全に含まれる場合、すべての行 ID の列挙を省略できます。実際のスカラー述語は引き続き評価する必要があり、削除や可視性の処理も残る場合があります。配置を揃えることで回避可能な処理は減らせますが、フィルタ付き検索で Prefilter のコストがゼロになるとは限りません。