Overview
UModel supports advanced graph queries through the Cypher query language, including basic queries, multi-hop traversals, aggregation statistics, and path pattern matching. This topic also covers data integrity handling and performance optimization.
Detailed explanation of Cypher queries
Basic syntax structure
Cypher is a declarative query language. It follows a three-part structure similar to SQL:
.topo | graph-call cypher(`
MATCH <graph query path>
WHERE <filter condition>
RETURN <return content>
`)
Basic three-part queries
Single-node query
-- Query all nodes of a specific type
.topo | graph-call cypher(`
MATCH (n {__entity_type__:"apm.service"})
WHERE n.__domain__ STARTS WITH 'a' AND n.__entity_type__ = "apm.service"
RETURN n
`)
Advantages over graph-match:
-
Supports the WHERE clause for complex filtering.
-
MATCH can contain only nodes without specifying relationships.
-
Supports queries on more properties, such as
__entity_type__and__domain__.
Relationship query
-- Query the call relationships between services
.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__
`)
Multi-hop queries
Basic multi-hop syntax
-- Find call chains with 2 to 3 hops
.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__
`)
Important:
-
The multi-hop syntax is left-inclusive and right-exclusive. For example,
*2..3queries for exactly two hops. -
*1..3queries for one or two hops, but not three hops. -
A single number, such as
*3, queries for exactly three hops.
Multi-hop query scenarios
Connectivity analysis:
-- Find reachable paths between services
.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
`)
Impact chain analysis:
-- Analyze fault propagation paths
.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
`)
Node aggregation statistics
Basic aggregation query
-- Count the number of services in different domains
.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
`)
Scenarios:
-
Connected component analysis: Identify connected subgraphs.
-
Centrality calculation: Find key nodes in the network.
-
Cluster detection: Discover tightly connected node groups.
Path pattern matching
Complex path patterns
-- Find specific topology patterns
.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
`)
Scenarios:
-
Security audit: Detect abnormal network connectivity patterns.
-
Compliance check: Verify that the network architecture meets compliance requirements.
-
Pattern detection: Identify specific topology structures.
Full Cypher features: Support for custom node properties
Free property search
Query based on custom entity properties
-- Query using custom properties of entities
.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
`)
Combined property conditions
-- Query with complex property conditions
.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
`)
Multi-level path output
Return path information
-- Return the full path information for multi-hop traversals
.topo | graph-call cypher(`
MATCH (n:``acs@acs.alb.listener``)-[e:``calls``*2..3]-()
RETURN e
`)
Path result format:
-
Returns an array of all edges in the path.
-
Each edge includes the start node, end node, and their properties.
-
Supports path length and path weight calculations.
Real-world business scenarios
1. Fine-grained connectivity search
Cross-network-layer connection analysis
-- Find the connection path from an ECS instance to a Server Load Balancer
.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
`)
Service mesh connection analysis
-- Analyze traffic paths in a microservice mesh
.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. Topology graph construction
Query equivalent to getNeighborNodes
-- Traditional method
.topo | graph-call getNeighborNodes(
'sequence', 5,
[(:"acs@acs.alb.listener" {__entity_id__: '0b04e22d024b31a4cb880c0b2c652638'})]
)
-- Equivalent Cypher query
.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. Fault diagnosis and impact analysis
Cascading failure analysis
-- Analyze the cascading impact of a service failure
.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
`)
Data integrity and troubleshooting
Analysis of missing data scenarios
|
UModel |
Entity |
Topo |
Query behavior |
|
Normal |
Normal |
Normal |
Normal. All queries are available. |
|
Normal |
Normal |
Missing |
Graph queries fail. |
|
Normal |
Missing |
Normal |
Relationships are normal, but node information is empty. |
|
Normal |
Missing |
Missing |
Queries fail. The schema exists, but no data is available. |
|
Missing |
Normal |
Normal |
Queries fail. The pure-topo mode works as expected. |
|
Missing |
Normal |
Missing |
Queries fail. |
|
Missing |
Missing |
Normal |
Queries fail. The pure-topo mode works as expected. |
|
Missing |
Missing |
Missing |
Queries fail. |
pure-topo mode
When entity data is incomplete, use pure-topo mode to query based only on relationship data:
-- Standard mode (requires complete data)
.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 mode (relies only on relationship data)
.topo | graph-call cypher(`
MATCH (n:``acs@acs.alb.listener``)-[e]->(d)
RETURN n, e, d
`, 'pure-topo')
Features of pure-topo mode:
-
Advantage: Independent of entity data, resulting in faster queries.
-
Limitation: Cannot filter by custom entity properties.
-
Applicable scenarios: Topology analysis and relationship validation.
Data quality checks
Check data integrity
-- Check the data integrity of entities and relationships
.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
`)
Identify dangling relationships
-- Find relationships that point to non-existent entities
.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, 'Dangling')
| where status = 'Dangling';
$entityData
Performance optimization suggestions
1. Optimize query structure
Use indexes properly
-- Before optimization: Full table scan
.topo | graph-call cypher(`
MATCH (n) WHERE n.service_name = 'web-app'
RETURN n
`)
-- After optimization: Use a label index
.topo | graph-call cypher(`
MATCH (n:``apm@apm.service`` {service_name: 'web-app'})
RETURN n
`)
Filter conditions early
-- Before optimization: Late filtering
.topo | graph-call cypher(`
MATCH (start)-[*1..5]->(endNode)
WHERE start.environment = 'production' AND endNode.status = 'active'
RETURN start, endNode
`)
-- After optimization: Early filtering
.topo | graph-call cypher(`
MATCH (start {environment: 'production'})-[*1..5]->(endNode {status: 'active'})
RETURN start, endNode
`)
2. Control the result set
Paging and limits
-- Use LIMIT to control the number of results
.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
`)
Result sampling
-- Sample a large result set
.topo | graph-call cypher(`
MATCH (n:``apm@apm.service``)
RETURN n.service
LIMIT 100
`)
| extend seed = random()
| where seed < 0.1
3. Multi-hop optimization
Control the hop depth
-- Avoid excessively deep traversals
.topo | graph-call cypher(`
MATCH (start)-[path*1..3]->(endNode)
WHERE length(path) <= 2
RETURN path
`)
Use directional optimization
-- Use relationship direction to reduce the search space
.topo | graph-call cypher(`
MATCH (start)-[calls:calls*1..3]->(endNode) -- Specify direction
WHERE start.__entity_type__ = 'apm.service'
RETURN start, endNode
`)