|
@@ -25,7 +25,7 @@ from app.core.graph.graph_operations import connect_graph,create_or_get_node,get
|
|
from app.services.neo4j_driver import neo4j_driver
|
|
from app.services.neo4j_driver import neo4j_driver
|
|
from app.core.meta_data import get_formatted_time, handle_id_unstructured
|
|
from app.core.meta_data import get_formatted_time, handle_id_unstructured
|
|
from app.core.common import delete_relationships, update_or_create_node, get_node_by_id_no_label
|
|
from app.core.common import delete_relationships, update_or_create_node, get_node_by_id_no_label
|
|
-from app.core.data_resource.resource import get_node_by_id
|
|
|
|
|
|
+from app.core.data_resource.resource import get_node_by_id, serialize_node_properties
|
|
|
|
|
|
|
|
|
|
# 根据child关系计算数据模型当前的level自动保存
|
|
# 根据child关系计算数据模型当前的level自动保存
|
|
@@ -253,7 +253,7 @@ def resource_handle_meta_data_model(id_lists, data_model_node_id):
|
|
# query = """
|
|
# query = """
|
|
# MATCH (source:DataModel), (target:DataResource)
|
|
# MATCH (source:DataModel), (target:DataResource)
|
|
# WHERE id(source)=$source_id AND id(target) IN $target_ids
|
|
# WHERE id(source)=$source_id AND id(target) IN $target_ids
|
|
- # MERGE (source)-[:DERIVES_FROM]->(target)
|
|
|
|
|
|
+ # MERGE (source)-[:DERIVED_FROM]->(target)
|
|
# RETURN count(*) as count
|
|
# RETURN count(*) as count
|
|
# """
|
|
# """
|
|
# with connect_graph().session() as session:
|
|
# with connect_graph().session() as session:
|
|
@@ -734,6 +734,7 @@ def model_resource_list(skip_count, page_size, name_filter=None, id=None,
|
|
def model_kinship_graph(nodeid, meta=False):
|
|
def model_kinship_graph(nodeid, meta=False):
|
|
"""
|
|
"""
|
|
生成数据模型的血缘关系图谱
|
|
生成数据模型的血缘关系图谱
|
|
|
|
+ 按照DERIVED_FROM关系进行递归查找,从当前节点作为起点查找所有DERIVED_FROM关系指向的节点
|
|
|
|
|
|
Args:
|
|
Args:
|
|
nodeid: 节点ID
|
|
nodeid: 节点ID
|
|
@@ -742,127 +743,123 @@ def model_kinship_graph(nodeid, meta=False):
|
|
Returns:
|
|
Returns:
|
|
dict: 包含节点和连线信息的图谱数据
|
|
dict: 包含节点和连线信息的图谱数据
|
|
"""
|
|
"""
|
|
- result = {}
|
|
|
|
-
|
|
|
|
- with connect_graph().session() as session:
|
|
|
|
- # 查询起始模型节点
|
|
|
|
- start_node_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
- RETURN n.name as name, n.en_name as en_name
|
|
|
|
- """
|
|
|
|
-
|
|
|
|
- start_result = session.run(start_node_query, nodeId=nodeid)
|
|
|
|
- start_record = start_result.single()
|
|
|
|
-
|
|
|
|
- if not start_record:
|
|
|
|
- return {"nodes": [], "lines": []}
|
|
|
|
-
|
|
|
|
- # 查询与模型关联的血缘关系(包括数据资源和其他数据模型),表示哪些节点是当前节点的上级血缘关系
|
|
|
|
- lineage_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
- OPTIONAL MATCH (n)-[:DERIVED_FROM]->(resource:DataResource)
|
|
|
|
- OPTIONAL MATCH (n)-[:DERIVED_FROM]->(model:DataModel)
|
|
|
|
- RETURN resource, model
|
|
|
|
- """
|
|
|
|
-
|
|
|
|
- lineage_result = session.run(lineage_query, nodeId=nodeid)
|
|
|
|
-
|
|
|
|
- nodes = [{"id": str(nodeid), "text": start_record['name'], "type": "model"}]
|
|
|
|
- lines = []
|
|
|
|
-
|
|
|
|
- # 处理血缘节点(数据资源和数据模型)
|
|
|
|
- for record in lineage_result:
|
|
|
|
- # 处理数据资源节点
|
|
|
|
- if record['resource']:
|
|
|
|
- resource = record['resource']
|
|
|
|
- resource_id = str(resource.id)
|
|
|
|
- resource_name = resource.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建资源节点
|
|
|
|
- resource_node = {
|
|
|
|
- "id": resource_id,
|
|
|
|
- "text": resource_name,
|
|
|
|
- "type": "DataResource"
|
|
|
|
- }
|
|
|
|
- nodes.append(resource_node)
|
|
|
|
-
|
|
|
|
- # 创建模型到资源的关系
|
|
|
|
- line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": resource_id,
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
|
|
+ try:
|
|
|
|
+ with connect_graph().session() as session:
|
|
|
|
+ # 确保nodeid为整数
|
|
|
|
+ try:
|
|
|
|
+ nodeid_int = int(nodeid)
|
|
|
|
+ except (ValueError, TypeError):
|
|
|
|
+ logger.error(f"节点ID不是有效的整数: {nodeid}")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
|
|
- # 处理数据模型节点
|
|
|
|
- if record['model']:
|
|
|
|
- model = record['model']
|
|
|
|
- model_id = str(model.id)
|
|
|
|
- model_name = model.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建模型节点
|
|
|
|
- model_node = {
|
|
|
|
- "id": model_id,
|
|
|
|
- "text": model_name,
|
|
|
|
- "type": "DataModel"
|
|
|
|
- }
|
|
|
|
- nodes.append(model_node)
|
|
|
|
-
|
|
|
|
- # 创建模型到模型的关系
|
|
|
|
- line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": model_id,
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
-
|
|
|
|
- # 处理元数据节点
|
|
|
|
- if meta:
|
|
|
|
- meta_query = """
|
|
|
|
|
|
+ # 查询起始模型节点是否存在
|
|
|
|
+ start_node_query = """
|
|
MATCH (n:DataModel)
|
|
MATCH (n:DataModel)
|
|
WHERE id(n) = $nodeId
|
|
WHERE id(n) = $nodeId
|
|
- MATCH p = (n)-[:INCLUDES]->(meta:DataMeta)
|
|
|
|
- RETURN meta
|
|
|
|
|
|
+ RETURN n
|
|
|
|
+ """
|
|
|
|
+
|
|
|
|
+ start_result = session.run(start_node_query, nodeId=nodeid_int)
|
|
|
|
+ start_record = start_result.single()
|
|
|
|
+
|
|
|
|
+ if not start_record:
|
|
|
|
+ logger.error(f"未找到ID为{nodeid_int}的DataModel节点")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
+
|
|
|
|
+ # 递归查找DERIVED_FROM关系
|
|
|
|
+ cypher = """
|
|
|
|
+ MATCH (start:DataModel)
|
|
|
|
+ WHERE id(start) = $nodeId
|
|
|
|
+ MATCH path = (start)-[:DERIVED_FROM*0..]->(target)
|
|
|
|
+ WHERE target:DataResource OR target:DataModel
|
|
|
|
+ RETURN path
|
|
"""
|
|
"""
|
|
- meta_result = session.run(meta_query, nodeId=nodeid)
|
|
|
|
|
|
+
|
|
|
|
+ result = session.run(cypher, nodeId=nodeid_int)
|
|
|
|
|
|
- for record in meta_result:
|
|
|
|
- if 'meta' in record:
|
|
|
|
- meta_node = record['meta']
|
|
|
|
- meta_id = str(meta.id)
|
|
|
|
- meta_name = meta.get('name', '')
|
|
|
|
- meta_en_name = meta.get('en_name', '')
|
|
|
|
|
|
+ # 收集节点和关系
|
|
|
|
+ nodes = {}
|
|
|
|
+ lines = {}
|
|
|
|
+
|
|
|
|
+ for record in result:
|
|
|
|
+ # 处理路径
|
|
|
|
+ path = record['path']
|
|
|
|
+ logger.debug(f"处理路径,长度: {len(path)}, 节点数: {len(path.nodes)}, 关系数: {len(path.relationships)}")
|
|
|
|
+
|
|
|
|
+ # 处理路径中的所有节点
|
|
|
|
+ for node in path.nodes:
|
|
|
|
+ node_id = int(node.id) # 直接转换为整数
|
|
|
|
+ if node_id not in nodes:
|
|
|
|
+ node_dict = serialize_node_properties(node)
|
|
|
|
+ node_dict["id"] = str(node_id)
|
|
|
|
+ node_dict["node_type"] = list(node.labels)[0] if node.labels else ""
|
|
|
|
+ nodes[node_id] = node_dict
|
|
|
|
+ logger.debug(f"添加节点: ID={node_id}, 标签={list(node.labels)}")
|
|
|
|
+
|
|
|
|
+ # 处理路径中的所有关系
|
|
|
|
+ for rel in path.relationships:
|
|
|
|
+ rel_id = int(rel.id) # 直接转换为整数
|
|
|
|
+ if rel_id not in lines:
|
|
|
|
+ rel_dict = {
|
|
|
|
+ "id": str(rel_id),
|
|
|
|
+ "from": str(int(rel.start_node.id)),
|
|
|
|
+ "to": str(int(rel.end_node.id)),
|
|
|
|
+ "text": rel.type
|
|
|
|
+ }
|
|
|
|
+ lines[rel_id] = rel_dict
|
|
|
|
+ logger.debug(f"添加关系: ID={rel_id}, 类型={rel.type}, 从{int(rel.start_node.id)}到{int(rel.end_node.id)}")
|
|
|
|
+
|
|
|
|
+ # 如果需要元数据,查询INCLUDES关系
|
|
|
|
+ if meta:
|
|
|
|
+ meta_cypher = """
|
|
|
|
+ MATCH (start:DataModel)-[r:INCLUDES]->(meta:DataMeta)
|
|
|
|
+ WHERE id(start) = $nodeId
|
|
|
|
+ RETURN start, r, meta
|
|
|
|
+ """
|
|
|
|
+ meta_result = session.run(meta_cypher, nodeId=nodeid_int)
|
|
|
|
+
|
|
|
|
+ for meta_record in meta_result:
|
|
|
|
+ start_node = meta_record['start']
|
|
|
|
+ rel = meta_record['r']
|
|
|
|
+ meta_node = meta_record['meta']
|
|
|
|
|
|
- # 创建元数据节点
|
|
|
|
- meta_node = {
|
|
|
|
- "id": meta_id,
|
|
|
|
- "text": meta_name,
|
|
|
|
- "type": "DataMeta"
|
|
|
|
- }
|
|
|
|
- nodes.append(meta_node)
|
|
|
|
|
|
+ # 添加元数据节点
|
|
|
|
+ meta_node_id = int(meta_node.id)
|
|
|
|
+ if meta_node_id not in nodes:
|
|
|
|
+ node_dict = serialize_node_properties(meta_node)
|
|
|
|
+ node_dict["id"] = str(meta_node_id)
|
|
|
|
+ node_dict["node_type"] = list(meta_node.labels)[0] if meta_node.labels else ""
|
|
|
|
+ nodes[meta_node_id] = node_dict
|
|
|
|
|
|
- # 创建模型到元数据的标签关系
|
|
|
|
- tag_line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": meta_id,
|
|
|
|
- "text": "INCLUDES"
|
|
|
|
- }
|
|
|
|
- lines.append(tag_line)
|
|
|
|
-
|
|
|
|
- # 构建结果
|
|
|
|
- result = {
|
|
|
|
- "nodes": nodes,
|
|
|
|
- "lines": lines
|
|
|
|
- }
|
|
|
|
- return result
|
|
|
|
|
|
+ # 添加INCLUDES关系
|
|
|
|
+ rel_id = int(rel.id)
|
|
|
|
+ if rel_id not in lines:
|
|
|
|
+ rel_dict = {
|
|
|
|
+ "id": str(rel_id),
|
|
|
|
+ "from": str(nodeid_int),
|
|
|
|
+ "to": str(meta_node_id),
|
|
|
|
+ "text": rel.type
|
|
|
|
+ }
|
|
|
|
+ lines[rel_id] = rel_dict
|
|
|
|
+
|
|
|
|
+ logger.info(f"成功获取血缘关系图谱,ID: {nodeid_int}, 节点数: {len(nodes)}, 关系数: {len(lines)}")
|
|
|
|
+ return {
|
|
|
|
+ "nodes": list(nodes.values()),
|
|
|
|
+ "lines": list(lines.values())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ except Exception as e:
|
|
|
|
+ logger.error(f"获取数据模型血缘关系图谱失败: {str(e)}")
|
|
|
|
+ import traceback
|
|
|
|
+ logger.error(f"错误详情: {traceback.format_exc()}")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
|
|
|
|
|
|
# 数据模型影响图谱
|
|
# 数据模型影响图谱
|
|
def model_impact_graph(nodeid, meta=False):
|
|
def model_impact_graph(nodeid, meta=False):
|
|
"""
|
|
"""
|
|
生成数据模型的影响关系图谱
|
|
生成数据模型的影响关系图谱
|
|
|
|
+ 按照DERIVED_FROM关系进行递归查找,从当前节点作为终点查找所有指向这个终点的节点
|
|
|
|
|
|
Args:
|
|
Args:
|
|
nodeid: 节点ID
|
|
nodeid: 节点ID
|
|
@@ -871,126 +868,124 @@ def model_impact_graph(nodeid, meta=False):
|
|
Returns:
|
|
Returns:
|
|
dict: 包含节点和连线信息的图谱数据
|
|
dict: 包含节点和连线信息的图谱数据
|
|
"""
|
|
"""
|
|
- result = {}
|
|
|
|
-
|
|
|
|
- with connect_graph().session() as session:
|
|
|
|
- # 查询起始模型节点
|
|
|
|
- start_node_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
- RETURN n.name as name, n.en_name as en_name
|
|
|
|
- """
|
|
|
|
-
|
|
|
|
- start_result = session.run(start_node_query, nodeId=nodeid)
|
|
|
|
- start_record = start_result.single()
|
|
|
|
-
|
|
|
|
- if not start_record:
|
|
|
|
- return {"nodes": [], "lines": []}
|
|
|
|
-
|
|
|
|
- # 查询指向当前模型的影响关系(包括数据资源和其他数据模型),表示哪些节点受到当前节点影响
|
|
|
|
- impact_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
- OPTIONAL MATCH (resource:DataResource)-[:DERIVED_FROM]->(n)
|
|
|
|
- OPTIONAL MATCH (model:DataModel)-[:DERIVED_FROM]->(n)
|
|
|
|
- RETURN resource, model
|
|
|
|
- """
|
|
|
|
-
|
|
|
|
- impact_result = session.run(impact_query, nodeId=nodeid)
|
|
|
|
-
|
|
|
|
- nodes = [{"id": str(nodeid), "text": start_record['name'], "type": "model"}]
|
|
|
|
- lines = []
|
|
|
|
-
|
|
|
|
- # 处理影响节点(数据资源和数据模型)
|
|
|
|
- for record in impact_result:
|
|
|
|
- # 处理数据资源节点
|
|
|
|
- if record['resource']:
|
|
|
|
- resource = record['resource']
|
|
|
|
- resource_id = str(resource.id)
|
|
|
|
- resource_name = resource.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建资源节点
|
|
|
|
- resource_node = {
|
|
|
|
- "id": resource_id,
|
|
|
|
- "text": resource_name,
|
|
|
|
- "type": "DataResource"
|
|
|
|
- }
|
|
|
|
- nodes.append(resource_node)
|
|
|
|
-
|
|
|
|
- # 创建资源到模型的关系
|
|
|
|
- line = {
|
|
|
|
- "from": resource_id,
|
|
|
|
- "to": str(nodeid),
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
|
|
+ try:
|
|
|
|
+ with connect_graph().session() as session:
|
|
|
|
+ # 确保nodeid为整数
|
|
|
|
+ try:
|
|
|
|
+ nodeid_int = int(nodeid)
|
|
|
|
+ except (ValueError, TypeError):
|
|
|
|
+ logger.error(f"节点ID不是有效的整数: {nodeid}")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
|
|
- # 处理数据模型节点
|
|
|
|
- if record['model']:
|
|
|
|
- model = record['model']
|
|
|
|
- model_id = str(model.id)
|
|
|
|
- model_name = model.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建模型节点
|
|
|
|
- model_node = {
|
|
|
|
- "id": model_id,
|
|
|
|
- "text": model_name,
|
|
|
|
- "type": "DataModel"
|
|
|
|
- }
|
|
|
|
- nodes.append(model_node)
|
|
|
|
-
|
|
|
|
- # 创建模型到模型的关系
|
|
|
|
- line = {
|
|
|
|
- "from": model_id,
|
|
|
|
- "to": str(nodeid),
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
-
|
|
|
|
- # 处理元数据节点
|
|
|
|
- if meta:
|
|
|
|
- meta_query = """
|
|
|
|
|
|
+ # 查询起始模型节点是否存在
|
|
|
|
+ start_node_query = """
|
|
MATCH (n:DataModel)
|
|
MATCH (n:DataModel)
|
|
WHERE id(n) = $nodeId
|
|
WHERE id(n) = $nodeId
|
|
- MATCH p = (n)-[:INCLUDES]->(meta:DataMeta)
|
|
|
|
- RETURN meta
|
|
|
|
|
|
+ RETURN n
|
|
"""
|
|
"""
|
|
- meta_result = session.run(meta_query, nodeId=nodeid)
|
|
|
|
|
|
|
|
- for record in meta_result:
|
|
|
|
- if 'meta' in record:
|
|
|
|
- meta_node = record['meta']
|
|
|
|
- meta_id = str(meta.id)
|
|
|
|
- meta_name = meta.get('name', '')
|
|
|
|
|
|
+ start_result = session.run(start_node_query, nodeId=nodeid_int)
|
|
|
|
+ start_record = start_result.single()
|
|
|
|
+
|
|
|
|
+ if not start_record:
|
|
|
|
+ logger.error(f"未找到ID为{nodeid_int}的DataModel节点")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
+
|
|
|
|
+ # 递归查找指向当前节点的DERIVED_FROM关系
|
|
|
|
+ cypher = """
|
|
|
|
+ MATCH (target:DataModel)
|
|
|
|
+ WHERE id(target) = $nodeId
|
|
|
|
+ MATCH path = (source)-[:DERIVED_FROM*0..]->(target)
|
|
|
|
+ WHERE source:DataResource OR source:DataModel
|
|
|
|
+ RETURN path
|
|
|
|
+ """
|
|
|
|
+
|
|
|
|
+ result = session.run(cypher, nodeId=nodeid_int)
|
|
|
|
+
|
|
|
|
+ # 收集节点和关系
|
|
|
|
+ nodes = {}
|
|
|
|
+ lines = {}
|
|
|
|
+
|
|
|
|
+ for record in result:
|
|
|
|
+ # 处理路径
|
|
|
|
+ path = record['path']
|
|
|
|
+ logger.debug(f"处理影响路径,长度: {len(path)}, 节点数: {len(path.nodes)}, 关系数: {len(path.relationships)}")
|
|
|
|
+
|
|
|
|
+ # 处理路径中的所有节点
|
|
|
|
+ for node in path.nodes:
|
|
|
|
+ node_id = int(node.id) # 直接转换为整数
|
|
|
|
+ if node_id not in nodes:
|
|
|
|
+ node_dict = serialize_node_properties(node)
|
|
|
|
+ node_dict["id"] = str(node_id)
|
|
|
|
+ node_dict["node_type"] = list(node.labels)[0] if node.labels else ""
|
|
|
|
+ nodes[node_id] = node_dict
|
|
|
|
+ logger.debug(f"添加影响节点: ID={node_id}, 标签={list(node.labels)}")
|
|
|
|
+
|
|
|
|
+ # 处理路径中的所有关系
|
|
|
|
+ for rel in path.relationships:
|
|
|
|
+ rel_id = int(rel.id) # 直接转换为整数
|
|
|
|
+ if rel_id not in lines:
|
|
|
|
+ rel_dict = {
|
|
|
|
+ "id": str(rel_id),
|
|
|
|
+ "from": str(int(rel.start_node.id)),
|
|
|
|
+ "to": str(int(rel.end_node.id)),
|
|
|
|
+ "text": rel.type
|
|
|
|
+ }
|
|
|
|
+ lines[rel_id] = rel_dict
|
|
|
|
+ logger.debug(f"添加影响关系: ID={rel_id}, 类型={rel.type}, 从{int(rel.start_node.id)}到{int(rel.end_node.id)}")
|
|
|
|
+
|
|
|
|
+ # 如果需要元数据,查询INCLUDES关系
|
|
|
|
+ if meta:
|
|
|
|
+ meta_cypher = """
|
|
|
|
+ MATCH (target:DataModel)-[r:INCLUDES]->(meta:DataMeta)
|
|
|
|
+ WHERE id(target) = $nodeId
|
|
|
|
+ RETURN target, r, meta
|
|
|
|
+ """
|
|
|
|
+ meta_result = session.run(meta_cypher, nodeId=nodeid_int)
|
|
|
|
+
|
|
|
|
+ for meta_record in meta_result:
|
|
|
|
+ target_node = meta_record['target']
|
|
|
|
+ rel = meta_record['r']
|
|
|
|
+ meta_node = meta_record['meta']
|
|
|
|
|
|
- # 创建元数据节点
|
|
|
|
- meta_node = {
|
|
|
|
- "id": meta_id,
|
|
|
|
- "text": meta_name,
|
|
|
|
- "type": "DataMeta"
|
|
|
|
- }
|
|
|
|
- nodes.append(meta_node)
|
|
|
|
|
|
+ # 添加元数据节点
|
|
|
|
+ meta_node_id = int(meta_node.id)
|
|
|
|
+ if meta_node_id not in nodes:
|
|
|
|
+ node_dict = serialize_node_properties(meta_node)
|
|
|
|
+ node_dict["id"] = str(meta_node_id)
|
|
|
|
+ node_dict["node_type"] = list(meta_node.labels)[0] if meta_node.labels else ""
|
|
|
|
+ nodes[meta_node_id] = node_dict
|
|
|
|
|
|
- # 创建模型到元数据的标签关系
|
|
|
|
- tag_line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": meta_id,
|
|
|
|
- "text": "INCLUDES"
|
|
|
|
- }
|
|
|
|
- lines.append(tag_line)
|
|
|
|
-
|
|
|
|
- # 构建结果
|
|
|
|
- result = {
|
|
|
|
- "nodes": nodes,
|
|
|
|
- "lines": lines
|
|
|
|
- }
|
|
|
|
- return result
|
|
|
|
|
|
+ # 添加INCLUDES关系
|
|
|
|
+ rel_id = int(rel.id)
|
|
|
|
+ if rel_id not in lines:
|
|
|
|
+ rel_dict = {
|
|
|
|
+ "id": str(rel_id),
|
|
|
|
+ "from": str(nodeid_int),
|
|
|
|
+ "to": str(meta_node_id),
|
|
|
|
+ "text": rel.type
|
|
|
|
+ }
|
|
|
|
+ lines[rel_id] = rel_dict
|
|
|
|
+
|
|
|
|
+ logger.info(f"成功获取影响关系图谱,ID: {nodeid_int}, 节点数: {len(nodes)}, 关系数: {len(lines)}")
|
|
|
|
+ return {
|
|
|
|
+ "nodes": list(nodes.values()),
|
|
|
|
+ "lines": list(lines.values())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ except Exception as e:
|
|
|
|
+ logger.error(f"获取数据模型影响关系图谱失败: {str(e)}")
|
|
|
|
+ import traceback
|
|
|
|
+ logger.error(f"错误详情: {traceback.format_exc()}")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
|
|
|
|
|
|
# 数据模型全部图谱
|
|
# 数据模型全部图谱
|
|
def model_all_graph(nodeid, meta=False):
|
|
def model_all_graph(nodeid, meta=False):
|
|
"""
|
|
"""
|
|
生成数据模型的所有关系图谱
|
|
生成数据模型的所有关系图谱
|
|
|
|
+ 分别调用model_impact_graph查找影响关系,调用model_kinship_graph查找血缘关系,
|
|
|
|
+ 然后合并两部分数据返回
|
|
|
|
|
|
Args:
|
|
Args:
|
|
nodeid: 节点ID
|
|
nodeid: 节点ID
|
|
@@ -999,171 +994,55 @@ def model_all_graph(nodeid, meta=False):
|
|
Returns:
|
|
Returns:
|
|
dict: 包含节点和连线信息的图谱数据
|
|
dict: 包含节点和连线信息的图谱数据
|
|
"""
|
|
"""
|
|
- result = {}
|
|
|
|
-
|
|
|
|
- with connect_graph().session() as session:
|
|
|
|
- # 查询起始模型节点
|
|
|
|
- start_node_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
- RETURN n.name as name, n.en_name as en_name
|
|
|
|
- """
|
|
|
|
|
|
+ try:
|
|
|
|
+ # 获取血缘关系图谱
|
|
|
|
+ kinship_data = model_kinship_graph(nodeid, meta)
|
|
|
|
|
|
- start_result = session.run(start_node_query, nodeId=nodeid)
|
|
|
|
- start_record = start_result.single()
|
|
|
|
|
|
+ # 获取影响关系图谱
|
|
|
|
+ impact_data = model_impact_graph(nodeid, meta)
|
|
|
|
|
|
- if not start_record:
|
|
|
|
- return {"nodes": [], "lines": []}
|
|
|
|
|
|
+ # 合并节点数据,使用字典去重
|
|
|
|
+ merged_nodes = {}
|
|
|
|
+ merged_lines = {}
|
|
|
|
|
|
- # 查询与模型关联的所有DERIVED_FROM关系(双向,包括数据资源和其他数据模型)
|
|
|
|
- all_relations_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
|
|
+ # 添加血缘关系的节点和连线
|
|
|
|
+ if kinship_data and 'nodes' in kinship_data:
|
|
|
|
+ for node in kinship_data['nodes']:
|
|
|
|
+ node_id = node.get('id')
|
|
|
|
+ if node_id:
|
|
|
|
+ merged_nodes[node_id] = node
|
|
|
|
|
|
- // 查询当前节点指向的节点(血缘关系)
|
|
|
|
- OPTIONAL MATCH (n)-[:DERIVED_FROM]->(outbound_resource:DataResource)
|
|
|
|
- OPTIONAL MATCH (n)-[:DERIVED_FROM]->(outbound_model:DataModel)
|
|
|
|
|
|
+ if kinship_data and 'lines' in kinship_data:
|
|
|
|
+ for line in kinship_data['lines']:
|
|
|
|
+ line_id = line.get('id')
|
|
|
|
+ if line_id:
|
|
|
|
+ merged_lines[line_id] = line
|
|
|
|
|
|
- // 查询指向当前节点的节点(影响关系)
|
|
|
|
- OPTIONAL MATCH (inbound_resource:DataResource)-[:DERIVED_FROM]->(n)
|
|
|
|
- OPTIONAL MATCH (inbound_model:DataModel)-[:DERIVED_FROM]->(n)
|
|
|
|
|
|
+ # 添加影响关系的节点和连线
|
|
|
|
+ if impact_data and 'nodes' in impact_data:
|
|
|
|
+ for node in impact_data['nodes']:
|
|
|
|
+ node_id = node.get('id')
|
|
|
|
+ if node_id:
|
|
|
|
+ merged_nodes[node_id] = node
|
|
|
|
|
|
- RETURN outbound_resource, outbound_model, inbound_resource, inbound_model
|
|
|
|
- """
|
|
|
|
-
|
|
|
|
- relations_result = session.run(all_relations_query, nodeId=nodeid)
|
|
|
|
-
|
|
|
|
- nodes = [{"id": str(nodeid), "text": start_record['name'], "type": "DataModel"}]
|
|
|
|
- lines = []
|
|
|
|
|
|
+ if impact_data and 'lines' in impact_data:
|
|
|
|
+ for line in impact_data['lines']:
|
|
|
|
+ line_id = line.get('id')
|
|
|
|
+ if line_id:
|
|
|
|
+ merged_lines[line_id] = line
|
|
|
|
|
|
- # 处理所有DERIVED_FROM关系节点
|
|
|
|
- for record in relations_result:
|
|
|
|
- # 处理当前节点指向的数据资源(血缘关系)
|
|
|
|
- if record['outbound_resource']:
|
|
|
|
- resource = record['outbound_resource']
|
|
|
|
- resource_id = str(resource.id)
|
|
|
|
- resource_name = resource.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建资源节点
|
|
|
|
- resource_node = {
|
|
|
|
- "id": resource_id,
|
|
|
|
- "text": resource_name,
|
|
|
|
- "type": "DataResource"
|
|
|
|
- }
|
|
|
|
- nodes.append(resource_node)
|
|
|
|
-
|
|
|
|
- # 创建当前模型到资源的关系
|
|
|
|
- line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": resource_id,
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
-
|
|
|
|
- # 处理当前节点指向的数据模型(血缘关系)
|
|
|
|
- if record['outbound_model']:
|
|
|
|
- model = record['outbound_model']
|
|
|
|
- model_id = str(model.id)
|
|
|
|
- model_name = model.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建模型节点
|
|
|
|
- model_node = {
|
|
|
|
- "id": model_id,
|
|
|
|
- "text": model_name,
|
|
|
|
- "type": "DataModel"
|
|
|
|
- }
|
|
|
|
- nodes.append(model_node)
|
|
|
|
-
|
|
|
|
- # 创建当前模型到模型的关系
|
|
|
|
- line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": model_id,
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
-
|
|
|
|
- # 处理指向当前节点的数据资源(影响关系)
|
|
|
|
- if record['inbound_resource']:
|
|
|
|
- resource = record['inbound_resource']
|
|
|
|
- resource_id = str(resource.id)
|
|
|
|
- resource_name = resource.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建资源节点
|
|
|
|
- resource_node = {
|
|
|
|
- "id": resource_id,
|
|
|
|
- "text": resource_name,
|
|
|
|
- "type": "DataResource"
|
|
|
|
- }
|
|
|
|
- nodes.append(resource_node)
|
|
|
|
-
|
|
|
|
- # 创建资源到当前模型的关系
|
|
|
|
- line = {
|
|
|
|
- "from": resource_id,
|
|
|
|
- "to": str(nodeid),
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
-
|
|
|
|
- # 处理指向当前节点的数据模型(影响关系)
|
|
|
|
- if record['inbound_model']:
|
|
|
|
- model = record['inbound_model']
|
|
|
|
- model_id = str(model.id)
|
|
|
|
- model_name = model.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建模型节点
|
|
|
|
- model_node = {
|
|
|
|
- "id": model_id,
|
|
|
|
- "text": model_name,
|
|
|
|
- "type": "DataModel"
|
|
|
|
- }
|
|
|
|
- nodes.append(model_node)
|
|
|
|
-
|
|
|
|
- # 创建模型到当前模型的关系
|
|
|
|
- line = {
|
|
|
|
- "from": model_id,
|
|
|
|
- "to": str(nodeid),
|
|
|
|
- "text": "DERIVED_FROM"
|
|
|
|
- }
|
|
|
|
- lines.append(line)
|
|
|
|
-
|
|
|
|
- # 处理元数据节点
|
|
|
|
- if meta:
|
|
|
|
- meta_query = """
|
|
|
|
- MATCH (n:DataModel)
|
|
|
|
- WHERE id(n) = $nodeId
|
|
|
|
- MATCH p = (n)-[:INCLUDES]->(meta:DataMeta)
|
|
|
|
- RETURN meta
|
|
|
|
- """
|
|
|
|
- meta_result = session.run(meta_query, nodeId=nodeid)
|
|
|
|
-
|
|
|
|
- for record in meta_result:
|
|
|
|
- if 'meta' in record:
|
|
|
|
- meta_node = record['meta']
|
|
|
|
- meta_id = str(meta.id)
|
|
|
|
- meta_name = meta.get('name', '')
|
|
|
|
-
|
|
|
|
- # 创建元数据节点
|
|
|
|
- meta_node = {
|
|
|
|
- "id": meta_id,
|
|
|
|
- "text": meta_name,
|
|
|
|
- "type": "DataMeta"
|
|
|
|
- }
|
|
|
|
- nodes.append(meta_node)
|
|
|
|
-
|
|
|
|
- # 创建模型到元数据的关系
|
|
|
|
- tag_line = {
|
|
|
|
- "from": str(nodeid),
|
|
|
|
- "to": meta_id,
|
|
|
|
- "text": "INCLUDES"
|
|
|
|
- }
|
|
|
|
- lines.append(tag_line)
|
|
|
|
-
|
|
|
|
- # 构建结果
|
|
|
|
|
|
+ # 构建最终结果
|
|
result = {
|
|
result = {
|
|
- "nodes": nodes,
|
|
|
|
- "lines": lines
|
|
|
|
|
|
+ "nodes": list(merged_nodes.values()),
|
|
|
|
+ "lines": list(merged_lines.values())
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ logger.info(f"成功获取完整关系图谱,ID: {nodeid}, 节点数: {len(merged_nodes)}, 关系数: {len(merged_lines)}")
|
|
return result
|
|
return result
|
|
|
|
+
|
|
|
|
+ except Exception as e:
|
|
|
|
+ logger.error(f"获取数据模型完整关系图谱失败: {str(e)}")
|
|
|
|
+ return {"nodes": [], "lines": []}
|
|
|
|
|
|
|
|
|
|
# 更新数据模型
|
|
# 更新数据模型
|