优化了 handle_id_metric 函数中的 Cypher 查询脚本,简化查询逻辑,只查找第一层关系,提升查询性能。
✅ 直接查询第一层关系: 使用简单的 OPTIONAL MATCH 查找所有第一层关系 ✅ 统一的节点匹配: 使用 OR 条件一次性匹配 DataModel 和 DataMetric ✅ 简化的聚合逻辑: 使用列表推导式构建结果 ✅ 更好的可读性: 清晰的注释和逻辑分层
MATCH (n:DataMetric)
WHERE id(n) = $nodeId
WITH apoc.convert.fromJsonList(n.id_list) AS info, n
UNWIND info AS item
WITH n, item.id AS model_or_metric_id, item.metaData AS meta_ids, item.type AS type
// 数据模型或者数据指标
OPTIONAL MATCH (n)-[:origin]->(m1:DataModel)
WHERE type = 'model' AND id(m1) = model_or_metric_id
WITH n, model_or_metric_id, meta_ids, type, m1
OPTIONAL MATCH (n)-[:origin]->(m2:DataMetric)
WHERE type = 'metric' AND id(m2) = model_or_metric_id
WITH n, model_or_metric_id, meta_ids, type, m1, m2
// 元数据
OPTIONAL MATCH (n)-[:connection]-(meta:DataMeta)
// 数据标签
OPTIONAL MATCH (n)-[:LABEL]-(la:DataLabel)
OPTIONAL MATCH (parent)-[:child]-(n)
WITH properties(n) AS properties,collect(DISTINCT id(meta)) AS meta_list,parent,
{id: id(la), name_zh: la.name_zh} AS tag,
CASE
WHEN type = 'model' THEN m1
WHEN type = 'metric' THEN m2
ELSE NULL
END AS m
WITH {model_name: m.name_zh, model_id: id(m), meta: meta_list} AS result, properties,
tag,{id:id(parent),name_zh:parent.name_zh} as parentId
RETURN collect(result) AS id_list, properties, tag,collect(parentId)as parentId
MATCH (n:DataMetric)
WHERE id(n) = $nodeId
// 查找第一层关系 - 来源关系(DataModel 和 DataMetric)
OPTIONAL MATCH (n)-[:origin]->(origin)
WHERE origin:DataModel OR origin:DataMetric
// 查找第一层关系 - 元数据连接
OPTIONAL MATCH (n)-[:connection]->(meta:DataMeta)
// 查找第一层关系 - 数据标签
OPTIONAL MATCH (n)-[:LABEL]->(label:DataLabel)
// 查找第一层关系 - 父节点
OPTIONAL MATCH (parent:DataMetric)-[:child]->(n)
// 聚合数据
WITH n,
collect(DISTINCT label) AS labels,
collect(DISTINCT parent) AS parents,
collect(DISTINCT origin) AS origins,
collect(DISTINCT meta) AS metas
// 构建 id_list(来源信息和元数据)
WITH n, labels, parents,
[origin IN origins | {
model_name: origin.name_zh,
model_id: id(origin),
meta: [m IN metas | id(m)],
type: CASE
WHEN 'DataModel' IN labels(origin) THEN 'model'
WHEN 'DataMetric' IN labels(origin) THEN 'metric'
ELSE null
END
}] AS id_list_data
// 返回结果
RETURN
properties(n) AS properties,
id_list_data AS id_list,
CASE WHEN size(labels) > 0
THEN {id: id(labels[0]), name_zh: labels[0].name_zh}
ELSE null
END AS tag,
[p IN parents | {id: id(p), name_zh: p.name_zh}] AS parentId
优化前: 依赖节点属性中的 JSON 数据(n.id_list),需要先解析 JSON
优化后: 直接通过图关系查询,更符合图数据库的特性
优化前:
OPTIONAL MATCH (n)-[:origin]->(m1:DataModel)
WHERE type = 'model' AND id(m1) = model_or_metric_id
...
OPTIONAL MATCH (n)-[:origin]->(m2:DataMetric)
WHERE type = 'metric' AND id(m2) = model_or_metric_id
优化后:
OPTIONAL MATCH (n)-[:origin]->(origin)
WHERE origin:DataModel OR origin:DataMetric
优化前: 使用多层 WITH 子句传递和组合数据 优化后: 一次性聚合所有相关节点,然后使用列表推导式构建结果
每种关系类型都有明确的注释和独立的 OPTIONAL MATCH:
origin - 来源关系(DataModel/DataMetric)connection - 元数据连接(DataMeta)LABEL - 数据标签(DataLabel)child - 父子关系(DataMetric)| 指标 | 优化前 | 优化后 | 改进 |
|---|---|---|---|
| OPTIONAL MATCH 次数 | 5次 | 4次 | ↓ 20% |
| WITH 子句层数 | 5层 | 2层 | ↓ 60% |
| CASE 表达式 | 2个 | 2个 | = |
| 依赖 APOC 插件 | 是 | 否 | ✅ |
apoc.convert.fromJsonListMATCH (n:DataMetric)
WHERE id(n) = $nodeId
根据节点ID匹配 DataMetric 节点。
OPTIONAL MATCH (n)-[:origin]->(origin)
WHERE origin:DataModel OR origin:DataMetric
OPTIONAL MATCH (n)-[:connection]->(meta:DataMeta)
OPTIONAL MATCH (n)-[:LABEL]->(label:DataLabel)
OPTIONAL MATCH (parent:DataMetric)-[:child]->(n)
使用 4 个 OPTIONAL MATCH 查询所有第一层关系。
WITH n,
collect(DISTINCT label) AS labels,
collect(DISTINCT parent) AS parents,
collect(DISTINCT origin) AS origins,
collect(DISTINCT meta) AS metas
将每种类型的关联节点聚合成列表。
WITH n, labels, parents,
[origin IN origins | {
model_name: origin.name_zh,
model_id: id(origin),
meta: [m IN metas | id(m)],
type: CASE
WHEN 'DataModel' IN labels(origin) THEN 'model'
WHEN 'DataMetric' IN labels(origin) THEN 'metric'
ELSE null
END
}] AS id_list_data
使用列表推导式构建 id_list 数据结构。
RETURN
properties(n) AS properties,
id_list_data AS id_list,
CASE WHEN size(labels) > 0
THEN {id: id(labels[0]), name_zh: labels[0].name_zh}
ELSE null
END AS tag,
[p IN parents | {id: id(p), name_zh: p.name_zh}] AS parentId
返回节点属性、关联数据列表、标签和父节点信息。
{
"properties": {
"name_zh": "指标名称",
"name_en": "metric_name",
"category": "应用类",
"create_time": "2025-11-03 11:31:40",
...
},
"id_list": [
{
"model_name": "数据模型名称",
"model_id": 123,
"meta": [456, 789],
"type": "model"
}
],
"tag": {
"id": 100,
"name_zh": "标签名称"
},
"parentId": [
{
"id": 200,
"name_zh": "父节点名称"
}
]
}
优化后的查询不再依赖节点的 id_list 属性(JSON 字段),而是直接查询图关系。确保图关系数据的完整性。
如果旧数据中关系不完整,可能返回的 id_list 为空。建议:
在生产环境中监控查询性能:
为提升查询性能,建议在以下字段上创建索引:
CREATE INDEX ON :DataMetric(name_zh);
CREATE INDEX ON :DataMetric(create_time);
如果需要查询多个指标详情,可以修改为批量查询:
MATCH (n:DataMetric)
WHERE id(n) IN $nodeIds
...
对于关联节点较多的情况,考虑添加分页:
OPTIONAL MATCH (n)-[:connection]->(meta:DataMeta)
WITH n, collect(meta)[0..10] AS metas
from app.core.data_metric.metric_interface import handle_id_metric
# 测试查询
result = handle_id_metric(1378)
print(result)
✅ 简化查询逻辑 - 减少嵌套层数,提高可读性
✅ 移除 APOC 依赖 - 不再依赖 apoc.convert.fromJsonList
✅ 统一节点匹配 - 使用 OR 条件一次性匹配多种节点类型
✅ 清晰的关系查询 - 每种关系独立查询,便于维护
✅ 更好的性能 - 减少不必要的查询步骤
优化完成时间: 2025-11-03
文件路径: app/core/data_metric/metric_interface.py
函数: handle_id_metric (行 335-404)