|
@@ -56,17 +56,32 @@ public class RetrieverService {
|
|
|
String sql;
|
|
String sql;
|
|
|
Object[] params;
|
|
Object[] params;
|
|
|
if (!drugName.isEmpty()) {
|
|
if (!drugName.isEmpty()) {
|
|
|
- // 药品名+向量混合检索:精确匹配 或 前缀匹配(如"布洛芬"匹配"布洛芬片")
|
|
|
|
|
|
|
+ // 先精确匹配,没结果再前缀匹配(如"布洛芬"→先查"布洛芬",没有再查"布洛芬片/胶囊等")
|
|
|
sql = """
|
|
sql = """
|
|
|
SELECT c.content, c.source, c.drug_id, c.section,
|
|
SELECT c.content, c.source, c.drug_id, c.section,
|
|
|
1 - (c.vec <=> ?::vector) AS similarity
|
|
1 - (c.vec <=> ?::vector) AS similarity
|
|
|
FROM drug_chunks c
|
|
FROM drug_chunks c
|
|
|
JOIN drugs d ON d.drug_id = c.drug_id
|
|
JOIN drugs d ON d.drug_id = c.drug_id
|
|
|
- WHERE c.vec IS NOT NULL AND (d.name = ? OR d.name LIKE ?)
|
|
|
|
|
|
|
+ WHERE c.vec IS NOT NULL AND d.name = ?
|
|
|
ORDER BY c.vec <=> ?::vector
|
|
ORDER BY c.vec <=> ?::vector
|
|
|
LIMIT ?
|
|
LIMIT ?
|
|
|
""";
|
|
""";
|
|
|
- params = new Object[]{vecStr, drugName, drugName + "%", vecStr, topK};
|
|
|
|
|
|
|
+ params = new Object[]{vecStr, drugName, vecStr, topK};
|
|
|
|
|
+ List<Map<String, Object>> results = jdbc.queryForList(sql, params);
|
|
|
|
|
+ if (results.isEmpty()) {
|
|
|
|
|
+ // 精确无结果,用前缀匹配
|
|
|
|
|
+ sql = """
|
|
|
|
|
+ SELECT c.content, c.source, c.drug_id, c.section,
|
|
|
|
|
+ 1 - (c.vec <=> ?::vector) AS similarity
|
|
|
|
|
+ FROM drug_chunks c
|
|
|
|
|
+ JOIN drugs d ON d.drug_id = c.drug_id
|
|
|
|
|
+ WHERE c.vec IS NOT NULL AND d.name LIKE ?
|
|
|
|
|
+ ORDER BY c.vec <=> ?::vector
|
|
|
|
|
+ LIMIT ?
|
|
|
|
|
+ """;
|
|
|
|
|
+ params = new Object[]{vecStr, drugName + "%", vecStr, topK};
|
|
|
|
|
+ }
|
|
|
|
|
+ return jdbc.queryForList(sql, params);
|
|
|
} else {
|
|
} else {
|
|
|
sql = """
|
|
sql = """
|
|
|
SELECT content, source, drug_id, section,
|
|
SELECT content, source, drug_id, section,
|
|
@@ -84,18 +99,34 @@ public class RetrieverService {
|
|
|
|
|
|
|
|
/** 从 query 中提取已知药品名:查 drugs 表精确匹配 */
|
|
/** 从 query 中提取已知药品名:查 drugs 表精确匹配 */
|
|
|
private String extractDrugName(String query) {
|
|
private String extractDrugName(String query) {
|
|
|
- // 去掉常见后缀词,尝试匹配药品名
|
|
|
|
|
- String cleaned = query.replaceAll("[的之是](用法|用量|副作用|禁忌|注意|说明书|是什么|怎么|如何).*$", "");
|
|
|
|
|
- cleaned = cleaned.trim();
|
|
|
|
|
- if (cleaned.length() < 2) return "";
|
|
|
|
|
-
|
|
|
|
|
- // 查 drugs 表精确匹配
|
|
|
|
|
|
|
+ String cleaned = query.trim();
|
|
|
|
|
+ // 逐步去掉尾部修饰词,尝试匹配药品名
|
|
|
|
|
+ String[] suffixes = {
|
|
|
|
|
+ "的用法与用量", "的用法用量", "用法与用量", "用法用量", "的用量", "的用法",
|
|
|
|
|
+ "的副作用", "不良反应", "的禁忌", "禁忌", "的注意事项", "注意事项",
|
|
|
|
|
+ "是什么", "说明书", "怎么用", "怎么吃", "的用量", "用量", "的剂量", "剂量"
|
|
|
|
|
+ };
|
|
|
|
|
+ // 先尝试原始 query
|
|
|
try {
|
|
try {
|
|
|
List<String> matches = jdbc.queryForList(
|
|
List<String> matches = jdbc.queryForList(
|
|
|
"SELECT name FROM drugs WHERE name = ? AND is_active = TRUE LIMIT 1",
|
|
"SELECT name FROM drugs WHERE name = ? AND is_active = TRUE LIMIT 1",
|
|
|
String.class, cleaned);
|
|
String.class, cleaned);
|
|
|
if (!matches.isEmpty()) return matches.get(0);
|
|
if (!matches.isEmpty()) return matches.get(0);
|
|
|
} catch (Exception ignored) {}
|
|
} catch (Exception ignored) {}
|
|
|
|
|
+
|
|
|
|
|
+ // 逐步去掉后缀再试
|
|
|
|
|
+ for (String suffix : suffixes) {
|
|
|
|
|
+ if (cleaned.endsWith(suffix)) {
|
|
|
|
|
+ String candidate = cleaned.substring(0, cleaned.length() - suffix.length()).trim();
|
|
|
|
|
+ if (candidate.length() < 2) continue;
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<String> matches = jdbc.queryForList(
|
|
|
|
|
+ "SELECT name FROM drugs WHERE name = ? AND is_active = TRUE LIMIT 1",
|
|
|
|
|
+ String.class, candidate);
|
|
|
|
|
+ if (!matches.isEmpty()) return matches.get(0);
|
|
|
|
|
+ } catch (Exception ignored) {}
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
return "";
|
|
return "";
|
|
|
}
|
|
}
|
|
|
|
|
|