图查询进阶

概述

本文档介绍 UModel 中的高级图查询功能,主要涵盖 Cypher 查询语言的使用,包括基础查询、多级跳跃、聚合统计、路径模式查找等高级特性,以及数据完整性处理和性能优化建议。

应用案例

当前应用案例相关素材,请参考:umodel.zip

Cypher查询详解

基础语法结构

Cypher采用声明式查询语言,遵循SQL类似的三段式结构:

.topo | graph-call cypher(`
    MATCH <图查询路径>
    WHERE <筛选条件> 
    RETURN <返回内容>
`)

基础三段式查询

单节点查询

-- 查询特定类型的所有节点
.topo | graph-call cypher(`
    MATCH (n {__entity_type__:"apm.service"})
    WHERE n.__domain__ STARTS WITH 'a' AND n.__entity_type__ = "apm.service"
    RETURN n
`)

相比 graph-match 的优势

  • 支持 WHERE 子句进行复杂筛选。

  • MATCH 可以只包含节点,无需指定关系。

  • 支持更多的属性查询(__entity_type____domain__等)。

关系查询

-- 查询服务间调用关系
.topo | graph-call cypher(`
    MATCH (src:``apm@apm.service``)-[e:calls]->(dest:``apm@apm.service``)
    WHERE src.cluster = 'production' AND dest.cluster = 'production'
    RETURN src.service_name, dest.service_name, e.__type__
`)

多级跳查询

基础多级跳语法

-- 查找2-3跳的调用链路
.topo | graph-call cypher(`
    MATCH (src {__entity_type__:"acs.service"})-[e:calls*2..3]->(dest)
    WHERE dest.__domain__ = 'acs'
    RETURN src, dest, dest.__entity_type__
`)

重要说明

  • 多级跳规则是左闭右开*2..3表示只查询2跳。

  • *1..3表示1跳或2跳,不包括3跳。

  • 单个数字*3表示恰好3跳。

多级跳应用场景

连通性分析

-- 查找服务间的可达路径
.topo | graph-call cypher(`
    MATCH (startNode:``apm@apm.service`` {service_name: 'gateway'})
          -[path:calls*1..4]->
          (endNode:``apm@apm.service`` {service_name: 'database'})
    RETURN startNode.service_name, length(path) as hop_count, endNode.service_name
`)

影响链分析

-- 分析故障传播路径
.topo | graph-call cypher(`
    MATCH (failed:``apm@apm.service`` {status: 'error'})
          -[impact:depends_on*1..3]->
          (affected)
    WHERE affected.__entity_type__ = 'apm.service'
    RETURN failed.service_name, 
           length(impact) as impact_distance,
           affected.service_name
    ORDER BY impact_distance ASC
`)

节点聚合统计

基础聚合查询

-- 统计不同域的服务数量
.topo | graph-call cypher(`
    MATCH (src {__entity_type__:"apm.service"})-[e:calls*2..3]->(dest)
    WHERE dest.__domain__ = 'apm'
    RETURN src, count(src) as connection_count
`)

适用场景

  • 连通分量分析:识别图中的连通子图。

  • 中心度计算:找出网络中的关键节点。

  • 集群检测:发现紧密连接的节点群组。

路径模式查找

复杂路径模式

-- 查找特定的拓扑模式
.topo | graph-call cypher(`
    MATCH (src:``acs@acs.vpc.vswitch``)-[e1]->(n1)<-[e2]-(n2)-[e3]->(n3)
    WHERE NOT (src = n2 AND e1.__type__ = e2.__type__) 
        AND n1.__entity_type__ <> n3.__entity_type__ 
        AND NOT (src)<-[e1:``calls``]-(n1)
    RETURN src, e1.__type__, n1, e2.__type__, n2, e3.__type__, n3
`)

适用场景

  • 安全审计:发现异常的网络连接模式。

  • 合规检查:验证网络架构的合规性。

  • 模式检测:识别特定的系统拓扑结构。

完整Cypher功能:支持自定义节点属性

自由属性查找

基于实体自定义属性查询

-- 使用实体的自定义属性进行查询
.topo | graph-call cypher(`
    MATCH (n:``acs@acs.alb.listener`` {ListenerId: 'lsn-rxp574lk5vu3gos29g'})-[e]->(d)
    WHERE d.vSwitchId CONTAINS 'vsw-bp1gvyids4uwo20crmp15' 
        AND d.user_id IN ['1654218965343050', '2'] 
        AND d.dnsName ENDS WITH '.com'
    RETURN n, e, d
`)

属性条件组合

-- 复杂的属性条件查询
.topo | graph-call cypher(`
    MATCH (instance:``acs@acs.ecs.instance``)
    WHERE instance.instance_type STARTS WITH 'ecs.c6'
        AND instance.cpu_cores >= 4
        AND instance.memory_gb >= 8
        AND instance.status = 'Running'
        AND instance.create_time > '2024-01-01'
    RETURN 
        instance.instance_id,
        instance.instance_type,
        instance.cpu_cores,
        instance.memory_gb,
        instance.availability_zone
    ORDER BY instance.cpu_cores DESC, instance.memory_gb DESC
`)

多级路径输出

路径信息返回

-- 返回多级跳的完整路径信息
.topo | graph-call cypher(`
    MATCH (n:``acs@acs.alb.listener``)-[e:``calls``*2..3]-()
    RETURN e
`)

路径结果格式

  • 返回路径中所有边的数组。

  • 每个边包含完整的起止节点和属性信息。

  • 支持路径长度和路径权重计算。

真实业务场景应用

1. 细粒度链路控制的连通性查找

跨网络层级的连接分析

-- 查找ECS实例到负载均衡器的连接路径
.topo | graph-call cypher(`
    MATCH (start_node:``acs@acs.ecs.instance``)
          -[e*2..3]-
          (mid_node {ListenerName: 'entity-test-listener-zuozhi'})
          -[e2*1..2]-
          (end_node:``acs@acs.alb.loadbalancer``)
    WHERE start_node.__entity_id__ <> mid_node.__entity_id__ 
        AND start_node.__entity_type__ <> mid_node.__entity_type__
    RETURN 
        start_node.instance_name, 
        e, 
        mid_node.__entity_type__, 
        e2, 
        end_node.instance_name
`)

服务网格连接分析

-- 分析微服务网格中的流量路径
.topo | graph-call cypher(`
    MATCH (client:``apm@apm.service``)
          -[request:calls]->
          (gateway:``apm@apm.gateway``)
          -[route:routes_to]->
          (service:``apm@apm.service``)
          -[backend:calls]->
          (database:``middleware@database``)
    WHERE client.environment = 'production'
        AND request.protocol = 'HTTP'
        AND route.load_balancer_type = 'round_robin'
    RETURN 
        client.service_name,
        gateway.gateway_name,
        service.service_name,
        database.database_name,
        request.request_count,
        backend.connection_pool_size
`)

2. 拓扑图构建

等价的getNeighborNodes查询

-- 传统方式
.topo | graph-call getNeighborNodes(
  'sequence', 5, 
  [(:"acs@acs.alb.listener" {__entity_id__: '0b04e22d024b31a4cb880c0b2c652638'})]
)

-- Cypher等价写法
.topo | graph-call cypher(`
    MATCH (n:``acs@acs.alb.listener`` {__entity_id__: '0b04e22d024b31a4cb880c0b2c652638'})
          -[e1*1..6]->(),
          (n:``acs@acs.alb.listener`` {__entity_id__: '0b04e22d024b31a4cb880c0b2c652638'})
          <-[e2*1..6]-()
    RETURN n, e1, e2
`)

3. 故障诊断和影响分析

级联故障分析

-- 分析服务故障的级联影响
.topo | graph-call cypher(`
    MATCH (failed_service:``apm@apm.service`` {status: 'error'})
    MATCH cascade_path = (failed_service)-[impact:depends_on*1..4]->(affected_service)
    WHERE affected_service.__entity_type__ = 'apm.service'
    RETURN 
        failed_service.service_name as root_cause,
        length(cascade_path) as impact_depth,
        affected_service.service_name as affected_service,
        affected_service.criticality_level,
        impact as dependency_chain
    ORDER BY impact_depth ASC, affected_service.criticality_level DESC
`)

数据完整性和故障排查

数据缺失场景分析

UModel

Entity

Topo

查询表现

正常

正常

正常

正常情况,所有查询都可用。

正常

正常

缺失 

无法进行图查询。

正常

缺失 

正常

关系正常,但节点信息为空。

正常

缺失 

缺失 

完全无法查询,虽有Schema但无数据。

缺失 

正常

正常

无法查询,纯拓扑模式可正常工作。

缺失 

正常

缺失 

完全无法查询。

缺失 

缺失 

正常

无法查询,pure-topo可正常工作。

缺失 

缺失 

缺失 

完全无法查询。

pure-topo模式

Entity数据不完整时,可以使用pure-topo模式,仅依赖关系数据进行查询:

-- 标准模式(需要完整数据)
.topo | graph-call cypher(`
    MATCH (n:``acs@acs.alb.listener`` {ListenerId: 'lsn-123'})-[e]->(d)
    WHERE d.vSwitchId CONTAINS 'vsw-456'
    RETURN n, e, d
`)

-- pure-topo模式(仅依赖关系数据)
.topo | graph-call cypher(`
    MATCH (n:``acs@acs.alb.listener``)-[e]->(d)
    RETURN n, e, d
`, 'pure-topo')

pure-topo模式特点

  • 优势:不依赖Entity数据,查询速度更快。

  • 限制:无法使用实体的自定义属性进行筛选。

  • 适用:拓扑结构分析、关系验证等场景。

数据质量检查

检查数据完整性

-- 检查实体和关系的数据完整性
.topo | graph-call cypher(`
    MATCH (n)-[e]->(m)
    RETURN 
        count(DISTINCT n) as unique_nodes,
        count(DISTINCT e) as unique_edges,
        count(DISTINCT e.__type__) as edge_types,
        collect(DISTINCT n.__entity_type__)[0..10] as node_types_sample
`)

识别悬挂关系

-- 查找指向不存在实体的关系
.let topoData = .topo | graph-call cypher(`
        MATCH ()-[e]->()
        RETURN e
    `)
    | extend startNodeId = json_extract_scalar(e, '$.startNodeId'), endNodeId = json_extract_scalar(e, '$.endNodeId'), relationType = json_extract_scalar(e, '$.type')
    | project startNodeId, endNodeId, relationType;
--$topoData
.let entityData = .entity with(domain='*', type='*') 
| project __entity_id__, __entity_type__, __domain__
| extend matchedId = concat(__domain__, '@', __entity_type__, ':', __entity_id__)
| join -kind='left' $topoData on matchedId = $topoData.endNodeId
| project matchedId, startNodeId, endNodeId, relationType
| extend status = COALESCE(startNodeId, '悬挂')
| where status = '悬挂';
$entityData

性能优化建议

1. 查询结构优化

合理使用索引

-- 优化前:全表扫描
.topo | graph-call cypher(`
    MATCH (n) WHERE n.service_name = 'web-app'
    RETURN n
`)

-- 优化后:使用标签索引
.topo | graph-call cypher(`
    MATCH (n:``apm@apm.service`` {service_name: 'web-app'})
    RETURN n
`)

早期条件过滤

-- 优化前:后期过滤
.topo | graph-call cypher(`
    MATCH (start)-[*1..5]->(endNode)
    WHERE start.environment = 'production' AND endNode.status = 'active'
    RETURN start, endNode
`)

-- 优化后:早期过滤
.topo | graph-call cypher(`
    MATCH (start {environment: 'production'})-[*1..5]->(endNode {status: 'active'})
    RETURN start, endNode
`)

2. 结果集控制

分页和限制

-- 使用LIMIT控制结果数量
.topo | graph-call cypher(`
    MATCH (service:``apm@apm.service``)-[calls:calls]->(target)
    WHERE calls.request_count > 1000
    RETURN service.service_name, target.service_name, calls.request_count
    ORDER BY calls.request_count DESC
    LIMIT 50
`)

结果采样

-- 对大结果集进行采样
.topo | graph-call cypher(`
    MATCH (n:``apm@apm.service``)
    RETURN n.service
    LIMIT 100
`)
| extend seed = random()
| where seed < 0.1

3. 多级跳优化

控制跳跃深度

-- 避免过深的遍历
.topo | graph-call cypher(`
    MATCH (start)-[path*1..3]->(endNode)
    WHERE length(path) <= 2
    RETURN path
`)

使用方向性优化

-- 利用关系方向减少搜索空间
.topo | graph-call cypher(`
    MATCH (start)-[calls:calls*1..3]->(endNode)  -- 明确方向
    WHERE start.__entity_type__ = 'apm.service'
    RETURN start, endNode
`)