From 562370ece51f9c313669f1784f667c1eafea1c6d Mon Sep 17 00:00:00 2001 From: wanghanlin <1533525126@qq.com> Date: Wed, 2 Sep 2026 15:20:47 +0800 Subject: [PATCH] =?UTF-8?q?fix(backend):=20=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B9=82=E7=AD=89=E8=87=AA=E6=84=88?= =?UTF-8?q?=E4=B8=8E=20vector=5Fstore=20=E7=89=A9=E7=90=86=E5=88=A0?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DatabaseInitConfig 改为全幂等自愈(ADD COLUMN IF NOT EXISTS + 回填 + 索引/触发器幂等) - HybridSearchService 移除对 vector_store 的 is_delete 过滤(该表无此列,物理删除) --- .../supportbot/config/DatabaseInitConfig.java | 19 +++++++------------ .../supportbot/rag/HybridSearchService.java | 4 +++- src/main/resources/init-database.sql | 6 ++++++ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java b/src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java index e499a23..4e69124 100644 --- a/src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java +++ b/src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java @@ -930,7 +930,9 @@ public class DatabaseInitConfig { /** * 为 vector_store 表添加全文检索支持(tsvector 列 + GIN 索引 + 触发器) - * 幂等操作:已存在则跳过 + * 全幂等自愈:每一步都用幂等 SQL(ADD COLUMN IF NOT EXISTS / CREATE INDEX IF NOT EXISTS / + * CREATE OR REPLACE + DROP TRIGGER IF EXISTS),不做「列已存在就 return」的早退, + * 避免半途失败或触发器被手动删除后新文档 content_tsvector 恒为 NULL 的静默缺口。 */ private void initVectorStoreFullTextSearch() { try { @@ -940,19 +942,12 @@ public class DatabaseInitConfig { return; } - // 检查 content_tsvector 列是否已存在 - String checkSql = "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'vector_store' AND column_name = 'content_tsvector'"; - Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class); - if (count != null && count > 0) { - return; // 已初始化 - } - - log.info("为 vector_store 添加全文检索支持"); + log.info("初始化 vector_store 全文检索支持"); - // 添加 tsvector 列 - jdbcTemplate.execute("ALTER TABLE vector_store ADD COLUMN content_tsvector tsvector"); + // 添加 tsvector 列(已存在则跳过) + jdbcTemplate.execute("ALTER TABLE vector_store ADD COLUMN IF NOT EXISTS content_tsvector tsvector"); - // 填充已有数据 + // 回填已有数据(幂等:只补 NULL 行) jdbcTemplate.execute("UPDATE vector_store SET content_tsvector = to_tsvector('simple', coalesce(content, '')) WHERE content_tsvector IS NULL"); // GIN 索引 diff --git a/src/main/java/com/wok/supportbot/rag/HybridSearchService.java b/src/main/java/com/wok/supportbot/rag/HybridSearchService.java index d7fc7ae..6d6c24e 100644 --- a/src/main/java/com/wok/supportbot/rag/HybridSearchService.java +++ b/src/main/java/com/wok/supportbot/rag/HybridSearchService.java @@ -97,6 +97,9 @@ public class HybridSearchService { * 全文关键词检索 * 使用 PostgreSQL tsvector 全文索引,按 ts_rank 排序。 * P1-2.1: 始终过滤禁用的文档(metadata->>'enabled' = 'true') + * 注意:vector_store 为物理删除(无 is_delete 列),仅保证有 + * id / content / metadata / embedding / content_tsvector / create_time 六列, + * 禁止在原生 SQL 中引用 is_delete、update_time 等业务表字段。 */ private List keywordSearch(String query, int topK, List categoryIds) { String categoryFilter = buildCategoryFilter(categoryIds); @@ -105,7 +108,6 @@ public class HybridSearchService { ts_rank(content_tsvector, plainto_tsquery('simple', ?)) AS rank FROM vector_store WHERE content_tsvector @@ plainto_tsquery('simple', ?) - AND is_delete = false AND metadata->>'enabled' = 'true' %s ORDER BY rank DESC diff --git a/src/main/resources/init-database.sql b/src/main/resources/init-database.sql index 24349ec..4806813 100644 --- a/src/main/resources/init-database.sql +++ b/src/main/resources/init-database.sql @@ -367,6 +367,12 @@ CREATE TABLE IF NOT EXISTS vector_store ( update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); +-- ⚠️ 与 Spring AI 自动建表的差异(勿误判): +-- 1. Spring AI PgVectorStore 自动建表时 metadata 是 json(非 jsonb),且不含 create_time/update_time。 +-- create_time/content_tsvector 由 DatabaseInitConfig 补加;update_time 仅本手动脚本含、无代码引用。 +-- 2. vector_store 为物理删除(pgVectorVectorStore.delete),没有 is_delete 列。 +-- 任何原生 SQL 禁止引用 is_delete / update_time,只允许 id/content/metadata/embedding/content_tsvector/create_time。 + -- HNSW 向量索引(余弦距离) CREATE INDEX IF NOT EXISTS idx_vector_store_embedding ON vector_store USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);