使我的Neo4j查询更快
我正在为我们的应用程序评估Neo4j,而现在,性能是一个问题。我已经创建了很多节点和边,我正在对它们进行一些查询。以下是此数据库中节点和边数据的详细信息: 我正在尝试进行一次搜索,遍历此图中的黄色箭头。到目前为止,我的问题如下:使我的Neo4j查询更快,neo4j,cypher,Neo4j,Cypher,我正在为我们的应用程序评估Neo4j,而现在,性能是一个问题。我已经创建了很多节点和边,我正在对它们进行一些查询。以下是此数据库中节点和边数据的详细信息: 我正在尝试进行一次搜索,遍历此图中的黄色箭头。到目前为止,我的问题如下: MATCH (n:LABEL_TYPE_Project {id:'14'}) -[:RELATIONSHIP_scopes*1]->(m:LABEL_TYPE_PermissionNode) -[:RELATIONSHIP_observedBy*
MATCH (n:LABEL_TYPE_Project {id:'14'})
-[:RELATIONSHIP_scopes*1]->(m:LABEL_TYPE_PermissionNode)
-[:RELATIONSHIP_observedBy*1]->(o:LABEL_TYPE_Item)
WHERE m.id IN ['1', '2', '6', '12', '12064', '19614', '19742', '19863', '21453', '21454', '21457', '21657', '21658', '31123', '31127', '31130', '47691', '55603', '55650', '56026', '56028', '56029', '56050', '56052', '85383', '85406', '85615', '105665', '1035242', '1035243']
AND o.content =~ '.*some string.*'
RETURN o
LIMIT 20
(上述变量路径已更新,请参阅“更新2”)
上面的查询需要1200毫秒的时间。它只返回请求的20个项目。如果我想要一个相同的计数,这需要永远:
MATCH ... more of the same ...
RETURN count(o)
上面的查询需要很多分钟。这是运行在CentOS上的Neo4j 2.2.0-M03社区。大约有385000个节点,170000个类型项
我已经在所有id
字段上创建了索引(以编程方式,index().forNodes(…).add(…)
),也在内容字段上创建了索引(createindex…
语句)
我的问题还有根本性的改进吗?我能试试的东西
非常感谢
根据他们的建议,这个问题从谷歌的Neo4j讨论组转移过来
更新1 应要求:
:schema
给出:
Indexes
ON :LABEL_TYPE_Item(id) ONLINE
ON :LABEL_TYPE_Item(active) ONLINE
ON :LABEL_TYPE_Item(content) ONLINE
ON :LABEL_TYPE_PermissionNode(id) ONLINE
ON :LABEL_TYPE_Project(id) ONLINE
No constraints
(此信息已更新,请参阅“更新2”)
更新2 我对查询做了以下值得注意的改进:
- 真丢脸,我确实为所有
s都设置了超级节点(不是出于设计,只是弄乱了我正在使用的导入算法),现在我删除了它TYPE\u项目
- 我有很多“字符串”可能是正确的数据类型,比如整数、布尔值,现在我正在将它们导入(你会在下面更新的查询中看到,我删除了很多引号)
- 正如前面指出的,我有可变长度的路径,并且我修复了这些路径
- 正如前面指出的,我应该有唯一性指数而不是正则指数,我修正了这一点
:schema
现在给出:
Indexes
ON :LABEL_TYPE_Item(active) ONLINE
ON :LABEL_TYPE_Item(content) ONLINE
ON :LABEL_TYPE_Item(id) ONLINE (for uniqueness constraint)
ON :LABEL_TYPE_PermissionNode(id) ONLINE (for uniqueness constraint)
ON :LABEL_TYPE_Project(id) ONLINE (for uniqueness constraint)
Constraints
ON (label_type_item:LABEL_TYPE_Item) ASSERT label_type_item.id IS UNIQUE
ON (label_type_project:LABEL_TYPE_Project) ASSERT label_type_project.id IS UNIQUE
ON (label_type_permissionnode:LABEL_TYPE_PermissionNode) ASSERT label_type_permissionnode.id IS UNIQUE
查询现在如下所示:
MATCH (n:LABEL_TYPE_Project {id:14})
-[:RELATIONSHIP_scopes]->(m:LABEL_TYPE_PermissionNode)
-[:RELATIONSHIP_observedBy]->(o:LABEL_TYPE_Item)
WHERE m.id IN [1, 2, 6, 12, 12064, 19614, 19742, 19863, 21453, 21454, 21457, 21657, 21658, 31123, 31127, 31130, 47691, 55603, 55650, 56026, 56028, 56029, 56050, 56052, 85383, 85406, 85615, 105665, 1035242, 1035243]
AND o.content =~ '.*some string.*'
RETURN o
LIMIT 20
以上查询现在大约需要350毫秒
我仍然想要一个相同的计数:
MATCH ...
RETURN count(0)
以上查询现在大约需要1100ms。虽然这要好得多,而且对于这个特定的查询几乎不可接受,但我已经发现一些更复杂的查询本质上需要更长的时间。因此,对这个查询进行进一步改进将是非常好的
根据要求,这里是用于返回o
查询(用于改进的查询)的配置文件
:
下面是返回计数(o)
查询(用于改进的查询)的配置文件
:
其余建议:
- 使用
语法:到目前为止,这对我没有任何帮助匹配。。。使用x MATCH…->(x)
- 使用:仍要执行请参见“更新3”中的结果
- 使用预计算:这对我没有帮助,因为查询将是相当不同的
更新3 我一直在玩全文搜索,并将
内容
属性编入索引,如下所示:
IndexManager indexManager = getGraphDb().index();
Map<String, String> customConfiguration = MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "type", "fulltext");
Index<Node> index = indexManager.forNodes("INDEX_FULL_TEXT_content_Item", customConfiguration);
index.add(node, "content", value);
以下是此查询的配置文件
:
Compiler CYPHER 2.2
Planner COST
EagerAggregation
|
+Filter(0)
|
+Expand(All)(0)
|
+NodeHashJoin
|
+Filter(1)
| |
| +NodeByIndexQuery
|
+Expand(All)(1)
|
+NodeUniqueIndexSeek
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
| Operator | EstimatedRows | Rows | DbHits | Identifiers | Other |
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
| EagerAggregation | 50 | 1 | 0 | count(o) | |
| Filter(0) | 2533 | 166 | 498 | m, n, o | (Property(n,id(0)) == { AUTOINT0} AND hasLabel(n:LABEL_TYPE_Project)) |
| Expand(All)(0) | 32933 | 166 | 332 | m, n, o | (m)<-[:RELATIONSHIP_scopes]-(n) |
| NodeHashJoin | 32933 | 166 | 0 | m, o | o |
| Filter(1) | 1 | 553 | 553 | o | hasLabel(o:LABEL_TYPE_Item) |
| NodeByIndexQuery | 1 | 553 | 554 | o | Literal(content:*itzndby*); INDEX_FULL_TEXT_content_Item |
| Expand(All)(1) | 64914 | 146855 | 146881 | m, o | (m)-[:RELATIONSHIP_observedBy]->(o) |
| NodeUniqueIndexSeek | 27 | 26 | 30 | m | :LABEL_TYPE_PermissionNode(id) |
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
编译器密码2.2
计划成本
渴望聚合
|
+过滤器(0)
|
+展开(全部)(0)
|
+NodeHashJoin
|
+过滤器(1)
| |
|+NodeByIndexQuery
|
+展开(全部)(1)
|
+NodeUniqueIndexSeek
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
|运算符| EstimatedRows |行|数据命中|标识符|其他|
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
|加总| 50 | 1 | 0 |计数(o)||
|过滤器(0)| 2533 | 166 | 498 | m,n,o |(属性(n,id(0))={AUTOINT0}和hasLabel(n:LABEL_TYPE_项目))|
|扩展(全部)(0)| 32933 | 166 | 332 | m,n,o |(m)(o)|
|NodeUniqueIndexSeek | 27 | 26 | 30 | m |:标签类型|许可证节点(id)|
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
在考虑查询优化的情况下,游戏的第1个名称是在回答问题时首先考虑如何考虑较少的数据。与考虑较少的数据相比,更快地考虑同一数据是远远不够的。
- 在
内容
字段中。我的理解是,您正在执行的正则表达式并没有缩小cypher的搜索路径,因此它基本上必须查看每个o:LABEL_TYPE_Item
,并针对该字段运行正则表达式。你的正则表达式只不过在寻找子串,所以Lucene可以帮助减少Cyfor节点在给出结果之前必须考虑的数量。
- 您的关系路径是可变长度的(
-[:relationship_scopes*1]->
),但您给我们的图像表明您只需要一个跳跃。在这两个关系跃点上,取决于图表的结构(以及您拥有的数据量),您可能正在浏览比您需要的更多的信息。仔细考虑这些关系跳数和数据模型;你能用-[:RELATIONSHIP\u scopes]->
代替吗?请注意,在m
节点上有一个WHERE
子句,您可能需要遍历更多的节点
- 检查查询计划(通过
PROFILE
,谷歌文档)。我看到很多人使用的一个技巧是将他们查询中最严格的部分推到顶部,在aIndexManager indexManager = getGraphDb().index();
Map<String, String> customConfiguration = MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "type", "fulltext");
Index<Node> index = indexManager.forNodes("INDEX_FULL_TEXT_content_Item", customConfiguration);
index.add(node, "content", value);
START o=node:INDEX_FULL_TEXT_content_Item("content:*some string*")
MATCH (n:LABEL_TYPE_Project {id:14})
-[:RELATIONSHIP_scopes]->(m:LABEL_TYPE_PermissionNode)
-[:RELATIONSHIP_observedBy]->(o:LABEL_TYPE_Item)
WHERE m.id IN [1, 2, 6, 12, 12064, 19614, 19742, 19863, 21453, 21454, 21457, 21657, 21658, 31123, 31127, 31130, 47691, 55603, 55650, 56026, 56028, 56029, 56050, 56052, 85383, 85406, 85615, 105665, 1035242, 1035243]
RETURN count(o);
Compiler CYPHER 2.2
Planner COST
EagerAggregation
|
+Filter(0)
|
+Expand(All)(0)
|
+NodeHashJoin
|
+Filter(1)
| |
| +NodeByIndexQuery
|
+Expand(All)(1)
|
+NodeUniqueIndexSeek
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
| Operator | EstimatedRows | Rows | DbHits | Identifiers | Other |
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
| EagerAggregation | 50 | 1 | 0 | count(o) | |
| Filter(0) | 2533 | 166 | 498 | m, n, o | (Property(n,id(0)) == { AUTOINT0} AND hasLabel(n:LABEL_TYPE_Project)) |
| Expand(All)(0) | 32933 | 166 | 332 | m, n, o | (m)<-[:RELATIONSHIP_scopes]-(n) |
| NodeHashJoin | 32933 | 166 | 0 | m, o | o |
| Filter(1) | 1 | 553 | 553 | o | hasLabel(o:LABEL_TYPE_Item) |
| NodeByIndexQuery | 1 | 553 | 554 | o | Literal(content:*itzndby*); INDEX_FULL_TEXT_content_Item |
| Expand(All)(1) | 64914 | 146855 | 146881 | m, o | (m)-[:RELATIONSHIP_observedBy]->(o) |
| NodeUniqueIndexSeek | 27 | 26 | 30 | m | :LABEL_TYPE_PermissionNode(id) |
+---------------------+---------------+--------+--------+-------------+------------------------------------------------------------------------+
MATCH (foo)-[:stuff*]->(bar) // (bunch of other complex stuff)
WHERE bar.id = 5
RETURN foo
MATCH bar
WHERE bar.id = 5
WITH bar
MATCH (foo)-[:stuff*]->(bar)
RETURN foo;
create constraint on (p:LABEL_TYPE_Project) assert p.id is unique;
create constraint on (m:LABEL_TYPE_PermissionNode) assert m.id is unique;
MATCH (n:LABEL_TYPE_Project {id:'14'})-[:RELATIONSHIP_scopes]->
(m:LABEL_TYPE_PermissionNode)-[:RELATIONSHIP_observedBy]->(o:LABEL_TYPE_Item)
WHERE m.id in ['1', '2', ... '1035242', '1035243']
AND o.content =~ '.*itzndby.*' RETURN o LIMIT 20
MATCH (n:LABEL_TYPE_Project {id: {p_id}})-[:RELATIONSHIP_scopes]->(m:LABEL_TYPE_PermissionNode)-[:RELATIONSHIP_observedBy]->(o:LABEL_TYPE_Item)
WHERE m.id in {m_ids} AND o.content =~ '.*'+{item_content}+'.*'
RETURN o LIMIT 20
MATCH (n:LABEL_TYPE_Project {id: {p_id}})-[:RELATIONSHIP_scopes]->(m:LABEL_TYPE_PermissionNode)
WHERE m.id in {m_ids}
WITH distinct m
MATCH (m)-[:RELATIONSHIP_observedBy]->(o:LABEL_TYPE_Item)
WHERE o.content =~ '.*'+{item_content}+'.*'
RETURN o LIMIT 20