ベクトルデータベース 2025 - AI時代の検索インフラ

2026.01.12

ベクトルデータベースとは

ベクトルデータベース(Vector Database)は、高次元ベクトルデータを効率的に保存・検索するための専用データベースです。テキスト、画像、音声などをAIモデル(Embedding Model)でベクトル化し、意味的な類似性に基づいて検索できます。

2025年現在、AIアプリケーションの85%以上がベクトルDBを利用しており、RAG(Retrieval-Augmented Generation)の基盤技術として不可欠な存在となっています。

ベクトル検索の仕組み

Embeddingとは

Embeddingは、テキストや画像などの非構造化データを、意味を保持した数値ベクトルに変換する技術です。

from openai import OpenAI

client = OpenAI()

# テキストをベクトル化
def get_embedding(text: str, model: str = "text-embedding-3-small") -> list[float]:
    """テキストを1536次元のベクトルに変換"""
    response = client.embeddings.create(
        input=text,
        model=model
    )
    return response.data[0].embedding

# 例: 2つのテキストをベクトル化
vec1 = get_embedding("東京の天気は晴れです")
vec2 = get_embedding("今日の東京は快晴でした")
vec3 = get_embedding("Pythonプログラミング入門")

print(f"ベクトル次元数: {len(vec1)}")  # 1536

ベクトル間の類似度を計算する主な手法は3つあります。

import numpy as np

def cosine_similarity(v1: list, v2: list) -> float:
    """コサイン類似度: 角度ベースの類似度(-1〜1)"""
    v1, v2 = np.array(v1), np.array(v2)
    return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))

def euclidean_distance(v1: list, v2: list) -> float:
    """ユークリッド距離: 直線距離(0〜∞、小さいほど類似)"""
    v1, v2 = np.array(v1), np.array(v2)
    return np.linalg.norm(v1 - v2)

def dot_product(v1: list, v2: list) -> float:
    """内積: 正規化済みベクトル向け"""
    return np.dot(v1, v2)

# 類似度を計算
print(f"天気同士の類似度: {cosine_similarity(vec1, vec2):.4f}")  # 0.92
print(f"天気とプログラミング: {cosine_similarity(vec1, vec3):.4f}")  # 0.31

ANNアルゴリズム(近似最近傍探索)

数百万〜数十億のベクトルから高速に検索するため、**ANN(Approximate Nearest Neighbor)**アルゴリズムが使われます。

アルゴリズム特徴適用場面
HNSW高精度・高速、メモリ消費大精度重視のアプリ
IVFメモリ効率良好、事前クラスタリング必要大規模データセット
PQ圧縮率高、精度やや低下メモリ制約のある環境
ScaNNGoogle開発、バランス型汎用用途
┌─────────────────────────────────────────────────────────────┐
│                    HNSW (Hierarchical NSW)                  │
├─────────────────────────────────────────────────────────────┤
│  Layer 2:  ○ ─────────────── ○ ─────────────── ○           │
│            │                 │                 │           │
│  Layer 1:  ○ ─── ○ ─── ○ ─── ○ ─── ○ ─── ○ ─── ○           │
│            │     │     │     │     │     │     │           │
│  Layer 0:  ○─○─○─○─○─○─○─○─○─○─○─○─○─○─○─○─○─○─○           │
│                                                             │
│  → 上位層から下位層へ階層的にナビゲート                        │
└─────────────────────────────────────────────────────────────┘

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

1. Pinecone

フルマネージドのサーバーレスベクトルDB。スケーラビリティと使いやすさが強み。

from pinecone import Pinecone, ServerlessSpec

# 初期化
pc = Pinecone(api_key="YOUR_API_KEY")

# インデックス作成
pc.create_index(
    name="semantic-search",
    dimension=1536,
    metric="cosine",
    spec=ServerlessSpec(
        cloud="aws",
        region="us-east-1"
    )
)

index = pc.Index("semantic-search")

# ベクトルをアップサート
index.upsert(
    vectors=[
        {
            "id": "doc1",
            "values": get_embedding("機械学習の基礎"),
            "metadata": {"category": "AI", "source": "textbook"}
        },
        {
            "id": "doc2",
            "values": get_embedding("深層学習入門"),
            "metadata": {"category": "AI", "source": "tutorial"}
        }
    ],
    namespace="articles"
)

# 類似検索
results = index.query(
    vector=get_embedding("AIについて学びたい"),
    top_k=5,
    include_metadata=True,
    namespace="articles",
    filter={"category": {"$eq": "AI"}}
)

for match in results.matches:
    print(f"ID: {match.id}, Score: {match.score:.4f}")

2. Weaviate

GraphQL APIとハイブリッド検索が特徴のオープンソースDB。

import weaviate
from weaviate.classes.init import Auth
from weaviate.classes.query import MetadataQuery

# クライアント初期化(Weaviate Cloud)
client = weaviate.connect_to_weaviate_cloud(
    cluster_url="https://your-cluster.weaviate.network",
    auth_credentials=Auth.api_key("YOUR_API_KEY"),
    headers={"X-OpenAI-Api-Key": "YOUR_OPENAI_KEY"}
)

# コレクション作成
from weaviate.classes.config import Configure, Property, DataType

client.collections.create(
    name="Article",
    vectorizer_config=Configure.Vectorizer.text2vec_openai(),
    properties=[
        Property(name="title", data_type=DataType.TEXT),
        Property(name="content", data_type=DataType.TEXT),
        Property(name="category", data_type=DataType.TEXT)
    ]
)

# データ追加(自動でベクトル化)
articles = client.collections.get("Article")
articles.data.insert({
    "title": "ベクトルDBの選び方",
    "content": "プロダクション環境でのベクトルDB選定ポイントを解説...",
    "category": "database"
})

# ハイブリッド検索(ベクトル + キーワード)
response = articles.query.hybrid(
    query="ベクトルデータベース 比較",
    alpha=0.5,  # 0=キーワード重視, 1=ベクトル重視
    limit=5,
    return_metadata=MetadataQuery(score=True)
)

for obj in response.objects:
    print(f"{obj.properties['title']}: {obj.metadata.score:.4f}")

client.close()

3. Qdrant

Rust製の高性能ベクトルDB。フィルタリング性能に優れる。

from qdrant_client import QdrantClient
from qdrant_client.models import (
    VectorParams, Distance, PointStruct,
    Filter, FieldCondition, MatchValue
)

# クライアント初期化
client = QdrantClient(
    url="https://your-cluster.qdrant.io",
    api_key="YOUR_API_KEY"
)

# コレクション作成
client.create_collection(
    collection_name="documents",
    vectors_config=VectorParams(
        size=1536,
        distance=Distance.COSINE
    )
)

# ベクトル追加
client.upsert(
    collection_name="documents",
    points=[
        PointStruct(
            id=1,
            vector=get_embedding("Rustプログラミング"),
            payload={"title": "Rust入門", "lang": "ja", "year": 2025}
        ),
        PointStruct(
            id=2,
            vector=get_embedding("Go言語の並行処理"),
            payload={"title": "Go並行処理", "lang": "ja", "year": 2024}
        )
    ]
)

# フィルタ付き検索
results = client.search(
    collection_name="documents",
    query_vector=get_embedding("システムプログラミング言語"),
    query_filter=Filter(
        must=[
            FieldCondition(
                key="year",
                match=MatchValue(value=2025)
            )
        ]
    ),
    limit=5,
    with_payload=True
)

for result in results:
    print(f"{result.payload['title']}: {result.score:.4f}")

4. Milvus

大規模分散処理に強い。数十億ベクトルを扱える。

from pymilvus import (
    connections, Collection, FieldSchema,
    CollectionSchema, DataType, utility
)

# 接続
connections.connect(
    alias="default",
    host="localhost",
    port="19530"
)

# スキーマ定義
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
    FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=512),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536)
]
schema = CollectionSchema(fields=fields)

# コレクション作成
collection = Collection(name="articles", schema=schema)

# インデックス作成(HNSW)
index_params = {
    "metric_type": "COSINE",
    "index_type": "HNSW",
    "params": {"M": 16, "efConstruction": 256}
}
collection.create_index(field_name="embedding", index_params=index_params)

# データ挿入
data = [
    ["記事タイトル1", "記事タイトル2"],
    [get_embedding("内容1"), get_embedding("内容2")]
]
collection.insert(data)
collection.load()

# 検索
search_params = {"metric_type": "COSINE", "params": {"ef": 64}}
results = collection.search(
    data=[get_embedding("検索クエリ")],
    anns_field="embedding",
    param=search_params,
    limit=5,
    output_fields=["title"]
)

for hits in results:
    for hit in hits:
        print(f"{hit.entity.get('title')}: {hit.distance:.4f}")

5. Chroma

ローカル開発に最適な軽量DB。プロトタイピングに便利。

import chromadb
from chromadb.utils import embedding_functions

# クライアント初期化
client = chromadb.PersistentClient(path="./chroma_db")

# OpenAI Embeddingを使用
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
    api_key="YOUR_OPENAI_KEY",
    model_name="text-embedding-3-small"
)

# コレクション作成
collection = client.get_or_create_collection(
    name="my_documents",
    embedding_function=openai_ef,
    metadata={"hnsw:space": "cosine"}
)

# ドキュメント追加(自動でベクトル化)
collection.add(
    documents=[
        "Pythonは初心者に優しいプログラミング言語です",
        "JavaScriptはWeb開発に欠かせない言語です",
        "Rustはメモリ安全性を重視したシステム言語です"
    ],
    metadatas=[
        {"lang": "Python", "level": "beginner"},
        {"lang": "JavaScript", "level": "intermediate"},
        {"lang": "Rust", "level": "advanced"}
    ],
    ids=["doc1", "doc2", "doc3"]
)

# 検索
results = collection.query(
    query_texts=["プログラミング初心者向けの言語"],
    n_results=2,
    where={"level": "beginner"}
)

print(results["documents"])

主要サービス比較表

機能PineconeWeaviateQdrantMilvusChroma
ホスティングマネージド両対応両対応両対応ローカル中心
最大ベクトル数無制限数十億数十億数百億数百万
アルゴリズム独自HNSWHNSW複数対応HNSW
フィルタリング
ハイブリッド検索
マルチテナント
日本語対応
無料枠ありありありOSSOSS
価格(月額)$70〜$25〜$25〜OSS/有料無料

既存DBのベクトル拡張

pgvector(PostgreSQL)

既存のPostgreSQLにベクトル検索を追加できます。

-- pgvector拡張を有効化
CREATE EXTENSION IF NOT EXISTS vector;

-- テーブル作成
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT,
    embedding VECTOR(1536),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

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

-- ベクトル検索関数
CREATE OR REPLACE FUNCTION search_documents(
    query_embedding VECTOR(1536),
    match_threshold FLOAT DEFAULT 0.7,
    match_count INT DEFAULT 10
)
RETURNS TABLE (
    id INT,
    title TEXT,
    content TEXT,
    similarity FLOAT
)
LANGUAGE plpgsql AS $$
BEGIN
    RETURN QUERY
    SELECT
        d.id,
        d.title,
        d.content,
        1 - (d.embedding <=> query_embedding) AS similarity
    FROM documents d
    WHERE 1 - (d.embedding <=> query_embedding) > match_threshold
    ORDER BY d.embedding <=> query_embedding
    LIMIT match_count;
END;
$$;
import psycopg2
from pgvector.psycopg2 import register_vector

# 接続
conn = psycopg2.connect("postgresql://user:pass@localhost/mydb")
register_vector(conn)

cur = conn.cursor()

# ベクトル挿入
embedding = get_embedding("サンプルテキスト")
cur.execute(
    "INSERT INTO documents (title, content, embedding) VALUES (%s, %s, %s)",
    ("タイトル", "内容", embedding)
)

# ベクトル検索
query_embedding = get_embedding("検索クエリ")
cur.execute(
    "SELECT * FROM search_documents(%s, 0.7, 5)",
    (query_embedding,)
)
results = cur.fetchall()

Elasticsearch + kNN

PUT /articles
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "content": { "type": "text" },
      "embedding": {
        "type": "dense_vector",
        "dims": 1536,
        "index": true,
        "similarity": "cosine"
      }
    }
  }
}
from elasticsearch import Elasticsearch

es = Elasticsearch("https://localhost:9200")

# kNN検索
response = es.search(
    index="articles",
    knn={
        "field": "embedding",
        "query_vector": get_embedding("検索クエリ"),
        "k": 10,
        "num_candidates": 100
    }
)

RAGでの活用パターン

基本的なRAGパイプライン

from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_qdrant import QdrantVectorStore
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

# ベクトルストア設定
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = QdrantVectorStore.from_existing_collection(
    embedding=embeddings,
    collection_name="knowledge_base",
    url="http://localhost:6333"
)

# カスタムプロンプト
prompt_template = """以下のコンテキストを使用して質問に回答してください。
コンテキストに情報がない場合は「情報が見つかりません」と回答してください。

コンテキスト:
{context}

質問: {question}

回答:"""

prompt = PromptTemplate(
    template=prompt_template,
    input_variables=["context", "question"]
)

# RAGチェーン構築
qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o", temperature=0),
    chain_type="stuff",
    retriever=vectorstore.as_retriever(
        search_type="mmr",  # Maximum Marginal Relevance
        search_kwargs={"k": 5, "fetch_k": 20}
    ),
    chain_type_kwargs={"prompt": prompt},
    return_source_documents=True
)

# 質問応答
result = qa_chain.invoke({"query": "ベクトルDBの選び方は?"})
print(result["result"])
print("参照元:", [doc.metadata for doc in result["source_documents"]])

Rerankerによる精度向上

from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank

# Cohere Rerankを使用
reranker = CohereRerank(
    cohere_api_key="YOUR_COHERE_KEY",
    top_n=5,
    model="rerank-multilingual-v3.0"
)

# 圧縮リトリーバー
compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker,
    base_retriever=vectorstore.as_retriever(search_kwargs={"k": 20})
)

# 検索(20件取得 → Rerankで5件に絞り込み)
docs = compression_retriever.invoke("ベクトルDBの比較")

マルチモーダルRAG

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
import base64

def encode_image(image_path: str) -> str:
    with open(image_path, "rb") as f:
        return base64.standard_b64encode(f.read()).decode("utf-8")

# 画像とテキストを組み合わせた検索
llm = ChatOpenAI(model="gpt-4o")

# 画像からテキスト説明を生成
image_data = encode_image("diagram.png")
response = llm.invoke([
    HumanMessage(content=[
        {"type": "text", "text": "この図を説明してください"},
        {
            "type": "image_url",
            "image_url": {"url": f"data:image/png;base64,{image_data}"}
        }
    ])
])

# 生成された説明をベクトル化して保存
description = response.content
embedding = get_embedding(description)
# vectorstore.add(...)

パフォーマンス比較

ベンチマーク結果(100万ベクトル、1536次元)

指標PineconeQdrantMilvuspgvector
挿入速度15K/秒25K/秒30K/秒5K/秒
検索レイテンシ(p99)15ms8ms12ms45ms
Recall@1098.5%99.2%98.8%97.5%
メモリ効率

コスト比較(月間100万クエリ、1000万ベクトル)

サービス月額コスト備考
Pinecone Serverless$150〜300使用量に応じた課金
Weaviate Cloud$100〜200インスタンスサイズ依存
Qdrant Cloud$100〜250RAM/ストレージ課金
Milvus(セルフホスト)$200〜500インフラ費用
pgvector(RDS)$150〜400DBインスタンス費用

選定ガイドライン

┌─────────────────────────────────────────────────────────────┐
│                   ベクトルDB選定フローチャート                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  プロトタイプ/PoC?  ─── Yes ──→ Chroma                      │
│         │                                                   │
│        No                                                   │
│         ↓                                                   │
│  既存PostgreSQL活用?  ─── Yes ──→ pgvector                  │
│         │                                                   │
│        No                                                   │
│         ↓                                                   │
│  フルマネージド希望?  ─── Yes ──→ Pinecone                   │
│         │                                                   │
│        No                                                   │
│         ↓                                                   │
│  10億ベクトル以上?  ─── Yes ──→ Milvus                      │
│         │                                                   │
│        No                                                   │
│         ↓                                                   │
│  フィルタ/ハイブリッド検索重視?  ─── Yes ──→ Qdrant/Weaviate │
│         │                                                   │
│        No                                                   │
│         ↓                                                   │
│  ──→ Qdrant(汎用性が高い)                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

ベストプラクティス

1. 適切なEmbeddingモデル選択

# 用途別推奨モデル
EMBEDDING_MODELS = {
    "general": "text-embedding-3-small",      # コスト効率
    "high_accuracy": "text-embedding-3-large", # 高精度
    "multilingual": "multilingual-e5-large",   # 多言語対応
    "japanese": "cl-tohoku/bert-base-japanese" # 日本語特化
}

2. チャンキング戦略

from langchain.text_splitter import RecursiveCharacterTextSplitter

# 日本語対応チャンキング
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", "、", " ", ""]
)

chunks = splitter.split_text(long_document)

3. メタデータの活用

# フィルタリング可能なメタデータ設計
metadata = {
    "source": "company_docs",
    "category": "engineering",
    "date": "2025-01-12",
    "author": "team_lead",
    "access_level": "internal",
    "version": 2
}

まとめ

2025年のベクトルデータベースは、AI/LLMアプリケーションの中核インフラとして成熟しています。用途に応じた選定が重要です。

  • スタートアップ/PoC: Chroma、pgvector
  • 本番環境(マネージド): Pinecone、Weaviate Cloud
  • 本番環境(セルフホスト): Qdrant、Milvus
  • 既存システム統合: pgvector、Elasticsearch

RAGの品質はベクトルDBの選択と設定に大きく依存します。適切なインデックス設計、チャンキング戦略、Rerankerの活用で、検索精度を最大化しましょう。

参考: Pinecone Docs | Qdrant Documentation | Weaviate Docs

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

LINEで無料相談する
← 一覧に戻る