Performance Blueprints/Gremlin graph DB查询是否天生就很慢?

Performance Blueprints/Gremlin graph DB查询是否天生就很慢?,performance,neo4j,graph-databases,gremlin,titan,Performance,Neo4j,Graph Databases,Gremlin,Titan,我正在为使用GraphDB(特别是HBase上的Titan 0.4.4)进行概念验证。为此,我创建了一个相对简单的图表:我有买卖产品的公司。销售与买方的一个部门有关: buyer {name} --BUYS {departmentId}--> product {name} <--SELLS-- seller {name} 由于我创建的顶点索引返回速度相对较快(预热后

我正在为使用GraphDB(特别是HBase上的Titan 0.4.4)进行概念验证。为此,我创建了一个相对简单的图表:我有买卖产品的公司。销售与买方的一个部门有关:

buyer {name} --BUYS {departmentId}--> product {name} <--SELLS-- seller {name}
由于我创建的顶点索引返回速度相对较快(预热后<1ms)。现在,为了获得相应的产品,我运行以下命令:

new GremlinPipeline(start).outE("BUYS").has("departmentId", D )
    .inV().has("name", new LowerCaseContainsPredicate(), P ).toList()
针对HBase后端(AWS EMR上的10 m3.xlarge节点)的响应时间非常长,每个查询的单个消费者平均响应时间约为1.5秒(我随机挑选了买家、部门和产品名称,并迭代了1000次),返回了大约260条产品记录。为了排除可能出现故障的HBase配置,我对本地BerkelyDB(4个CPU,8 GB虚拟机内存,16 GB总内存)运行了它

这当然加快了查询速度,单线程应用程序在160ms内返回,虽然它不是真正的赛车,但仍然可以接受。添加更多的并行请求会导致响应时间的快速下降,平均值为1.2s的并行请求数为10个

因此,我使用这个密码查询与Neo4j 2.1.3进行了比较:

start buyer=node:company(name=C) match buyer-[:BUYS {departmentId:D}]->(product) 
where product.name =~ "(?i).*P.*" return product
它的返回速度要快得多(4-6倍,取决于并行请求的数量,~50ms用于单线程,~270ms用于10个并行请求)。现在有了Neo4j的蓝图实现,所以我也尝试了一下,看看是DB引擎还是我查询的方式造成了差异

事实证明,对Neo4j运行Gremlin查询的速度与对Titan运行Gremlin查询的速度一样慢——事实上甚至稍微慢一点

所有测试都作为Java应用程序运行在一个带有嵌入式graph DBs的VM中,以避免任何网络影响。我还注意到,第一次查询通常需要更长的时间,因此应用程序在启动基准测试之前首先运行一个随机查询。代码是使用GremlinePipeline Java类的纯Java,上面的代码片段实际上就是它正在运行的Java代码(谓词除外,它只实例化一次)。通过使用参数化常量查询字符串并传入相应的参数映射来运行Cypher查询


这是我第一次使用graph DB,所以我想知道我是否对Gremlin查询做了一些根本性的错误,或者Blueprints/Gremlin天生就是慢的。

如果您使用的是Gremlin2,您不能混合使用Cypher和Gremlin,因为Gremlin使用自动索引,Cypher使用的是新的“模式索引”。在Neo4j2+中,自动索引已弃用/过时。因此,在Gremlin 3中,Gremlin使用与Cypher相同的索引。因此,如果您想查看性能,请在两个Neo4jGraph上进行测试。一个用小精灵填充数据,另一个用密码填充数据。然后,您可以看到实际速度,因为正确使用了索引

关于Titan/HBase。请确保打开缓存,否则您将始终访问磁盘(磁盘可能很热,但速度不如Titan的缓存)。请在此阅读更多信息:

这个问题的部分答案是,正如丹尼尔在评论中所说,我缺少了泰坦上的顶点中心指数。除了在名称上创建顶点索引外,我还需要为标签创建索引:

graph.makeKey("name").dataType(String.class).indexed(Vertex.class).make();

TitanKey departmentIndex=graph.makeKey("departmentId")
                         .dataType(String.class).make();
graph.makeLabel("BUYS").sortKey(departmentIndex).make();

Neo4j和Cypher的速度更快,显然这对Neo4j上的Gremlin查询没有影响,但这可能只是Neo4j的Gremlin实现的一个问题。

我认为,实际上索引并不是问题所在。开始节点在不到1ms的时间内返回。到目前为止,大部分时间都花在运行Gremlin管道上,据我所知,它没有使用任何索引。还是不正确?我不确定,伙计。我的经验是,小精灵通常比密码更快。如果你在gremlin用户的邮件列表上发帖,也许其中一个家伙可以和你一起深入了解问题所在。Titan使用以顶点为中心的索引进行遍历。在您的示例中,您应该为
BUYS
标签上的
departmentId
创建一个以顶点为中心的索引。更多详情请参见:谢谢丹尼尔,这对《泰坦》有很大的影响。Neo4j和Cypher还不太成熟,但至少在一个可用范围内。您是否使用绑定来设置变量?如果不是的话,你的小精灵将需要用每一个随机更改重新编译,这就是为什么它会很慢。为了跟进上面的评论,你到底是如何发出你的查询的?你是在小精灵控制台上做这一切的吗?您是否向Rexster(作为Titan服务器)发出请求?这些查询是使用gremlin Java Tinkerpop Maven工件中的GremlinePipeline类从Java应用程序运行的。它在本地安装中运行(没有Rexter),并且没有绑定变量。我没有使用Gremlin Groovy和预编译管道。我更新了问题以提供更多细节。
graph.makeKey("name").dataType(String.class).indexed(Vertex.class).make();

TitanKey departmentIndex=graph.makeKey("departmentId")
                         .dataType(String.class).make();
graph.makeLabel("BUYS").sortKey(departmentIndex).make();