13

我使用 Michael Hunger 的 Batch Import 导入了数据,通过它我创建了:-

4,612,893 nodes
14,495,063 properties
    node properties are indexed.
5,300,237 relationships

{问题} Cypher 查询执行速度太慢,几乎是爬行,简单的遍历需要 5 分钟以上才能返回结果集,请让我知道如何调整服务器以获得更好的性能以及我做错了什么。

店铺详情:-

-rw-r--r-- 1 root root 567M Jul 12 12:42 data/graph.db/neostore.propertystore.db
-rw-r--r-- 1 root root 167M Jul 12 12:42 data/graph.db/neostore.relationshipstore.db
-rw-r--r-- 1 root root  40M Jul 12 12:42 data/graph.db/neostore.nodestore.db
-rw-r--r-- 1 root root 7.8M Jul 12 12:42 data/graph.db/neostore.propertystore.db.strings
-rw-r--r-- 1 root root  330 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index.keys
-rw-r--r-- 1 root root  292 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db.names
-rw-r--r-- 1 root root  153 Jul 12 12:42 data/graph.db/neostore.propertystore.db.arrays
-rw-r--r-- 1 root root   88 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index
-rw-r--r-- 1 root root   69 Jul 12 12:42 data/graph.db/neostore
-rw-r--r-- 1 root root   58 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.nodestore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.arrays.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index.keys.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.strings.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.relationshipstore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db.names.id

我在用

neo4j-community-1.9.1
java version "1.7.0_25"
Amazon EC2 m1.large instance with Ubuntu 12.04.2 LTS (GNU/Linux 3.2.0-40-virtual x86_64)
RAM ~8GB.
EBS 200 GB, neo4j is running on EBS volume.

调用为 ./neo4j-community-1.9.1/bin/neo4j start

以下是 neo4j 服务器信息:

neostore.nodestore.db.mapped_memory                 161M
neostore.relationshipstore.db.mapped_memory         714M
neostore.propertystore.db.mapped_memory              90M
neostore.propertystore.db.index.keys.mapped_memory    1M
neostore.propertystore.db.strings.mapped_memory     130M
neostore.propertystore.db.arrays.mapped_memory      130M
mapped_memory_page_size                               1M
all_stores_total_mapped_memory_size                 500M

{数据模型} 就像社交图:-

User-User
    User-[:FOLLOWS]->User
User-Item
    User-[:CREATED]->Item
    User-[:LIKE]->Item
    User-[:COMMENT]->Item
    User-[:VIEW]->Item
Cluster-User
    User-[:FACEBOOK]->SocialLogin_Cluster
Cluster-Item
    Item-[:KIND_OF]->Type_Cluster
Cluster-Cluster
    Cluster-[:KIND_OF]->Type_Cluster

{一些查询}和时间:

START u=node(467242)
MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b
WHERE NOT(a=b)
RETURN u,COUNT(b)

查询耗时 1015348 毫秒。返回 70956115 结果计数。

START a=node:nodes(kind="user")
RETURN a,length(a-[:CREATED|LIKE|COMMENT|FOLLOWS]-()) AS cnt
ORDER BY cnt DESC
LIMIT 10

查询耗时 231613ms


根据建议,我将盒子升级为 M1.xlarge 和 M2.2xlarge

  • M1.xlarge (vCPU:4,ECU:8,RAM:15 GB,实例存储:~600 GB)
  • M2.2xlarge (vCPU:4,ECU:13,RAM:34 GB,实例存储:~800 GB)

我调整了如下属性,并从实例存储运行(针对 EBS)

neo4j.properties

neostore.nodestore.db.mapped_memory=1800M
neostore.relationshipstore.db.mapped_memory=1800M
neostore.propertystore.db.mapped_memory=100M
neostore.propertystore.db.strings.mapped_memory=150M
neostore.propertystore.db.arrays.mapped_memory=10M

neo4j-wrapper.conf

wrapper.java.additional.1=-d64
wrapper.java.additional.1=-server
wrapper.java.additional=-XX:+UseConcMarkSweepGC
wrapper.java.additional=-XX:+CMSClassUnloadingEnabled
wrapper.java.initmemory=4098
wrapper.java.maxmemory=8192

但是查询(如下所示)仍然在几分钟内运行约 5-8 分钟,从推荐的角度来看这是不可接受的。

询问:

START u=node(467242)
MATCH u-[r1:LIKE]->a<-[r2:LIKE]-lu-[r3:LIKE]-b
RETURN u,COUNT(b)

{分析}

neo4j-sh (0)$ profile START u=node(467242) MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b RETURN u,COUNT(b);
==> +-------------------------+
==> | u            | COUNT(b) |
==> +-------------------------+
==> | Node[467242] | 70960482 |
==> +-------------------------+
==> 1 row
==> 
==> ColumnFilter(symKeys=["u", "  INTERNAL_AGGREGATEad2ab10d-cfc3-48c2-bea9-be4b9c1b5595"], returnItemNames=["u", "COUNT(b)"], _rows=1, _db_hits=0)
==> EagerAggregation(keys=["u"], aggregates=["(  INTERNAL_AGGREGATEad2ab10d-cfc3-48c2-bea9-be4b9c1b5595,Count)"], _rows=1, _db_hits=0)
==>   TraversalMatcher(trail="(u)-[r1:LIKE|COMMENT WHERE true AND true]->(a)<-[r2:LIKE|COMMENT WHERE true AND true]-(lu)-[r3:LIKE WHERE true AND true]-(b)", _rows=70960482, _db_hits=71452891)
==>     ParameterPipe(_rows=1, _db_hits=0)


neo4j-sh (0)$ profile START u=node(467242) MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b RETURN count(distinct a),COUNT(distinct b),COUNT(*);
==> +--------------------------------------------------+
==> | count(distinct a) | COUNT(distinct b) | COUNT(*) |
==> +--------------------------------------------------+
==> | 1950              | 91294             | 70960482 |
==> +--------------------------------------------------+
==> 1 row
==> 
==> ColumnFilter(symKeys=["  INTERNAL_AGGREGATEe6b94644-0a55-43d9-8337-491ac0b29c8c", "  INTERNAL_AGGREGATE1cfcd797-7585-4240-84ef-eff41a59af33", "  INTERNAL_AGGREGATEea9176b2-1991-443c-bdd4-c63f4854d005"], returnItemNames=["count(distinct a)", "COUNT(distinct b)", "COUNT(*)"], _rows=1, _db_hits=0)
==> EagerAggregation(keys=[], aggregates=["(  INTERNAL_AGGREGATEe6b94644-0a55-43d9-8337-491ac0b29c8c,Distinct)", "(  INTERNAL_AGGREGATE1cfcd797-7585-4240-84ef-eff41a59af33,Distinct)", "(  INTERNAL_AGGREGATEea9176b2-1991-443c-bdd4-c63f4854d005,CountStar)"], _rows=1, _db_hits=0)
==>   TraversalMatcher(trail="(u)-[r1:LIKE|COMMENT WHERE true AND true]->(a)<-[r2:LIKE|COMMENT WHERE true AND true]-(lu)-[r3:LIKE WHERE true AND true]-(b)", _rows=70960482, _db_hits=71452891)
==>     ParameterPipe(_rows=1, _db_hits=0)

请让我知道用于调整的配置和 neo4j 启动参数。提前致谢

4

3 回答 3

14

在我的 macbook air 上运行此程序,RAM 和 CPU 很少,并带有您的数据集。

通过更多的内存映射、GCR 缓存和更多的缓存堆,您将获得比我的结果更快的结果。还要确保在查询中使用参数。

你遇到了组合爆炸。

路径的每一步都将“times rels”元素/行添加到匹配的子图中。

例如,请参见此处:您最终获得 269268 个匹配项,但您只有 81674 个不同的 lu

问题在于,对于每一行,下一个匹配项都会被扩展。因此,如果您在两者之间再次使用 distinct 来限制大小,那么数据将减少一些数量级。下一级也一样。

START u=node(467242)
MATCH u-[:LIKED|COMMENTED]->a
WITH distinct a
MATCH a<-[r2:LIKED|COMMENTED]-lu
RETURN count(*),count(distinct a),count(distinct lu);

+---------------------------------------------------+
| count(*) | count(distinct a) | count(distinct lu) |
+---------------------------------------------------+
| 269268   | 1952              | 81674              |
+---------------------------------------------------+
1 row

895 ms

START u=node(467242)
MATCH u-[:LIKED|COMMENTED]->a
WITH distinct a
MATCH a<-[:LIKED|COMMENTED]-lu
WITH distinct lu
MATCH lu-[:LIKED]-b
RETURN count(*),count(distinct lu), count(distinct b)
;
+---------------------------------------------------+
| count(*) | count(distinct lu) | count(distinct b) |
+---------------------------------------------------+
| 2311694  | 62705              | 91294             |
+---------------------------------------------------+

在这里,您总共有 230 万个匹配项,并且只有 91k 个不同的元素。所以差不多2个数量级。

这是一个巨大的聚合,它更像是一个 BI / 统计查询而不是 OLTP 查询。通常,您可以将结果存储在用户节点上,并且只能在后台重新执行。

这些类型的查询又是全局图查询(统计/BI),在这种情况下是前 10 名用户。

通常你会在后台运行这些(例如每天或每小时一次)并将前 10 个用户节点连接到一个特殊的节点或索引,然后可以在几毫秒内查询。

START a=node:nodes(kind="user") RETURN count(*);
+----------+
| count(*) |
+----------+
| 3889031  |
+----------+
1 row

27329 ms

毕竟你是在整个图上运行匹配,即 4M 用户是一个全局图,而不是一个图本地查询。

START n=node:nodes(kind="top-user")
MATCH n-[r?:TOP_USER]-()
DELETE r
WITH distinct n
START a=node:nodes(kind="user")
MATCH a-[:CREATED|LIKED|COMMENTED|FOLLOWS]-()
WITH n, a,count(*) as cnt
ORDER BY cnt DESC
LIMIT 10
CREATE a-[:TOP_USER {count:cnt} ]->n;

+-------------------+
| No data returned. |
+-------------------+
Relationships created: 10
Properties set: 10
Relationships deleted: 10

70316 ms

查询将是:

START n=node:nodes(kind="top-user")
MATCH n-[r:TOP_USER]-a
RETURN a, r.count
ORDER BY r.count DESC;

+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| a                                                                                                                                                  | r.count |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
….
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
10 rows

4 ms
于 2013-07-31T12:21:59.740 回答
5

好的,首先,对于只有 8GB 的​​内存,这是一个非常大的图表。你应该认真考虑买一个更大的盒子。Neo4j 实际上提供了一个非常好的硬件计算器,可以让您准确地确定适合您的需求:

http://neotechnology.com/calculatorv2/

以一种人为的方式(因为有更多相关的指标来确定大小),他们的计算器估计应该至少专门用于 10GB。

其次,Neo4j 和任何图形数据库都会遇到具有大量连接的节点的问题。如果您希望调整您的实例以更好地执行(在获得更大的盒子之后),我建议您寻找任何具有大量连接的大型节点,因为这些节点会严重影响性能。

看到你的例子后,我很确定你有一个包含许多节点的图,这些节点的连接数比其他节点多得多。这本质上会降低你的表现。您也可以尝试更窄的查询。尤其是当您已经在一个太小的服务器上工作时,您不想运行那种非常繁重的大型返回查询。

关于您的查询有一些事情可以清理,但我真的敦促您为您的图表获取适当大小的框,并实际上对您连接最多的节点所拥有的连接数进行一些内省。

看起来你对 Java 堆大小有一个人为的上限。如果您尝试使用以下命令启动 java:

java -Xmx8g //Other stuff

您将分配 8 gigs 而不是标准的 ~500 Megs,这也会有所帮助。

于 2013-07-15T19:10:20.463 回答
1

你不需要:

WHERE NOT(a=b)

在模式匹配器中,两个不同的标识符永远不会是同一个节点。

你可以profile用你的查询吗?

profile START u=node(467242)
MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b
RETURN u,COUNT(b)

看看有多少节点被触及也会很有趣:

profile START u=node(467242)
MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b
RETURN count(distinct a),COUNT(distinct b),COUNT(*)

您还可以将 MMIO 设置减少到实际值:

neostore.nodestore.db.mapped_memory=180M
neostore.relationshipstore.db.mapped_memory=750M

如果您将机器的所有 RAM 声明为堆,它将与 FS 缓冲区和 mmio 缓冲区竞争。

wrapper.java.initmemory=5000
wrapper.java.maxmemory=5000

您是在测量查询的第一次运行还是后续运行?

于 2013-07-21T13:56:03.407 回答