feat: 搜索改进与代码修复
- 连字符扩展:multi-agent → multi agent 提升搜索召回率 - 中文同义词支持:添加中英文混合查询扩展 - Snippet 高亮预留:为 FTS5 snippet 功能预留接口 - YAML 解析增强:支持 HTML 实体解码 - 标签关联维护:自动维护 wiki_page_tags 关联表 - 缓存失效优化:支持智能前缀匹配 - 设计文档更新:汇总近期改动 (v1.3) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,13 +7,32 @@ Service Layer - QueryService(查询服务)
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Set, Optional
|
||||
import re
|
||||
from typing import List, Set, Optional, Dict
|
||||
from ..storage import Database, WikiPage
|
||||
from .cache import CacheService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# 中文同义词映射(用于扩展搜索查询)
|
||||
CHINESE_SYNONYMS: Dict[str, List[str]] = {
|
||||
"多智能体": ["multi-agent", "多agent", "multi agent"],
|
||||
"编排": ["orchestration", "调度"],
|
||||
"协作": ["collaboration", "协同"],
|
||||
"工具": ["tool", "工具调用"],
|
||||
"模式": ["pattern", "设计模式"],
|
||||
"实践": ["practice", "最佳实践"],
|
||||
"架构": ["architecture", "系统架构"],
|
||||
"代理": ["agent", "智能体"],
|
||||
"大模型": ["llm", "language model", "语言模型"],
|
||||
"向量": ["vector", "embedding", "嵌入"],
|
||||
"检索": ["retrieval", "search", "搜索"],
|
||||
"生成": ["generation", "生成式"],
|
||||
"推理": ["inference", "reasoning"],
|
||||
}
|
||||
|
||||
|
||||
class QueryService:
|
||||
"""查询服务 - 负责所有查询逻辑"""
|
||||
|
||||
@@ -21,19 +40,51 @@ class QueryService:
|
||||
self.db = db
|
||||
self.cache = cache
|
||||
|
||||
async def search(self, query: str, limit: int = 10) -> List[WikiPage]:
|
||||
"""FTS5 全文搜索"""
|
||||
def _expand_query_with_synonyms(self, query: str) -> str:
|
||||
"""使用中文同义词扩展查询
|
||||
|
||||
例如:"多智能体编排" → "多智能体编排 multi-agent orchestration"
|
||||
"""
|
||||
expanded_terms = []
|
||||
query_lower = query.lower()
|
||||
|
||||
# 检查每个中文词是否有对应的英文同义词
|
||||
for chinese_term, english_synonyms in CHINESE_SYNONYMS.items():
|
||||
if chinese_term in query:
|
||||
expanded_terms.extend(english_synonyms)
|
||||
|
||||
if expanded_terms:
|
||||
# 构建扩展查询(OR 连接)
|
||||
expanded_query = f"{query} OR {' OR '.join(expanded_terms)}"
|
||||
logger.debug(f"Expanded query: {query} → {expanded_query}")
|
||||
return expanded_query
|
||||
|
||||
return query
|
||||
|
||||
async def search(self, query: str, limit: int = 10, use_synonyms: bool = True) -> List[WikiPage]:
|
||||
"""FTS5 全文搜索
|
||||
|
||||
Args:
|
||||
query: 搜索查询
|
||||
limit: 返回结果数量限制
|
||||
use_synonyms: 是否使用中文同义词扩展
|
||||
"""
|
||||
# 1. 检查缓存
|
||||
cache_key = f"search:{query}:{limit}"
|
||||
cache_key = f"search:{query}:{limit}:{use_synonyms}"
|
||||
cached = await self.cache.get(cache_key)
|
||||
if cached:
|
||||
logger.debug(f"Cache hit for search: {query}")
|
||||
return cached
|
||||
|
||||
# 2. FTS5 搜索
|
||||
results = await self.db.fts_search(query, limit)
|
||||
# 2. 查询扩展(中文同义词)
|
||||
search_query = query
|
||||
if use_synonyms:
|
||||
search_query = self._expand_query_with_synonyms(query)
|
||||
|
||||
# 3. 缓存结果
|
||||
# 3. FTS5 搜索
|
||||
results = await self.db.fts_search(search_query, limit)
|
||||
|
||||
# 4. 缓存结果
|
||||
await self.cache.set(cache_key, results, ttl=3600)
|
||||
|
||||
return results
|
||||
@@ -116,5 +167,26 @@ class QueryService:
|
||||
return await self.db.get_stats()
|
||||
|
||||
async def invalidate_cache(self, pattern: str = "*") -> int:
|
||||
"""使缓存失效"""
|
||||
return await self.cache.invalidate(pattern)
|
||||
"""使缓存失效
|
||||
|
||||
如果 pattern 是具体路径(不是通配符),自动尝试匹配所有缓存前缀:
|
||||
- page:{pattern}
|
||||
- links:{pattern}
|
||||
- search:{pattern}
|
||||
"""
|
||||
# 清除所有缓存
|
||||
if pattern == "*":
|
||||
return await self.cache.invalidate(pattern)
|
||||
|
||||
# 对于具体路径,尝试所有可能的前缀
|
||||
prefixes = ["page:", "links:", "search:"]
|
||||
total_invalidated = 0
|
||||
|
||||
for prefix in prefixes:
|
||||
count = await self.cache.invalidate(f"{prefix}{pattern}")
|
||||
total_invalidated += count
|
||||
|
||||
# 也尝试原始模式(兼容直接传入完整 key 的情况)
|
||||
total_invalidated += await self.cache.invalidate(pattern)
|
||||
|
||||
return total_invalidated
|
||||
|
||||
Reference in New Issue
Block a user