添加 PostgreSQL 全文搜索的提示
复制粘贴 AI 提示,为现有 Next.js 应用添加原生 PostgreSQL 全文搜索,使用 tsvector、GIN 索引和排序结果。
CursorClaude CodeCodexWindsurf Next.jsPostgreSQLTypeScript
使用此提示为现有应用添加真正的 PostgreSQL 全文搜索——使用 tsvector、GIN 索引和 ts_rank,而无需代理转向 Elasticsearch、Algolia 或第三方搜索 API。
主要提示
You are working in a Next.js App Router project with TypeScript and PostgreSQL (using the`postgres` npm package, not Prisma or Drizzle).
Task: add full-text search over the `posts` table (columns: id, title, body, created_at).
Database changes:1. Write a migration file `migrations/0010_add_fts.sql` that: - Adds a generated column: `search_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', coalesce(title,'') || ' ' || coalesce(body,''))) STORED;` - Creates a GIN index: `CREATE INDEX posts_search_idx ON posts USING GIN (search_vector);`2. Do NOT use `pg_trgm` or LIKE queries — use `@@` with `to_tsquery` or `websearch_to_tsquery`.
Application changes:- Create `src/lib/search.ts` with a `searchPosts(query: string, limit = 20)` function that: - Uses `websearch_to_tsquery('english', $1)` to parse the query safely. - Returns rows ordered by `ts_rank(search_vector, query_vector) DESC`. - Returns `{ id, title, body_excerpt, rank }` — body_excerpt via `ts_headline`. - Uses parameterized queries only — no string interpolation.- Create a Server Action `src/lib/actions/search.ts` that calls `searchPosts` and returns results.- Create `src/components/SearchBox.tsx` (Client Component) with a debounced input (300 ms) that calls the Server Action via `useTransition` and renders results.
Do not install pg_search, Meilisearch, or any search service. Stop and list files before coding.实施说明
websearch_to_tsquery比to_tsquery更安全,因为它能容忍格式错误的查询(缺少运算符、特殊字符),而不会抛出 PostgreSQL 错误。- 生成的
tsvector列会在 INSERT/UPDATE 时自动更新——无需触发器。 ts_headline需要原始列文本和查询向量;从 SELECT 中同时传递两者。- GIN 索引使大表上的搜索速度更快;没有它,查询将进行顺序扫描。
预期文件更改
migrations/0010_add_fts.sql (new)src/lib/search.ts (new)src/lib/actions/search.ts (new — Server Action)src/components/SearchBox.tsx (new — Client Component)验收标准
psql -f migrations/0010_add_fts.sql在现有架构上运行无错误。- 搜索仅出现在
title中的单词会返回正确的文章。 - 搜索带有拼写错误的短语(例如 “postgress”)不会返回结果,也不会崩溃。
- 结果按相关性排序,相关性高的文章优先。
测试命令
psql "$DATABASE_URL" -f migrations/0010_add_fts.sqlbun run typecheckbun run dev# type a search term in SearchBox and verify ranked results appearpsql "$DATABASE_URL" -c "EXPLAIN ANALYZE SELECT * FROM posts WHERE search_vector @@ websearch_to_tsquery('english','test');"# confirm "Index Scan using posts_search_idx" appears in output常见 AI 错误
- 使用
LIKE '%query%'而不是@@全文运算符。 - 使用
to_tsquery('english', $1)处理原始用户输入——会在像"foo bar"这样的查询上出错。 - 忘记 GIN 索引,导致搜索变成顺序扫描。
- 在客户端组件中调用
searchPosts,而不是将其包装在 Server Action 中。
修复提示
The search is using LIKE or crashing on special characters. Fix in order:1. Replace any LIKE clause with `search_vector @@ websearch_to_tsquery('english', $1)`.2. If `to_tsquery` is used directly with user input, replace it with `websearch_to_tsquery`.3. Confirm the GIN index exists: `CREATE INDEX IF NOT EXISTS posts_search_idx ON posts USING GIN (search_vector);`Show only the corrected diff. Do not modify unrelated files.