ベクトルデータベースとは?RAGに不可欠な類似検索の仕組みを解説

kento_morota 15分で読めます

「LLMに社内の最新情報を回答させたい」「大量の文書から意味的に近い情報を検索したい」——こうしたニーズに応えるのがベクトルデータベースです。

LLM(大規模言語モデル)は強力ですが、学習データに含まれない最新情報や社内固有の知識は持っていません。RAG(Retrieval-Augmented Generation:検索拡張生成)は、ベクトルデータベースから関連情報を検索し、LLMのコンテキストに注入することで、この問題を解決するアーキテクチャです。

本記事では、ベクトルデータベースの仕組みから主要製品の比較、RAGシステムの実装まで、体系的に解説します。

ベクトルデータベースの基本概念

ベクトルデータベースとは、データをベクトル(数値の配列)として格納し、ベクトル間の類似度に基づく検索(類似検索)に特化したデータベースです。

Embedding(ベクトル化)とは

テキスト、画像、音声などのデータを、意味を保持したまま固定長の数値ベクトルに変換する処理をEmbeddingと呼びます。

# Embeddingのイメージ
"猫はかわいい" → [0.12, -0.34, 0.56, 0.78, -0.11, ...] (1536次元)
"犬はかわいい" → [0.13, -0.32, 0.58, 0.75, -0.09, ...] (1536次元)
"東京タワー"   → [-0.45, 0.67, -0.23, 0.11, 0.89, ...] (1536次元)

# 意味的に近いテキストは、ベクトル空間上で近い位置になる
# "猫はかわいい" と "犬はかわいい" のベクトルは近い
# "猫はかわいい" と "東京タワー" のベクトルは遠い

Embeddingモデルは、テキストの意味的な関係性をベクトル空間の幾何学的な関係に変換します。「猫」と「犬」は共に動物であり「かわいい」という文脈で使われることが多いため、そのベクトルは空間上で近い位置にマッピングされます。

代表的なEmbeddingモデルには以下があります。

OpenAI text-embedding-3-small/large:APIとして利用可能な高精度モデル
Cohere embed-multilingual-v3:多言語対応に強み
BGE-M3:オープンソースの多言語対応モデル
multilingual-e5-large:日本語を含む多言語で高精度

類似度の計算方法

ベクトル間の類似度は、主に以下の指標で計算されます。

コサイン類似度
2つのベクトルの向きの近さを測ります。値は-1〜1の範囲で、1に近いほど類似しています。テキストのEmbeddingではコサイン類似度が最も一般的です。

ユークリッド距離
ベクトル間の直線距離を測ります。値が小さいほど類似しています。空間的な距離が意味を持つデータに適しています。

内積(ドット積)
ベクトルの大きさと方向の両方を考慮します。正規化されたベクトルではコサイン類似度と同等です。

# Pythonでの類似度計算
import numpy as np

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

def euclidean_distance(a, b):
    return np.linalg.norm(np.array(a) - np.array(b))

# 例
vec_cat = [0.12, -0.34, 0.56, 0.78]
vec_dog = [0.13, -0.32, 0.58, 0.75]
vec_tower = [-0.45, 0.67, -0.23, 0.11]

print(cosine_similarity(vec_cat, vec_dog))    # 0.99(非常に類似)
print(cosine_similarity(vec_cat, vec_tower))   # -0.12(類似していない)

なぜベクトルデータベースが必要なのか

「通常のデータベースでベクトルの類似計算をすればいいのでは?」と思うかもしれません。しかし、数百万〜数億のベクトルに対して高速な類似検索を行うには、専用のインデックス構造とアルゴリズムが必要です。

近似最近傍探索(ANN)

すべてのベクトルと比較する全探索(brute-force)は、データ量が増えると実用的な速度で処理できません。ベクトルデータベースは、近似最近傍探索(ANN:Approximate Nearest Neighbor)アルゴリズムにより、わずかな精度のトレードオフで劇的な速度向上を実現します。

主なANNアルゴリズムは以下の通りです。

HNSW(Hierarchical Navigable Small World)
グラフ構造を使ったアルゴリズムで、最も広く使われています。高い精度と検索速度のバランスに優れ、Qdrant、Weaviate、pgvectorなどが採用しています。

IVF(Inverted File Index)
ベクトル空間をクラスタに分割し、検索時には近いクラスタのみを探索します。メモリ効率が良く、大規模データに適しています。

PQ(Product Quantization)
ベクトルを圧縮して保存する手法です。メモリ使用量を削減できますが、精度はやや低下します。IVFと組み合わせて使われることが多いです。

ベクトルデータベースが従来DBより優れる点

類似検索の速度:ANNインデックスにより、数百万ベクトルでもミリ秒単位の検索が可能
高次元データの扱い:1536次元や3072次元といった高次元ベクトルを効率的に格納・検索
メタデータフィルタリング:ベクトル検索とメタデータ条件の組み合わせ検索に対応
スケーラビリティ:データ量の増加に対して水平スケールが可能

主要ベクトルデータベースの比較

2026年現在、主要なベクトルデータベース4製品を比較します。

Pinecone:フルマネージドSaaS

Pineconeは、ベクトルデータベース専業のSaaSサービスです。セットアップ不要で、APIキーを取得するだけで利用開始できます。

特徴

・完全マネージドでサーバー管理不要
・サーバーレスプランで小規模利用からスタート可能
・自動スケーリングに対応
・Namespaceによるデータの論理分割

// Pineconeの使用例
import { Pinecone } from '@pinecone-database/pinecone';

const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pc.index('my-index');

// ベクトルの挿入
await index.upsert([
  {
    id: 'doc-1',
    values: [0.12, -0.34, 0.56, ...], // Embeddingベクトル
    metadata: { title: '記事タイトル', category: '技術', date: '2026-03-27' },
  },
]);

// 類似検索
const results = await index.query({
  vector: queryEmbedding,
  topK: 5,
  filter: { category: { $eq: '技術' } },
  includeMetadata: true,
});

料金:無料枠あり(Starterプラン)、有料プランは月額70ドルから。

Weaviate:GraphQLインターフェースのOSS

Weaviateは、GraphQLベースのAPIを持つオープンソースのベクトルデータベースです。セルフホストとクラウド版の両方が利用可能です。

特徴

・GraphQLベースの直感的なAPI
・オブジェクト指向のスキーマ設計
・Embeddingモデルとの統合(Vectorizer Module)
・ハイブリッド検索(ベクトル検索 + キーワード検索)に対応

料金:OSS版は無料、Weaviate Cloudは月額25ドルから。

Qdrant:Rust製の高性能ベクトルDB

Qdrantは、Rust言語で実装された高性能なベクトルデータベースです。パフォーマンスとメモリ効率に優れています。

特徴

・Rust実装による高いパフォーマンス
・高度なフィルタリング機能
・マルチテナント対応
・量子化によるメモリ最適化

// Qdrantの使用例(REST API)
// コレクションの作成
const createResponse = await fetch('http://localhost:6333/collections/articles', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    vectors: { size: 1536, distance: 'Cosine' },
  }),
});

// ベクトルの検索
const searchResponse = await fetch('http://localhost:6333/collections/articles/points/search', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    vector: queryEmbedding,
    limit: 5,
    filter: {
      must: [{ key: 'category', match: { value: '技術' } }],
    },
    with_payload: true,
  }),
});

料金:OSS版は無料、Qdrant Cloudは月額25ドルから。

pgvector:PostgreSQLの拡張

pgvectorは、PostgreSQLにベクトル検索機能を追加する拡張です。既存のPostgreSQL環境にベクトル検索を統合できるのが最大のメリットです。

特徴

・既存のPostgreSQLインフラをそのまま活用
・SQLでベクトル検索が記述可能
・リレーショナルデータとベクトルデータを同一DBで管理
・HNSWインデックスに対応

-- pgvectorの使用例

-- 拡張の有効化
CREATE EXTENSION vector;

-- テーブルの作成
CREATE TABLE documents (
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  category TEXT,
  embedding vector(1536)  -- 1536次元のベクトル
);

-- HNSWインデックスの作成
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

-- 類似検索(コサイン類似度)
SELECT id, title, content,
       1 - (embedding <=> $1::vector) AS similarity
FROM documents
WHERE category = '技術'
ORDER BY embedding <=> $1::vector
LIMIT 5;

料金:OSS(無料)。ホスティングはSupabase、Neon、AWS RDSなどで利用可能。

選び方のガイドライン

手軽に始めたい → Pinecone(フルマネージド、セットアップ最小)
既存のPostgreSQLがある → pgvector(追加インフラ不要)
高いパフォーマンスが必要 → Qdrant(Rust製で高速)
ハイブリッド検索が必要 → Weaviate(ベクトル+キーワードの統合検索)

RAG(検索拡張生成)の仕組みと実装

RAGは、ベクトルデータベースの最も重要なユースケースです。LLMの回答精度を劇的に向上させます。

RAGの処理フロー

RAGシステムは、大きく「インデックス構築」と「検索・生成」の2つのフェーズで構成されます。

インデックス構築フェーズ

1. ドキュメントの収集(社内文書、FAQなど)
2. テキストをチャンクに分割(例:500文字ごと)
3. 各チャンクをEmbeddingモデルでベクトル化
4. ベクトルとメタデータをベクトルデータベースに格納

検索・生成フェーズ

1. ユーザーの質問をEmbeddingモデルでベクトル化
2. ベクトルデータベースで類似検索し、関連チャンクを取得
3. 取得したチャンクをLLMのプロンプトに埋め込む
4. LLMが関連情報を元に回答を生成

RAGの実装例(Python)

# RAGシステムの簡易実装
from openai import OpenAI
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct

client = OpenAI()
qdrant = QdrantClient(host="localhost", port=6333)

# --- インデックス構築 ---

def create_embeddings(texts: list[str]) -> list[list[float]]:
    """テキストをEmbeddingベクトルに変換"""
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=texts,
    )
    return [item.embedding for item in response.data]

def chunk_text(text: str, chunk_size: int = 500, overlap: int = 100) -> list[str]:
    """テキストをオーバーラップ付きでチャンク分割"""
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size
        chunks.append(text[start:end])
        start = end - overlap
    return chunks

def index_document(doc_id: str, title: str, content: str, category: str):
    """ドキュメントをベクトルDBにインデックス"""
    chunks = chunk_text(content)
    embeddings = create_embeddings(chunks)

    points = [
        PointStruct(
            id=hash(f"{doc_id}-{i}") % (2**63),
            vector=embedding,
            payload={
                "doc_id": doc_id,
                "title": title,
                "chunk_text": chunk,
                "chunk_index": i,
                "category": category,
            },
        )
        for i, (chunk, embedding) in enumerate(zip(chunks, embeddings))
    ]

    qdrant.upsert(collection_name="knowledge", points=points)

# --- 検索・生成 ---

def search_relevant_chunks(query: str, top_k: int = 5) -> list[dict]:
    """クエリに関連するチャンクを検索"""
    query_embedding = create_embeddings([query])[0]

    results = qdrant.search(
        collection_name="knowledge",
        query_vector=query_embedding,
        limit=top_k,
    )

    return [
        {
            "text": hit.payload["chunk_text"],
            "title": hit.payload["title"],
            "score": hit.score,
        }
        for hit in results
    ]

def generate_answer(query: str) -> str:
    """RAGで質問に回答"""
    # 関連チャンクを検索
    chunks = search_relevant_chunks(query)

    # コンテキストを構築
    context = "\n\n".join([
        f"【{c['title']}】\n{c['text']}"
        for c in chunks
    ])

    # LLMで回答を生成
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": """あなたは社内ナレッジベースに基づいて質問に回答するアシスタントです。
以下のルールに従ってください:
- 提供されたコンテキスト情報のみに基づいて回答する
- コンテキストに情報がない場合は「該当する情報が見つかりませんでした」と回答する
- 回答の根拠となるドキュメントのタイトルを明記する"""
            },
            {
                "role": "user",
                "content": f"コンテキスト:\n{context}\n\n質問: {query}"
            },
        ],
        temperature=0,
    )

    return response.choices[0].message.content

RAGの精度を向上させるテクニック

基本的なRAGの実装に加えて、精度を向上させるためのテクニックを紹介します。

チャンキング戦略の最適化

チャンク分割の方法は、RAGの精度に大きく影響します。

固定長チャンキング:一定の文字数で機械的に分割します。実装が簡単ですが、文の途中で分割されることがあります。

セマンティックチャンキング:段落やセクションなどの意味的な区切りで分割します。より意味の通った検索結果が得られます。

再帰的チャンキング:見出し → 段落 → 文という階層で分割を試み、チャンクサイズに収まるまで再帰的に分割します。LangChainのRecursiveCharacterTextSplitterがこのアプローチです。

ハイブリッド検索

ベクトル検索(意味的な類似度)とキーワード検索(BM25など)を組み合わせることで、検索の再現率を向上させます。

# ハイブリッド検索の概念
def hybrid_search(query: str, top_k: int = 5):
    # ベクトル検索(意味的な類似度)
    vector_results = vector_search(query, top_k=top_k * 2)

    # キーワード検索(BM25)
    keyword_results = bm25_search(query, top_k=top_k * 2)

    # Reciprocal Rank Fusionでスコアを統合
    fused = reciprocal_rank_fusion(vector_results, keyword_results)

    return fused[:top_k]

リランキング

初回の検索結果を、より精密なモデルでリランキング(再順位付け)することで、上位の結果の関連性を高めます。Cohere RerankやBGE Rerankなどのリランキングモデルが利用できます。

まとめ

ベクトルデータベースは、AIアプリケーションにおける「意味的な検索」の基盤技術です。本記事のポイントを振り返ります。

・Embeddingによりテキストを数値ベクトルに変換し、意味的な類似度を計算できる
・ベクトルデータベースはANNアルゴリズムで大規模データの高速類似検索を実現する
・Pinecone(マネージド)、pgvector(PostgreSQL拡張)、Qdrant(高性能)、Weaviate(ハイブリッド検索)が主要な選択肢
・RAGはベクトル検索でLLMのコンテキストに関連情報を注入し、回答精度を向上させる
・チャンキング戦略、ハイブリッド検索、リランキングでRAGの精度をさらに高められる

まずはpgvector(既存のPostgreSQLがある場合)またはQdrant(Dockerで手軽に起動可能)で小規模なRAGシステムを構築してみましょう。社内FAQの10〜20件程度からスタートし、検索精度を確認しながらデータを拡大していくのが効果的です。

#ベクトルDB#RAG#類似検索
共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

起業準備に役立つ情報、もっとありますよ。

まずは話だけ聞いてもらう