pgvector
PostgreSQLでベクトル埋め込みを保存・検索できるpgvectorは、既存のデータベースにAI検索機能を手軽に追加したい場合に、別途ベクトルデータベースを用意せずに類似性検索やRAGを実現するSkill。
📜 元の英語説明(参考)
Store and search vector embeddings in PostgreSQL with pgvector — no separate vector database needed. Use when someone asks to "vector search in Postgres", "store embeddings", "pgvector", "similarity search", "RAG with Postgres", "semantic search in existing database", or "add AI search to my app without a separate vector DB". Covers vector columns, indexing (IVFFlat, HNSW), similarity search, and integration with ORMs.
🇯🇵 日本人クリエイター向け解説
PostgreSQLでベクトル埋め込みを保存・検索できるpgvectorは、既存のデータベースにAI検索機能を手軽に追加したい場合に、別途ベクトルデータベースを用意せずに類似性検索やRAGを実現するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o pgvector.zip https://jpskill.com/download/15251.zip && unzip -o pgvector.zip && rm pgvector.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15251.zip -OutFile "$d\pgvector.zip"; Expand-Archive "$d\pgvector.zip" -DestinationPath $d -Force; ri "$d\pgvector.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
pgvector.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
pgvectorフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
pgvector
概要
pgvector は、PostgreSQL にベクトル類似性検索を追加します。通常のデータと一緒に埋め込みを保存します。別のベクトルデータベースは不要、データ同期は不要、新しいインフラストラクチャは不要です。既存の Postgres をセマンティック検索、RAG、レコメンデーション、および重複排除に使用します。IVFFlat および HNSW インデックスによる正確な最近傍探索と近似最近傍探索をサポートします。
使用場面
- 既存の Postgres をバックエンドとするアプリケーションにセマンティック/ベクトル検索を追加する場合
- Pinecone/Qdrant/Weaviate を実行せずに RAG (Retrieval-Augmented Generation) を行う場合
- リレーショナルデータ (ユーザー、製品、ドキュメント) と共に埋め込みを保存する場合
- コンテンツの類似性に基づくレコメンデーションシステム
- 別のベクトルデータベースを管理したくない場合
手順
セットアップ
-- 拡張機能を有効にする (Supabase、Neon、RDS、セルフホストで利用可能)
CREATE EXTENSION IF NOT EXISTS vector;
スキーマ設計
-- 通常の列と一緒に埋め込みを持つドキュメントを保存する
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}',
embedding vector(1536), -- OpenAI ada-002 の次元
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 高速な近似検索のための HNSW インデックス (推奨)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- または、メモリ使用量を抑えるための IVFFlat
-- CREATE INDEX ON documents
-- USING ivfflat (embedding vector_cosine_ops)
-- WITH (lists = 100);
埋め込みの保存
// ingest.ts — 埋め込みを生成して保存する
import { Pool } from "pg";
import OpenAI from "openai";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const openai = new OpenAI();
async function storeDocument(title: string, content: string, metadata: object = {}) {
// 埋め込みを生成する
const embeddingRes = await openai.embeddings.create({
model: "text-embedding-3-small",
input: content,
});
const embedding = embeddingRes.data[0].embedding;
// 埋め込みとともに保存する (pgvector は配列形式を受け入れる)
await pool.query(
`INSERT INTO documents (title, content, metadata, embedding)
VALUES ($1, $2, $3, $4)`,
[title, content, JSON.stringify(metadata), JSON.stringify(embedding)]
);
}
類似性検索
// search.ts — ベクトル距離で類似したドキュメントを見つける
async function semanticSearch(query: string, limit = 5, threshold = 0.7) {
// クエリを埋め込む
const embeddingRes = await openai.embeddings.create({
model: "text-embedding-3-small",
input: query,
});
const queryEmbedding = embeddingRes.data[0].embedding;
// コサイン類似度検索
const result = await pool.query(
`SELECT id, title, content, metadata,
1 - (embedding <=> $1::vector) AS similarity
FROM documents
WHERE 1 - (embedding <=> $1::vector) > $2
ORDER BY embedding <=> $1::vector
LIMIT $3`,
[JSON.stringify(queryEmbedding), threshold, limit]
);
return result.rows;
// [{ id: 1, title: "...", content: "...", similarity: 0.89 }, ...]
}
pgvector を使用した RAG
// rag.ts — pgvector を使用した Retrieval-Augmented Generation
async function ragAnswer(question: string): Promise<string> {
// 1. 関連するドキュメントを見つける
const docs = await semanticSearch(question, 5);
// 2. 取得したドキュメントからコンテキストを構築する
const context = docs.map((d) => `## ${d.title}\n${d.content}`).join("\n\n");
// 3. コンテキストを使用して回答を生成する
const completion = await openai.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "system",
content: `Answer based on the following context. If the context doesn't contain the answer, say so.\n\n${context}`,
},
{ role: "user", content: question },
],
});
return completion.choices[0].message.content!;
}
Drizzle ORM と共に
// schema.ts — Drizzle ORM を使用した pgvector
import { pgTable, text, serial, jsonb, index, timestamp } from "drizzle-orm/pg-core";
import { customType } from "drizzle-orm/pg-core";
// Drizzle 用のカスタム vector 型
const vector = customType<{ data: number[]; driverData: string }>({
dataType: () => "vector(1536)",
toDriver: (value) => JSON.stringify(value),
});
export const documents = pgTable("documents", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
content: text("content").notNull(),
embedding: vector("embedding"),
createdAt: timestamp("created_at").defaultNow(),
});
例
例 1: 既存のアプリにセマンティック検索を追加する
ユーザープロンプト: 「記事を含む Postgres データベースがあります。キーワードだけでなく、意味で検索できるようにセマンティック検索を追加してください。」
エージェントは、ベクトル列を追加し、既存の記事の埋め込みを生成し、HNSW インデックスを作成し、ベクトル類似性と既存のフィルターを組み合わせた検索エンドポイントを構築します。
例 2: RAG を使用したドキュメント Q&A
ユーザープロンプト: 「既存の Postgres データベースを使用して、社内ドキュメントに関する Q&A システムを構築します。」
エージェントは、ドキュメントをチャンク化し、埋め込みを pgvector に保存し、関連するチャンクを取得して回答を生成する RAG パイプラインを構築します。
ガイドライン
- ほとんどの場合 HNSW インデックス — クエリが高速、IVFFlat よりわずかに多くのメモリを使用
- コサイン距離 (
<=>) — 正規化された埋め込みに最適 (OpenAI、Cohere) - L2 距離 (
<->) — 正規化されていない埋め込み用 - 次元はモデルと一致する必要がある — ada-002: 1536, text-embedding-3-small: 1536
- 一括挿入後にインデックスを作成 — データをロードする前にではなく、ロード後にインデックスを作成
- フィルター + ベクトル検索 —
WHERE句をベクトル類似性と組み合わせる - 別のインフラストラクチャは不要 — 管理、デプロイ、および支払いを行うサービスが 1 つ減る
- Supabase に組み込まれている — ダッシュボードで
enable_extension('vector') - 長いドキュメントをチャンク化 — 最適な検索のために、チャンクあたり 500〜1500 トークン
- モデルを変更するときに再埋め込み — 異なるモデルからの埋め込みには互換性がない
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
pgvector
Overview
pgvector adds vector similarity search to PostgreSQL. Store embeddings alongside your regular data — no separate vector database, no data sync, no new infrastructure. Use your existing Postgres for semantic search, RAG, recommendations, and deduplication. Supports exact and approximate nearest neighbor search with IVFFlat and HNSW indexes.
When to Use
- Adding semantic/vector search to an existing Postgres-backed app
- RAG (Retrieval-Augmented Generation) without running Pinecone/Qdrant/Weaviate
- Storing embeddings alongside relational data (users, products, documents)
- Recommendation systems based on content similarity
- Don't want to manage a separate vector database
Instructions
Setup
-- Enable the extension (available on Supabase, Neon, RDS, self-hosted)
CREATE EXTENSION IF NOT EXISTS vector;
Schema Design
-- Store documents with embeddings alongside regular columns
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}',
embedding vector(1536), -- OpenAI ada-002 dimension
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- HNSW index for fast approximate search (recommended)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- Or IVFFlat for lower memory usage
-- CREATE INDEX ON documents
-- USING ivfflat (embedding vector_cosine_ops)
-- WITH (lists = 100);
Store Embeddings
// ingest.ts — Generate and store embeddings
import { Pool } from "pg";
import OpenAI from "openai";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const openai = new OpenAI();
async function storeDocument(title: string, content: string, metadata: object = {}) {
// Generate embedding
const embeddingRes = await openai.embeddings.create({
model: "text-embedding-3-small",
input: content,
});
const embedding = embeddingRes.data[0].embedding;
// Store with embedding (pgvector accepts array format)
await pool.query(
`INSERT INTO documents (title, content, metadata, embedding)
VALUES ($1, $2, $3, $4)`,
[title, content, JSON.stringify(metadata), JSON.stringify(embedding)]
);
}
Similarity Search
// search.ts — Find similar documents by vector distance
async function semanticSearch(query: string, limit = 5, threshold = 0.7) {
// Embed the query
const embeddingRes = await openai.embeddings.create({
model: "text-embedding-3-small",
input: query,
});
const queryEmbedding = embeddingRes.data[0].embedding;
// Cosine similarity search
const result = await pool.query(
`SELECT id, title, content, metadata,
1 - (embedding <=> $1::vector) AS similarity
FROM documents
WHERE 1 - (embedding <=> $1::vector) > $2
ORDER BY embedding <=> $1::vector
LIMIT $3`,
[JSON.stringify(queryEmbedding), threshold, limit]
);
return result.rows;
// [{ id: 1, title: "...", content: "...", similarity: 0.89 }, ...]
}
RAG with pgvector
// rag.ts — Retrieval-Augmented Generation using pgvector
async function ragAnswer(question: string): Promise<string> {
// 1. Find relevant documents
const docs = await semanticSearch(question, 5);
// 2. Build context from retrieved documents
const context = docs.map((d) => `## ${d.title}\n${d.content}`).join("\n\n");
// 3. Generate answer with context
const completion = await openai.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "system",
content: `Answer based on the following context. If the context doesn't contain the answer, say so.\n\n${context}`,
},
{ role: "user", content: question },
],
});
return completion.choices[0].message.content!;
}
With Drizzle ORM
// schema.ts — pgvector with Drizzle ORM
import { pgTable, text, serial, jsonb, index, timestamp } from "drizzle-orm/pg-core";
import { customType } from "drizzle-orm/pg-core";
// Custom vector type for Drizzle
const vector = customType<{ data: number[]; driverData: string }>({
dataType: () => "vector(1536)",
toDriver: (value) => JSON.stringify(value),
});
export const documents = pgTable("documents", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
content: text("content").notNull(),
embedding: vector("embedding"),
createdAt: timestamp("created_at").defaultNow(),
});
Examples
Example 1: Add semantic search to an existing app
User prompt: "I have a Postgres database with articles. Add semantic search so users can search by meaning, not just keywords."
The agent will add a vector column, generate embeddings for existing articles, create an HNSW index, and build a search endpoint that combines vector similarity with existing filters.
Example 2: Document Q&A with RAG
User prompt: "Build a Q&A system over our internal docs using our existing Postgres database."
The agent will chunk documents, store embeddings in pgvector, and build a RAG pipeline that retrieves relevant chunks and generates answers.
Guidelines
- HNSW index for most cases — faster queries, slightly more memory than IVFFlat
- Cosine distance (
<=>) — best for normalized embeddings (OpenAI, Cohere) - L2 distance (
<->) — for non-normalized embeddings - Dimension must match model — ada-002: 1536, text-embedding-3-small: 1536
- Index after bulk insert — create index after loading data, not before
- Filter + vector search — combine
WHEREclauses with vector similarity - No separate infrastructure — one less service to manage, deploy, and pay for
- Supabase has it built-in —
enable_extension('vector')in dashboard - Chunk long documents — 500-1500 tokens per chunk for best retrieval
- Re-embed when you change models — embeddings from different models aren't compatible