api-vector-db-qdrant について
Qdrant の JavaScript クライアントでベクトル検索を行う開発者向けのスキルガイドです。コレクション設定、ペイロードフィルター、名前付きベクトル、推薦検索、量子化を扱います。
主な機能
- 01コレクションとベクトルの設定
- 02ポイントの登録、検索、削除
- 03ペイロードフィルターとインデックス
- 04ポイントごとの複数の名前付きベクトル
- 05推薦クエリ
- 06量子化オプション
活用シーン
- 01文書のセマンティック検索を構築
- 02メタデータで類似検索を絞り込み
- 03正例と負例から推薦を生成
- 04量子化でベクトルのメモリ使用量を削減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-vector-db-qdrantインストール後、Claude Code で/api-vector-db-qdrantを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/core.mdfiltering.mdnamed-vectors-quantization.mdrecommendations-batch.md詳細
Qdrant パターン
クイックガイド: 高性能なベクトル検索には
@qdrant/js-client-rest(v1.17.x)を使用します。コレクションでは、ベクトルの次元数と距離メトリクスをあらかじめ定義します。不一致があると、エラーが表面化しないまま失敗します。ペイロード条件を使ったmust/should/must_notフィルター句を使用します(Pinecone 形式の$eq/$andは使いません)。ペイロードインデックスは任意ですが、大規模環境でのフィルター性能に不可欠です。createPayloadIndex()で明示的に作成します。名前付きベクトルを使うと、1つのポイントに複数の埋め込み(例:タイトルと本文)を保存できます。量子化(スカラー/バイナリ/プロダクト)は、精度と引き換えにメモリ使用量と速度を改善します。query()メソッドは汎用検索エンドポイントです。旧式のsearch()メソッドよりもこちらを優先してください。
<critical_requirements>
重要:このスキルを使用する前に
(フィルターで使用するすべてのフィールドに対し、createPayloadIndex() でペイロードインデックスを作成する必要があります。インデックスのないフィールドは全件走査を引き起こし、コレクションのサイズに比例して性能が低下します)
(must/should/must_not のフィルター構文を使用する必要があります。Qdrant では、Pinecone のような $eq/$and/$or 演算子は使用しません)
(埋め込みモデルの出力とコレクション設定のベクトル次元数を完全に一致させる必要があります。次元数が一致しないと、エラーが表面化しないままアップサートに失敗したり、検索結果が破損したりします)
(後続の読み取りでデータが必要な場合は、書き込み時に wait: true を設定する必要があります。Qdrant の書き込みはデフォルトで非同期のため、直ちに参照できるとは限りません)
</critical_requirements>
例
- コアパターン -- クライアントのセットアップ、コレクションの作成、アップサート、クエリ、スクロール、削除
- フィルタリング -- must/should/must_not 条件、match/range 演算子、ペイロードインデックス
- 名前付きベクトルと量子化 -- 1つのポイントあたりの複数ベクトル、スカラー/バイナリ/プロダクト量子化
- レコメンデーションとバッチ処理 -- Recommend API、バッチ操作、スナップショット
追加リソース:
- reference.md -- API クイックリファレンス、フィルター演算子、制限、判断フレームワーク、本番環境チェックリスト
自動検出: Qdrant、QdrantClient、@qdrant/js-client-rest、createCollection、upsert、query、scroll、recommend、setPayload、createPayloadIndex、must、should、must_not、ペイロード、名前付きベクトル、量子化、ベクトルデータベース、類似検索、セマンティック検索、RAG 検索、埋め込み検索
使用する場面:
- ドキュメントの埋め込みを使ったセマンティック検索(RAG 検索パイプライン)
- レコメンデーション、重複排除、分類のための類似検索
- 名前付きベクトルを使ったマルチベクトル検索(例:ドキュメントごとのタイトル埋め込みと本文埋め込み)
- 複雑なペイロード条件(must/should/must_not)によるフィルター付きベクトル検索
- スカラー、バイナリ、またはプロダクト量子化を使ったメモリ最適化デプロイ
対象となる主なパターン:
- クライアントのセットアップとコレクション管理(距離メトリクス、HNSW 設定)
- ポイントの CRUD 操作(アップサート、クエリ、スクロール、取得、削除、件数取得)
- must/should/must_not および match/range 条件によるペイロードフィルタリング
- 1つのポイントに複数の埋め込みを格納する名前付きベクトル
- 量子化設定(スカラー、バイナリ、プロダクト)
- 正例/負例を使ったレコメンデーション API
- バッチ操作とスナップショット管理
- フィルター性能向上のためのペイロードインデックス作成
使用しない場面:
- BM25 ランキングによる全文検索(専用の検索エンジンを使用してください)
- 結合やトランザクションを伴うリレーショナルデータ(リレーショナルデータベースを使用してください)
- ベクトル類似性を使わないキー値検索(KV ストアを使用してください)
- 大きなドキュメントやバイナリ BLOB の保存(埋め込みとメタデータ参照のみを保存してください)
## 基本理念
Qdrant は Rust で構築された高性能なオープンソースのベクトルデータベースで、大規模環境でのフィルター付き類似検索を目的に設計されています。基本原則は、リッチなペイロードとともにベクトルを保存し、類似度で検索し、ペイロード条件でフィルタリングすることです。
基本原則:
- ペイロードを第一級の要素として扱う -- メタデータを二次的に扱うデータベースとは異なり、Qdrant のペイロードシステムは複雑なネストされた JSON、複数のデータ型、きめ細かなインデックス作成に対応しています。ペイロードは単なる注釈ではなく、フィルタリングに使用してください。
- フィルタリングするフィールドにインデックスを作成する -- ペイロードインデックスは自動では作成されません。
createPayloadIndex()を使用して、フィルターで使用するフィールドに明示的にインデックスを作成してください。インデックスがない場合、フィルターによってコレクション全体がスキャンされます。 - マルチモーダルには名前付きベクトルを使う -- 1 つのポイントに複数の名前付きベクトル(例:タイトルの埋め込み+コンテンツの埋め込み)を格納できます。検索では特定の名前付きベクトルを対象にします。これにより、コレクション間でペイロードを重複させずに済みます。
- 大規模利用には量子化を使う -- スカラー(4 倍圧縮)、バイナリ(32 倍)、積量子化は、精度とメモリ削減のトレードオフです。コレクション単位またはベクトル単位で設定できます。速度を高めるには、
always_ram: trueを設定して量子化されたベクトルをメモリに保持します。 - 書き込みはデフォルトで非同期 -- アップサートは、すべてのレプリカにデータが永続化される前に返されます。即時の整合性が重要な場合(例:書き込み後の読み取りフロー)は、
wait: trueを設定してください。
基本パターン
パターン 1:クライアントの初期化
ローカルインスタンスまたは Qdrant Cloud に接続する QdrantClient を作成します。詳しい例については、examples/core.md を参照してください。
// Good Example
import { QdrantClient } from "@qdrant/js-client-rest";
function createQdrantClient(): QdrantClient {
const url = process.env.QDRANT_URL;
const apiKey = process.env.QDRANT_API_KEY;
if (!url) {
throw new Error("QDRANT_URL environment variable is required");
}
return new QdrantClient({ url, apiKey });
}
export { createQdrantClient };
良い点: URL と API キーを環境変数から取得し、構築前に検証し、名前付きエクスポートを使用しています
// Bad Example
import { QdrantClient } from "@qdrant/js-client-rest";
const client = new QdrantClient({
host: "my-cluster.cloud.qdrant.io",
apiKey: "sk-abc123...",
});
// Hardcoded credentials leak in version control
悪い点: API キーがハードコードされており、ホストに HTTPS が使われていません(クラウドでは、プロトコルを含む完全な URL を url に指定してください)
パターン 2:コレクションの作成
ベクトルの次元と距離メトリックを定義します。次元は、埋め込みモデルの出力と完全に一致する必要があります。examples/core.md を参照してください。
// Good Example
const EMBEDDING_DIMENSION = 1536;
await client.createCollection("documents", {
vectors: {
size: EMBEDDING_DIMENSION,
distance: "Cosine",
},
});
export { EMBEDDING_DIMENSION };
良い点: 次元に名前付き定数を使用し、距離メトリックを明示し、設定が整理されています
// Bad Example
await client.createCollection("documents", {
vectors: { size: 768, distance: "Cosine" },
// Dimension mismatch if using a 1536-dim model -- upserts may silently fail or produce garbage search results
});
悪い点: 埋め込みモデルと一致しない可能性のある次元がハードコードされ、名前付き定数もありません
パターン 3:ペイロードを付けてポイントをアップサートする
ペイロード(Qdrant でのメタデータの呼称)とともにベクトルをアップサートします。examples/core.md を参照してください。
// Good Example
interface DocumentPayload {
title: string;
category: string;
createdAt: number;
tags: string[];
}
await client.upsert("documents", {
wait: true,
points: [
{
id: "doc-1",
vector: embedding,
payload: {
title: "Guide",
category: "tutorial",
createdAt: 1710000000,
tags: ["ai", "search"],
},
},
],
});
良い点: 型付きペイロードインターフェースを使い、即時の整合性のために wait: true を設定し、構造化されたペイロードを使用しています
パターン 4:ペイロードフィルターを使ったクエリ
must/should/must_not のフィルター句を使用します。Pinecone 形式の $eq/$and ではありません。examples/filtering.md を参照してください。
// Good Example
const TOP_K = 10;
const results = await client.query("documents", {
query: queryEmbedding,
filter: {
must: [
{ key: "category", match: { value: "tutorial" } },
{ key: "createdAt", range: { gte: 1700000000 } },
],
},
with_payload: true,
limit: TOP_K,
});
for (const point of results.points) {
console.log(point.id, point.score, point.payload);
}
良い点: limit に名前付き定数を使用し、Qdrant のフィルター構文(must と match/range)を使い、with_payload を含めています
// Bad Example -- Pinecone syntax does NOT work in Qdrant
const results = await client.query("documents", {
query: embedding,
filter: {
$and: [{ category: { $eq: "tutorial" } }],
},
limit: 100,
});
悪い点: Pinecone 形式の $and/$eq 演算子は Qdrant では無効で、limit にマジックナンバーを使用しています
パターン 5:名前付きベクトル
1 つのポイントに複数の埋め込みを保存します。examples/named-vectors-quantization.md を参照してください。
// Good Example
const TITLE_DIM = 384;
const CONTENT_DIM = 1536;
await client.createCollection("articles", {
vectors: {
title: { size: TITLE_DIM, distance: "Cosine" },
content: { size: CONTENT_DIM, distance: "Cosine" },
},
});
// Upsert with named vectors
await client.upsert("articles", {
wait: true,
points: [
{
id: "article-1",
vector: { title: titleEmbedding, content: contentEmbedding },
payload: { title: "Intro to Vectors" },
},
],
});
// Search by specific named vector
const results = await client.query("articles", {
query: queryEmbedding,
using: "content",
limit: TOP_K,
});
良い点: 名前付きベクトルごとに異なる次元を使用し、検索対象のベクトルを using で指定し、コレクション間でペイロードが重複するのを防いでいます
パターン 6:レコメンデーション API
肯定例と否定例を使って類似するポイントを検索します。examples/recommendations-batch.md を参照してください。
// Good Example
const results = await client.query("documents", {
query: {
recommend: {
positive: [1, 42],
negative: [7],
strategy: "best_score",
},
},
limit: TOP_K,
with_payload: true,
});
良い点: ポイント ID を肯定例/否定例として使用し、best_score 戦略によって、デフォルトの average_vector よりも否定例を適切に処理しています
<decision_framework>
選択の指針
距離メトリックの選び方
Which distance metric should I use?
|-- Using normalized embeddings (OpenAI, Cohere)? -> Cosine (most common, safe default)
|-- Pre-normalized embeddings and need speed? -> Dot (faster, same results as Cosine for unit vectors)
|-- Raw feature vectors where magnitude matters? -> Euclid (L2 distance)
|-- City-block distance needed? -> Manhattan
'-- Unsure? -> Cosine (works with any embedding model)
単一ベクトルと名前付きベクトルのどちらを選ぶか
How many embeddings per point?
|-- One embedding model? -> Single vector (simpler config)
|-- Multiple embedding models (title + content)? -> Named vectors
|-- Same model, different text segments? -> Named vectors
|-- Multi-modal (text + image)? -> Named vectors with different dimensions
'-- Want to avoid duplicating payloads across collections? -> Named vectors
量子化方式の選び方
How should I optimize memory?
|-- Good default, balanced accuracy/speed? -> Scalar (int8, 4x compression)
|-- Maximum speed, can tolerate accuracy loss? -> Binary (32x compression)
| '-- Best with high-dimensional models (>= 1024 dims)
|-- Maximum compression, speed not critical? -> Product (up to 64x compression)
| '-- Slowest quantization, most accuracy loss
'-- No memory pressure? -> Skip quantization (full float32 precision)
ペイロードインデックスの方針
Should I create a payload index?
|-- Field used in filter conditions? -> YES, always index
|-- Field used in order_by for scroll? -> YES, index for sort performance
|-- Field only read after search (display only)? -> NO, skip index
|-- High-cardinality field (UUIDs, timestamps)? -> YES, but evaluate index type
'-- Low-cardinality field (enum-like)? -> YES, keyword index is very efficient
</decision_framework>
<red_flags>
要注意の問題
優先度の高い問題:
- Pinecone 形式のフィルター構文(
$eq、$and、$or)を使用している — Qdrant では、match/range条件とともにmust/should/must_notを使用します - 埋め込みモデルとコレクション設定のベクトル次元が一致していない — サイレントな失敗や不正な結果の原因になります
- フィルター対象フィールドにペイロードインデックスがない — コレクション全体のスキャンが発生し、サイズに比例して性能が低下します
- 読み取り直後の一貫性が必要なのに
wait: trueを設定していない — 書き込みはデフォルトで非同期です
優先度が中程度の問題:
query()ではなく非推奨のsearch()メソッドを使用している —query()は、プリフェッチとフュージョンに対応した汎用エンドポイントです- クエリで
with_payload: trueを指定し忘れている — ペイロードはデフォルトでは含まれません - 一括アップサートの後にペイロードインデックスを作成している — 既存データへのインデックス作成は、アップサート中に作成するよりも低速です
- スクロールで深いページネーションに
offsetを使用している — パフォーマンスが低下します。ページ番号ではなく、カーソル(ポイント ID)としてoffsetを使用してください
よくある間違い:
filterを誤った階層に渡している —filterはクエリー引数の最上位に指定します。別のオブジェクト内にネストしないでください- ポイント ID として
id: 0を使用している — Qdrant で使用できるのは正の整数または UUID 文字列です。0 は無効です setPayload(マージ)とoverwritePayload(置き換え)を混同している —setPayloadはフィールドをマージし、overwritePayloadはペイロード全体を置き換えます- ポイントセレクターを指定せずに、フィールド名だけで
deletePayloadを呼び出している —points配列またはfilterで、更新するポイントを指定する必要があります
注意点とエッジケース:
- ポイント ID には正の整数または UUID 文字列を指定する必要があります — 負の数、ゼロ、UUID ではない文字列は拒否されます
order_byを指定したscroll()には、ソートフィールドのペイロードインデックスが必要です — インデックスがない場合、リクエストは失敗します- 大規模なコレクションで
exact: trueを指定したcount()は低速です — 概算カウントにはexact: false(デフォルト)を使用してください - スナップショットの復元には、Qdrant のマイナーバージョンが一致している必要があります — v1.14.x のスナップショットを v1.15.x クラスターに復元することはできません
- バイナリ量子化は、高次元ベクトル(>= 1024 dims)で最も効果を発揮します — それより小さいベクトルでは、スカラー量子化のほうが高精度です
prefetchを指定したquery()を使うと、複数段階の検索(1000 件を取得し、その後上位 10 件に再ランク付け)が可能になります — ただし、プリフェッチのパイプラインを理解している必要があります- 名前付きベクトル検索には
usingパラメーターが必要です — 省略すると、存在しない可能性のあるデフォルトの(名前なし)ベクトルが検索されます deletePayloadは指定したキーを削除し、clearPayloadはすべてのキーを削除します — これらは異なる操作です
</red_flags>
<critical_reminders>
重要な注意事項
(フィルターで使用するフィールドには、必ず createPayloadIndex() でペイロードインデックスを作成してください。インデックスのないフィールドではコレクション全体のスキャンが発生し、コレクションのサイズに比例して性能が低下します)
(フィルター構文には必ず must/should/must_not を使用してください。Qdrant は Pinecone のような $eq/$and/$or 演算子を使用しません)
(埋め込みモデルの出力とコレクション設定のベクトル次元は、必ず正確に一致させてください。次元が一致しないと、サイレントなアップサートの失敗や検索結果の破損が発生します)
(後続の読み取りがデータに依存する書き込みでは、必ず wait: true を設定してください。Qdrant の書き込みはデフォルトで非同期のため、直後には反映されていない場合があります)
これらのルールに従わないと、検索結果が空になる、フィルターのパフォーマンスが低下する、データの一貫性が損なわれる、デバッグが困難な次元不一致エラーが発生するといった問題につながります。
</critical_reminders>