|
|
@ -1,4 +1,5 @@ |
|
|
# neo4j_util.py |
|
|
# neo4j_util.py |
|
|
|
|
|
import traceback |
|
|
from datetime import datetime |
|
|
from datetime import datetime |
|
|
import logging |
|
|
import logging |
|
|
from typing import Dict, List, Optional, Any |
|
|
from typing import Dict, List, Optional, Any |
|
|
@ -263,7 +264,7 @@ class Neo4jUtil: |
|
|
node_properties: Dict[str, Any], |
|
|
node_properties: Dict[str, Any], |
|
|
direction: str = "both", |
|
|
direction: str = "both", |
|
|
rel_type: Optional[str] = None, |
|
|
rel_type: Optional[str] = None, |
|
|
limit: int = 500, # 👈 新增参数,默认 1000 |
|
|
limit: int = 2000, # 👈 新增参数,默认 1000 |
|
|
) -> List[Dict[str, Any]]: |
|
|
) -> List[Dict[str, Any]]: |
|
|
""" |
|
|
""" |
|
|
查询指定节点的邻居(最多返回 limit 条) |
|
|
查询指定节点的邻居(最多返回 limit 条) |
|
|
@ -288,17 +289,19 @@ class Neo4jUtil: |
|
|
else: |
|
|
else: |
|
|
raise ValueError("direction 必须是 'out', 'in' 或 'both'") |
|
|
raise ValueError("direction 必须是 'out', 'in' 或 'both'") |
|
|
|
|
|
|
|
|
# ✅ 添加 LIMIT |
|
|
|
|
|
cypher = f""" |
|
|
cypher = f""" |
|
|
MATCH {pattern} |
|
|
MATCH {pattern} |
|
|
WHERE {where_clause} |
|
|
WHERE {where_clause} |
|
|
|
|
|
WITH r, startNode(r) AS s, endNode(r) AS t |
|
|
RETURN |
|
|
RETURN |
|
|
elementId(n) AS sourceId, |
|
|
elementId(s) AS sourceId, |
|
|
head(labels(n)) AS sourceLabel, |
|
|
head(labels(s)) AS sourceLabel, |
|
|
n{{.*}} AS sourceProps, |
|
|
s{{.*}} AS sourceProps, |
|
|
elementId(m) AS targetId, |
|
|
|
|
|
head(labels(m)) AS targetLabel, |
|
|
elementId(t) AS targetId, |
|
|
m{{.*}} AS targetProps, |
|
|
head(labels(t)) AS targetLabel, |
|
|
|
|
|
t{{.*}} AS targetProps, |
|
|
|
|
|
|
|
|
elementId(r) AS relId, |
|
|
elementId(r) AS relId, |
|
|
type(r) AS relType, |
|
|
type(r) AS relType, |
|
|
r{{.*}} AS relProps |
|
|
r{{.*}} AS relProps |
|
|
@ -306,28 +309,38 @@ class Neo4jUtil: |
|
|
""" |
|
|
""" |
|
|
params["limit"] = limit # 注入 limit 参数(安全) |
|
|
params["limit"] = limit # 注入 limit 参数(安全) |
|
|
|
|
|
|
|
|
raw_results = self.execute_read(cypher, params) |
|
|
# ✅ 安全执行查询 |
|
|
|
|
|
try: |
|
|
|
|
|
raw_results = self.execute_read(cypher, params) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
# 可选:记录原始错误(如果你有 logger) |
|
|
|
|
|
# self.logger.error(f"Neo4j 查询失败: {str(e)}\nCypher: {cypher}\nParams: {params}") |
|
|
|
|
|
traceback.print_exc() # 这会打印完整的 traceback 到 stderr |
|
|
|
|
|
# 抛出更友好的运行时错误 |
|
|
|
|
|
raise RuntimeError( |
|
|
|
|
|
f"查询邻居节点时发生数据库错误: {str(e)}" |
|
|
|
|
|
) from e # 使用 'from e' 保留原始异常链 |
|
|
|
|
|
print(raw_results) |
|
|
neighbors = [] |
|
|
neighbors = [] |
|
|
|
|
|
print("Ssssssssss") |
|
|
|
|
|
print(len(raw_results)) |
|
|
for row in raw_results: |
|
|
for row in raw_results: |
|
|
source = dict(row["sourceProps"]) |
|
|
source = dict(row["sourceProps"]) |
|
|
source.update({"id": row["sourceId"], "label": row["sourceLabel"]}) |
|
|
source.update({"id": row["sourceId"], "label": row["sourceLabel"]}) |
|
|
|
|
|
|
|
|
target = dict(row["targetProps"]) |
|
|
target = dict(row["targetProps"]) |
|
|
target.update({"id": row["targetId"], "label": row["targetLabel"]}) |
|
|
target.update({"id": row["targetId"], "label": row["targetLabel"]}) |
|
|
|
|
|
|
|
|
relationship = { |
|
|
relationship = { |
|
|
"id": row["relId"], |
|
|
"id": row["relId"], |
|
|
"type": row["relType"], |
|
|
"type": row["relType"], |
|
|
"properties": dict(row["relProps"]) if row["relProps"] else {} |
|
|
"properties": dict(row["relProps"]) if row["relProps"] else {} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
neighbors.append({ |
|
|
neighbors.append({ |
|
|
"source": source, |
|
|
"source": source, |
|
|
"target": target, |
|
|
"target": target, |
|
|
"relationship": relationship |
|
|
"relationship": relationship |
|
|
}) |
|
|
}) |
|
|
|
|
|
print(relationship) |
|
|
|
|
|
print(neighbors) |
|
|
return neighbors |
|
|
return neighbors |
|
|
# def find_neighbors_with_relationships( |
|
|
# def find_neighbors_with_relationships( |
|
|
# self, |
|
|
# self, |
|
|
|