更新 app.py
减少索引的冗余代码
This commit is contained in:
parent
0dad49a050
commit
eb07576567
197
app.py
197
app.py
@ -106,7 +106,7 @@ _resources: Dict[str, Any] = {
|
|||||||
# 图谱检索和索引生成
|
# 图谱检索和索引生成
|
||||||
try:
|
try:
|
||||||
from graph_search.graph_service import GraphService
|
from graph_search.graph_service import GraphService
|
||||||
from neo4j_indexing import create_all_indexes, create_global_indexes, build_hybrid_indexes
|
from neo4j_indexing import build_hybrid_indexes
|
||||||
INDEXING_AVAILABLE = True
|
INDEXING_AVAILABLE = True
|
||||||
GRAPH_AVAILABLE = True
|
GRAPH_AVAILABLE = True
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
@ -2325,153 +2325,114 @@ class Neo4jIndexingRequest(BaseModel):
|
|||||||
force_refresh: Optional[bool] = (
|
force_refresh: Optional[bool] = (
|
||||||
False # 是否强制刷新所有索引(True=清空重建,False=增量更新,只处理新节点或缺失的索引)
|
False # 是否强制刷新所有索引(True=清空重建,False=增量更新,只处理新节点或缺失的索引)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/neo4j_indexing")
|
@app.post("/neo4j_indexing")
|
||||||
async def neo4j_indexing(request: Neo4jIndexingRequest):
|
async def neo4j_indexing(request: Neo4jIndexingRequest):
|
||||||
"""
|
"""
|
||||||
========== ========== ========== ========== ========== ==========
|
Neo4j知识图谱混合索引创建接口
|
||||||
Neo4j 知识图谱索引创建接口
|
|
||||||
|
|
||||||
功能:为 Neo4j 知识图谱中的所有节点标签创建向量索引和全文索引,
|
当前版本:
|
||||||
并构建跨标签的全局混合(Searchable)索引。
|
只创建 Searchable 混合索引体系:
|
||||||
|
|
||||||
请求参数(均为可选):
|
1. searchable_vector
|
||||||
- neo4j_uri: Neo4j 连接 URI(可选,优先使用 .env 中的 NEO4J_URI)
|
- embedding语义检索
|
||||||
- neo4j_username: Neo4j 用户名(可选,优先使用 .env 中的 NEO4J_USERNAME)
|
|
||||||
- neo4j_password: Neo4j 密码(可选,优先使用 .env 中的 NEO4J_PASSWORD)
|
|
||||||
- force_refresh: 是否强制刷新所有索引(默认 False)
|
|
||||||
* False(增量更新):只处理新节点或缺失索引的节点,保留现有索引
|
|
||||||
* True(强制刷新):清空所有索引和约束后重新创建
|
|
||||||
|
|
||||||
返回格式:
|
2. searchable_name_fulltext
|
||||||
{
|
- 名称关键词检索
|
||||||
"code": 200 / 207 / 409 / 500,
|
|
||||||
"message": "...",
|
|
||||||
"data": {
|
|
||||||
"success": bool,
|
|
||||||
"message": "...",
|
|
||||||
"mode": "force_refresh" / "incremental",
|
|
||||||
"labels": [...],
|
|
||||||
"labels_count": int,
|
|
||||||
"vector_index_errors": [...],
|
|
||||||
"fulltext_index_errors": [...],
|
|
||||||
"hybrid_index_status": "success" / "failed",
|
|
||||||
"hybrid_index_error": str / null,
|
|
||||||
"elapsed_seconds": float
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
并发说明:
|
3. searchable_fulltext
|
||||||
- 索引创建为重操作,接口通过全局锁串行化;
|
- 内容关键词检索
|
||||||
已有任务在跑时,新请求立即返回 409,不会排队等待。
|
|
||||||
========== ========== ========== ========== ========== ==========
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
logger.info("[neo4j_indexing] 收到索引创建请求")
|
logger.info("[neo4j_indexing] 收到索引创建请求")
|
||||||
|
|
||||||
# ========== 并发保护:已有索引任务在跑时直接拒绝 ==========
|
|
||||||
|
# ==============================
|
||||||
|
# 防止并发创建索引
|
||||||
|
# ==============================
|
||||||
|
|
||||||
if _neo4j_indexing_lock.locked():
|
if _neo4j_indexing_lock.locked():
|
||||||
logger.warning("[neo4j_indexing] 已有索引任务在执行,拒绝并发请求")
|
logger.warning(
|
||||||
|
"[neo4j_indexing] 已有任务执行,拒绝请求"
|
||||||
|
)
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=409,
|
status_code=409,
|
||||||
content={
|
content={
|
||||||
"code": 409,
|
"code":409,
|
||||||
"message": "已有索引创建任务正在执行,请稍后再试",
|
"message":"已有Neo4j索引创建任务正在执行",
|
||||||
"data": None,
|
"data":None
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
async with _neo4j_indexing_lock:
|
async with _neo4j_indexing_lock:
|
||||||
try:
|
try:
|
||||||
# ========== 检查依赖是否可用 ==========
|
|
||||||
if not INDEXING_AVAILABLE:
|
if not INDEXING_AVAILABLE:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=503,detail="Neo4j索引模块不可用")
|
||||||
status_code=503,
|
kwargs = {
|
||||||
detail="Neo4j索引创建功能不可用,请确保已正确安装相关依赖",
|
"drop_old": True,
|
||||||
)
|
}
|
||||||
|
# 如果接口传入连接参数,则覆盖
|
||||||
# force_refresh 在 Pydantic 模型中已有默认值 False,不会是 None
|
|
||||||
force_refresh = request.force_refresh
|
|
||||||
|
|
||||||
# 构建函数调用参数,只传递非 None 的参数
|
|
||||||
kwargs = {"force_refresh": force_refresh}
|
|
||||||
if request.neo4j_uri:
|
if request.neo4j_uri:
|
||||||
kwargs["neo4j_uri"] = request.neo4j_uri
|
kwargs["uri"] = request.neo4j_uri
|
||||||
if request.neo4j_username:
|
if request.neo4j_username:
|
||||||
kwargs["neo4j_username"] = request.neo4j_username
|
kwargs["user"] = request.neo4j_username
|
||||||
if request.neo4j_password:
|
if request.neo4j_password:
|
||||||
kwargs["neo4j_password"] = request.neo4j_password
|
kwargs["password"] = request.neo4j_password
|
||||||
|
|
||||||
# ========== 第一步:按标签创建向量/全文索引 ==========
|
result = await asyncio.to_thread(build_hybrid_indexes,**kwargs)
|
||||||
# 同步操作放到线程池执行,避免阻塞事件循环
|
elapsed = time.time()-start_time
|
||||||
result = await asyncio.to_thread(create_all_indexes, **kwargs)
|
if result.get("success"):
|
||||||
|
logger.info(
|
||||||
# ========== 第二步:构建全局混合(Searchable)索引 ==========
|
f"[neo4j_indexing] 创建成功 "
|
||||||
# 单独捕获异常:即使这一步失败,也不能丢掉 create_all_indexes 的成功结果
|
f"耗时:{elapsed:.2f}s")
|
||||||
hybrid_status = "success"
|
return {
|
||||||
hybrid_error = None
|
"code":200,
|
||||||
try:
|
"message":"success",
|
||||||
hybrid_result = await asyncio.to_thread(build_hybrid_indexes, driver)
|
"data":{
|
||||||
if not hybrid_result.get("success", False):
|
"success":True,
|
||||||
hybrid_status = "failed"
|
"message":
|
||||||
hybrid_error = hybrid_result.get("message", "未知错误")
|
result.get("message","混合索引创建完成"),
|
||||||
logger.error(f"[neo4j_indexing] build_hybrid_indexes 失败: {hybrid_error}")
|
"searchable_added":
|
||||||
except Exception as e:
|
result.get("searchable_added",0),
|
||||||
hybrid_status = "failed"
|
"elapsed_seconds":
|
||||||
hybrid_error = str(e)
|
round(elapsed,2)
|
||||||
logger.error(f"[neo4j_indexing] build_hybrid_indexes 异常: {e}", exc_info=True)
|
}
|
||||||
|
}
|
||||||
elapsed = time.time() - start_time
|
else:
|
||||||
|
logger.error(
|
||||||
# ========== 构建响应 ==========
|
f"[neo4j_indexing] 创建失败:"
|
||||||
overall_success = result["success"] and hybrid_status == "success"
|
f"{result.get('message')}"
|
||||||
response_data = {
|
)
|
||||||
"success": overall_success,
|
return {
|
||||||
"message": result["message"],
|
"code":207,
|
||||||
"mode": result.get("mode", "unknown"),
|
"message":"partial success",
|
||||||
"labels": result["labels"],
|
"data":{
|
||||||
"labels_count": len(result["labels"]),
|
"success":False,
|
||||||
"vector_index_errors": result["vector_index_errors"],
|
"message":
|
||||||
"fulltext_index_errors": result["fulltext_index_errors"],
|
result.get("message","未知错误"),
|
||||||
"hybrid_index_status": hybrid_status,
|
"searchable_added":0,
|
||||||
"hybrid_index_error": hybrid_error,
|
"elapsed_seconds":round(elapsed,2)
|
||||||
"elapsed_seconds": round(elapsed, 2),
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"[neo4j_indexing] 索引创建完成,耗时: {elapsed:.2f}秒")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"code": 200 if overall_success else 207, # 207 表示部分成功
|
|
||||||
"message": "success",
|
|
||||||
"data": response_data,
|
|
||||||
}
|
|
||||||
|
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
elapsed = time.time() - start_time
|
elapsed=time.time()-start_time
|
||||||
error_msg = f"索引创建失败: {str(e)}"
|
error_msg=f"索引创建失败:{str(e)}"
|
||||||
logger.error(f"[neo4j_indexing] {error_msg} (耗时: {elapsed:.2f}秒)", exc_info=True)
|
logger.error(error_msg,exc_info=True)
|
||||||
return {
|
return {
|
||||||
"code": 500,
|
"code":500,
|
||||||
"message": "索引创建失败",
|
"message":"索引创建失败",
|
||||||
"data": {
|
"data":{
|
||||||
"success": False,
|
"success":False,
|
||||||
"message": error_msg,
|
"message":error_msg,
|
||||||
"mode": "error",
|
"elapsed_seconds":
|
||||||
"labels": [],
|
round(elapsed,2)
|
||||||
"labels_count": 0,
|
}
|
||||||
"vector_index_errors": [],
|
|
||||||
"fulltext_index_errors": [],
|
|
||||||
"hybrid_index_status": "error",
|
|
||||||
"hybrid_index_error": error_msg,
|
|
||||||
"elapsed_seconds": round(elapsed, 2),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ========== ========== ========== ========== ========== ==========
|
# ========== ========== ========== ========== ========== ==========
|
||||||
# Neo4j 索引创建接口结束
|
# Neo4j 索引创建接口结束
|
||||||
# ========== ========== ========== ========== ========== ==========
|
# ========== ========== ========== ========== ========== ==========
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user