Neo4j 库存图-获取所有相关资产

Neo4j 库存图-获取所有相关资产,neo4j,cypher,neo4jclient,Neo4j,Cypher,Neo4jclient,给出了以下示例图: CREATE (app1:Application {Id: 1, Name: 'A big application'}), (db1:Database {Name: 'db1'}), (db2:Database {Name: 'db2'}), (di1:DatabaseInstance {Name: 'db1-i1'}), (di2:DatabaseInstance {Name: 'db1-i2'}), (di3:DatabaseIns

给出了以下示例图:

CREATE (app1:Application {Id: 1, Name: 'A big application'}),
    (db1:Database {Name: 'db1'}),
    (db2:Database {Name: 'db2'}),
    (di1:DatabaseInstance {Name: 'db1-i1'}),
    (di2:DatabaseInstance {Name: 'db1-i2'}),
    (di3:DatabaseInstance {Name: 'db2-i1'}),
    (di4:DatabaseInstance {Name: 'db2-i2'}),
    (s1:Server {Name: 'Server 1'}),
    (s2:Server {Name: 'Server 2'}),
    (s1)-[:ClusteredWith]->(s2),
    (s2)-[:ClusteredWith]->(s1),
    (di1)-[:InstalledOn]->(s1),
    (di3)-[:InstalledOn]->(s1),
    (di2)-[:InstalledOn]->(s2),
    (di4)-[:InstalledOn]->(s2),
    (di1)-[:Instantiate]->(db1),
    (di3)-[:Instantiate]->(db2),
    (di2)-[:Instantiate]->(db1),
    (di4)-[:Instantiate]->(db2),
    (app1)-[:Utilize]->(db1),
    (app1)-[:Utilize]->(db2)
这是一个IT清单,我在其中描述了大型环境中部署的应用程序之间的关系。实际上,该应用程序有约500个数据库和约1000台服务器

我的目标是获取应用程序、数据库或服务器的所有相关资产

使用Cypher 2,我的查询想法是从应用程序中获取所有相关资产:

MATCH (a:Application)
WHERE a.Id = 1
OPTIONAL MATCH (a)-->(d:Database)
OPTIONAL MATCH (a)-[*1..]-(s:Server)
RETURN
    a AS Application,
    collect(d) AS Databases,
    collect(s) AS Servers
使用Neo4jClient:

var result = client.Cypher
    .Match("(a:Application)")
    .Where((Application a) => a.Id == request.Id)
    .OptionalMatch("(a)-->(d:Database)")
    .OptionalMatch("(a)-[1..]-(s:Server)")
    .Return((a, d, s) => new {
        Application = a.As<Anwendung>(),
        Databases = d.CollectAs<Database>(),
        Servers = s.CollectAs<Server>()
    });
var result=client.Cypher
.Match(“(a:应用程序)”)
.Where((应用程序a)=>a.Id==request.Id)
.OptionalMatch(“(a-->(d:数据库)”)
.OptionalMatch(“(a)-[1..](s:服务器)”)
.返回((a、d、s)=>新{
Application=a.As(),
Databases=d.CollectAs(),
Servers=s.CollectAs()
});
我使用的是
可选匹配
,因为库存图并不总是处于一致状态

但是这个查询运行太长,占用了99%的CPU。在数据库或服务器上运行这个查询是可行的,但查询速度仍然很慢->400->900毫秒


我的数据模型是坏的还是我用错了密码?如何加快速度?

当我仅对您提供的样本数据运行该查询时,我得到了128个匹配项。您可以通过将return子句更改为

RETURN
     a AS Application,
     count(d) AS Databases,
     count(s) AS Servers
在你的完整数据集上也尝试一下,我敢打赌一个棒棒糖你会得到一个令人不舒服的匹配量。如果查看返回的数据,还可以看到大量重复数据。尽管在第一个可选模式中只有两个
:Database
节点匹配,但作为“Databases”返回的集合包含128项。在匹配服务器之前,请尝试显式地解析数据库节点,您可以通过在两个可选模式之间引入解析来实现这一点

WITH a, collect(d) as Databases
如果运行此查询并返回计数,您将看到已将结果减半。原始查询将第二个可选模式考虑两次,第一个模式中的每个结果考虑一次。当您使用
和…
显式解析第一个模式时,第二个模式只考虑一次。这可能就是为什么当您单独运行查询时,它们的速度不会那么慢的原因

然而,第二个可选匹配仍然匹配微小数据样本中的64个模式,这可能是导致查询速度缓慢的最终原因。这里的问题是你的模式太模糊了。只要最后一个节点是
:Server
,模式匹配器就可以在图形中以任何方向和深度移动任何类型的关系。有两种方式可以让事情变得更糟。考虑添加第二个应用程序。此应用程序使用不同的数据库,但托管该数据库实例的服务器之一也托管示例中第一个应用程序使用的数据库实例。扩展图形的查询可能如下所示

MATCH (s2:Server {Name: 'Server 2'})
CREATE (app2:Application {Id:2, Name: 'Another application'}),
    (db3:Database {Name: 'db3'}),
    (di5:DatabaseInstance {Name: 'db3-i1'}),
    (di6:DatabaseInstance {Name: 'db3-i2'}),
    (s3:Server {name: 'Server 3'}),
    (di5)-[:Instantiate]->(db3),
    (di5)-[:InstalledOn]->(s3),
    (di6)-[:Instantiate]->(db3),
    (di6)-[:InstalledOn]->(s2),
    (app2)-[:Utilize]->(db3)
您的第二个可选匹配项可以自由遍历该图,因此,虽然它确实找到了正确的服务器,但它也可以通过安装在同一服务器上的其他数据库实例继续“向后”移动。它将遵循如下路径:

(s2:Server {Name: 'Server 2'})<-[:InstalledOn]-(di6:DatabaseInstance {Name: 'db3-i2'})
如果应用程序在您的模型中使用的不是数据库,则保留
:Database
标签以消除歧义;其他模式也是如此。我的观点是:在cypher中声明模式时,不要用标签代替关系类型

根据您提供的示例,您可以通过将查询更改为

OPTIONAL MATCH (a)-[:Utilize]->()<-[:Instantiate]-()-[:InstalledOn]->(server)
OPTIONAL MATCH (a)-[:Utilize]->(d)
MATCH (a:Application {Id:1}) // From 2.0RC1 and on you can match with properties
OPTIONAL MATCH (a)-[:Utilize]->(d:Database)
WITH a, collect(d) as Databases
OPTIONAL MATCH (a)-[:Utilize]->()<-[:Instantiate]-()-[:InstalledOn]->(server)
RETURN
    a AS Application,
    Databases
    collect(s) AS Servers
MATCH(a:Application{Id:1})//从2.0RC1开始,您可以使用属性进行匹配
可选匹配(a)-[:利用]->(d:数据库)
使用a,将(d)收集为数据库
可选匹配(a)-[:利用]->()(服务器)
返回
a作为申请,
数据库
作为服务器收集

当我仅对您提供的样本数据运行该查询时,我得到了128个匹配项。您可以通过将return子句更改为

RETURN
     a AS Application,
     count(d) AS Databases,
     count(s) AS Servers
在你的完整数据集上也尝试一下,我敢打赌一个棒棒糖你会得到一个令人不舒服的匹配量。如果查看返回的数据,还可以看到大量重复数据。尽管在第一个可选模式中只有两个
:Database
节点匹配,但作为“Databases”返回的集合包含128项。在匹配服务器之前,请尝试显式地解析数据库节点,您可以通过在两个可选模式之间引入解析来实现这一点

WITH a, collect(d) as Databases
如果运行此查询并返回计数,您将看到已将结果减半。原始查询将第二个可选模式考虑两次,第一个模式中的每个结果考虑一次。当您使用
和…
显式解析第一个模式时,第二个模式只考虑一次。这可能就是为什么当您单独运行查询时,它们的速度不会那么慢的原因

然而,第二个可选匹配仍然匹配微小数据样本中的64个模式,这可能是导致查询速度缓慢的最终原因。这里的问题是你的模式太模糊了。只要最后一个节点是
:Server
,模式匹配器就可以在图形中以任何方向和深度移动任何类型的关系。有两种方式可以让事情变得更糟。考虑添加第二个应用程序。此应用程序使用不同的数据库,但托管该数据库实例的服务器之一也托管示例中第一个应用程序使用的数据库实例。扩展图形的查询可能如下所示

MATCH (s2:Server {Name: 'Server 2'})
CREATE (app2:Application {Id:2, Name: 'Another application'}),
    (db3:Database {Name: 'db3'}),
    (di5:DatabaseInstance {Name: 'db3-i1'}),
    (di6:DatabaseInstance {Name: 'db3-i2'}),
    (s3:Server {name: 'Server 3'}),
    (di5)-[:Instantiate]->(db3),
    (di5)-[:InstalledOn]->(s3),
    (di6)-[:Instantiate]->(db3),
    (di6)-[:InstalledOn]->(s2),
    (app2)-[:Utilize]->(db3)
您的第二个可选匹配项可以自由遍历该图,因此,虽然它确实找到了正确的服务器,但它也可以通过安装在同一服务器上的其他数据库实例继续“向后”移动。它将遵循如下路径:

(s2:Server {Name: 'Server 2'})<-[:InstalledOn]-(di6:DatabaseInstance {Name: 'db3-i2'})
如果应用程序在模型中使用数据库以外的其他东西,那么