0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ベクトル検索の仕組みを初心者向けに — コサイン類似度まで整理する

0
Last updated at Posted at 2026-07-18

Vector search cosine similarity basics

RAGやセマンティック検索の解説では「ベクトル検索」という言葉が頻出するが、埋め込みで数値化したあと、実際にどうやって「近い文書」を見つけているのかが見えにくい。
この記事は、ベクトル検索の全体像と、代表的な類似度指標であるコサイン類似度を、初心者向けに整理する。

結論:ベクトル検索は「意味の近さで探す検索」

観点 内容
定義 テキストを埋め込みベクトルに変換し、クエリベクトルに近いベクトルを高速に探す検索方式
従来検索との違い キーワード一致ではなく、意味の類似性でヒットする
核心の計算 ベクトル間の距離・類似度(コサイン類似度が最もよく使われる)
典型用途 RAGの検索ステップ、FAQ検索、重複文書検出、レコメンド
覚え方 Googleのキーワード検索の「意味版」

ポイント:ベクトル検索は単体の魔法ではない。事前にドキュメントを埋め込み化してベクトルDBに保存し、検索時にクエリも同じモデルで埋め込む——この2段階がセットだ。

ベクトル検索とは何か

ベクトル検索(vector search / similarity search)とは、高次元ベクトル空間の中で、クエリに最も近いベクトルを探し出す処理だ。

従来の全文検索(キーワード検索)との違いを表にまとめる。

方式 マッチの基準 例:「退勤手順を教えて」
キーワード検索 単語の一致・出現頻度 「退勤」「手順」が含まれる文書をヒット
ベクトル検索 ベクトル空間上の距離 「業務終了時のチェックリスト」もヒットしうる

キーワードが完全一致しなくても、意味が近ければ検索結果に現れる。RAGで「ユーザーの自然文の質問」から関連ドキュメントを引くとき、この性質が重要になる。

ベクトル検索の流れ(全体像)

[インデックス構築(オフライン)]
  ドキュメント群
    → チャンク分割
    → 各チャンクを埋め込みモデルでベクトル化
    → ベクトルDBに保存(ベクトル + メタデータ + 元テキスト)

[検索(オンライン)]
  ユーザーの質問
    → 同じ埋め込みモデルでベクトル化
    → ベクトルDBで類似ベクトルを検索(Top-K)
    → 上位K件の元テキストを取得
    → LLMのコンテキストに渡す(RAGの場合)
フェーズ やること 注意点
インデックス構築 全チャンクをベクトル化して保存 モデルと次元数を記録しておく
検索 クエリベクトルと全ベクトルの類似度を計算 インデックス時と同じモデルを使う
結果の利用 上位K件をLLMに渡す 閾値以下は除外する設計も有効

類似度の計算:コサイン類似度を中心に

2つのベクトルが「どれだけ近いか」を数値化する指標を類似度メトリックという。ベクトル検索で最もよく使われるのが**コサイン類似度(cosine similarity)**だ。

コサイン類似度とは

コサイン類似度は、2つのベクトルがなす角度のコサイン値を取る指標だ。

cosine_similarity(A, B) = (A · B) / (|A| × |B|)

A · B  : ベクトルAとBの内積(各要素の積の総和)
|A|    : ベクトルAの長さ(ユークリッドノルム)

値の範囲は -1〜1 で、1に近いほど方向が一致=意味が近いと解釈する。

コサイン類似度 意味
1.0 完全に同じ方向(最も類似)
0.0 直交(無関係)
-1.0 正反対の方向

テキスト埋め込みでは、ほとんどの場合 0.5〜0.9 の範囲にスコアが分布する。閾値はデータセットごとに調整が必要だ。

なぜコサイン類似度がよく使われるのか

理由 説明
文の長さに頑健 ベクトルの「方向」だけを見るため、短い文と長い文の比較でも極端に不利になりにくい
計算が軽い 内積とノルムだけで求まる
業界標準 Pinecone、Weaviate、Qdrant、pgvector など主要ツールがデフォルトまたは推奨でサポート

他の距離指標との比較

指標 計算の考え方 向いているケース
コサイン類似度 ベクトルの角度 テキスト埋め込み全般(最も一般的)
ユークリッド距離(L2) 座標間の直線距離 画像埋め込みなど、ノルムが意味を持つ場合
内積(ドット積) 方向と長さの両方 正規化済みベクトルではコサインと等価
マンハッタン距離(L1) 各次元の差の絶対値の総和 スパースベクトル(TF-IDF等)のレガシー用途

多くの埋め込みモデルは出力ベクトルを正規化(長さを1に揃える)している。この場合、コサイン類似度と内積は同じ結果になる。

コサイン類似度の計算例(Python)

最小限の例で、3つの文の類似度を計算してみる。

import numpy as np

def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
  dot = np.dot(a, b)
  norm_a = np.linalg.norm(a)
  norm_b = np.linalg.norm(b)
  if norm_a == 0 or norm_b == 0:
    return 0.0
  return dot / (norm_a * norm_b)

# 架空の3次元ベクトル(実際は数百〜数千次元)
vec_cat   = np.array([0.8, 0.6, 0.1])   # 「猫はかわいい」
vec_kitten = np.array([0.75, 0.65, 0.05])  # 「ネコは愛らしい」
vec_stock  = np.array([0.1, 0.2, 0.95])  # 「株価は上昇した」

print(f"猫 vs ネコ:   {cosine_similarity(vec_cat, vec_kitten):.3f}")  # → 高い値
print(f"猫 vs 株価:   {cosine_similarity(vec_cat, vec_stock):.3f}")   # → 低い値

実務では sentence-transformers や各社の埋め込みAPIでベクトル化してから、同じ計算を行う。

from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")

texts = [
  "退勤時の手順を教えて",
  "業務終了時のチェックリスト",
  "有給休暇の申請方法",
]
embeddings = model.encode(texts)

# クエリ(0番)と各文書の類似度
query_vec = embeddings[0].reshape(1, -1)
for i, text in enumerate(texts):
  score = cosine_similarity(query_vec, embeddings[i].reshape(1, -1))[0][0]
  print(f"[{score:.3f}] {text}")

「退勤」と「業務終了」のペアは高スコア、「有給休暇」は低スコアになる傾向が見られるはずだ。

大量データでの高速検索(近似最近傍探索)

ドキュメントが数千件なら全件と類似度を計算しても問題ない。しかし数百万〜数億件になると、クエリごとに全件計算する**総当たり(brute-force / exact search)**は遅すぎる。

そこで使われるのが**近似最近傍探索(ANN: Approximate Nearest Neighbor)**だ。

方式 概要 代表例
総当たり(Exact) 全ベクトルと類似度を計算 小規模データ向け
HNSW グラフ構造で近傍を高速探索 pgvector、Qdrant、Weaviate
IVF クラスタに分割して探索範囲を絞る Faiss、Milvus
LSH ハッシュで近いベクトルを同じバケットに 大規模・許容誤差あり

ANNは「完全に正確なTop-K」ではなく「ほぼ正しいTop-K」を高速に返すトレードオフだ。RAGの実務では、99%以上のケースで十分な精度が出る。

ベクトルDBで検索するときの設定項目

主要なベクトルDBには、検索時に次のパラメータを指定する。

パラメータ 意味 典型値
top_k 返す件数 3〜10(RAGでは多めに取りリランキングも)
metric 類似度の種類 cosine(テキスト向け)
score_threshold 閾値以下を除外 0.7〜0.8(データセットで調整)
ef / nprobe ANNの精度と速度のトレードオフ DBのドキュメント参照

Pineconeの例(概念):

# 概念例:実際のSDKはバージョンで異なる
results = index.query(
  vector=query_embedding,
  top_k=5,
  include_metadata=True,
  # metric="cosine" はインデックス作成時に指定
)

pgvectorの例:

-- コサイン距離(1 - コサイン類似度)で近い順に取得
SELECT content, 1 - (embedding <=> query_embedding) AS similarity
FROM documents
ORDER BY embedding <=> query_embedding
LIMIT 5;

pgvectorでは <=> がコサイン距離演算子だ。距離が小さいほど類似度が高い。

実装チェックリスト

  • インデックス構築と検索で同じ埋め込みモデル・同じバージョンを使っているか確認する
  • ベクトルDBのmetric設定がコサイン類似度(または内積)になっているか確認する
  • top_k を決めたうえで、score_threshold で無関係な結果を除外する設計を検討する
  • テストクエリ10〜20件で、期待する文書が上位に来るか検索品質を評価する
  • データ量が増えたら ANN インデックス(HNSW 等)の構築を検討する
  • 検索結果のメタデータ(元ファイル名、ページ番号等)を保存し、出典表示に使えるようにする

失敗パターン

パターン1:metricの不一致
インデックス作成時にユークリッド距離、検索時にコサイン類似度を使うなど、設定が食い違う。
→ 対策:インデックス作成時の metric をドキュメント化し、検索コードと一致させる。

パターン2:閾値なしでtop_kの結果をすべてLLMに渡す
類似度0.3の無関係チャンクまでコンテキストに入り、回答品質が下がる。
→ 対策:コサイン類似度0.7以上(目安)のみ採用し、全件下回る場合は「関連情報なし」と返す。

パターン3:top_kが小さすぎてリランキング前に正解が落ちる
ANNの近似誤差で、本当は関連するチャンクがtop_3に入らない。
→ 対策:まず top_k=20 程度で取得し、クロスエンコーダ等でリランキングして上位5件に絞る。

パターン4:埋め込みモデルとDBの次元数不一致
1536次元のベクトルを768次元用のインデックスに入れようとしてエラーになる。
→ 対策:モデルの dimensions パラメータとDBスキーマをデプロイ前に検証する。

まとめ

  • ベクトル検索は、埋め込みベクトル空間でクエリに近い文書を探す方式だ。
  • コサイン類似度は「ベクトルの角度」で意味の近さを測る、テキスト検索で最も一般的な指標だ。
  • 小規模なら総当たり、大規模ならANN(HNSW等)で高速化する。
  • モデルの一致、metricの一致、閾値設計が検索品質の前提になる。

次のステップとして、10件程度の短文をベクトル化し、コサイン類似度のスコアを実際に出力してみると、閾値設計の感覚がつかめる。

参考リンク

この記事を書いた人✏️@YushiYamamoto
ITPRODX.com代表 / AIアーキテクト
Next.js / TypeScript / n8nを活用した自律型アーキテクチャ設計を専門としています。
日々の自動化の検証結果や、ビジネス側の視点(ROI等)に関するより深い考察は、以下の公式サイトおよびnoteで発信しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?