我试图了解 gremlin 查询是如何工作的,特别是当涉及“AND”之类的查询时。
当我执行以下查询时,它会在大约 17 秒内产生结果。
g.V().has(id, gte(51200)).has(id, lte(51200000)).count().profile()
但是,如果我附加另一个 has 语句,如下所示,它甚至不会在 5 分钟内完成评估。
g.V().has(id, gte(51200)).has(id, lte(51200000)).has('entity_type', 'Human').count().profile()
我的期望是添加的“has”步骤只会在经过前两个has步骤的遍历中执行。因此,我没想到最后一个 has 语句会给整个查询增加很多时间,因为它只是检查属性的值。
我的后端是 JanusGraph,配置有 ElasticSearch 和 Google BigTable。它加载了大约 500 万个顶点。
对此的任何指导将不胜感激。
这将取决于图形引擎如何优化查询以及索引可以提供多少支持。使用 JanusGraph 时,假设您已经创建了相关索引,
.profile()
应该会向您显示索引的帮助程度以及时间花在了哪里。
您发布的内容缺少有关索引的信息。因此,我会做出一些假设。
假设 1:
id
使用混合索引进行索引,entity_type
未索引。
在这种情况下,您的最后一个
has
步骤(has('entity_type', 'Human')
)将需要从索引中获取每个检索到的顶点的属性。目前,图索引仅检索顶点/边 id(内联索引属性检索尚未完成,但不是 JanusGraph 1.0.0 的一部分)。因此,索引涵盖的 has
步骤之后的任何其他 has
步骤都需要从数据库中获取数据(获取属性)。
JanusGraph 1.0.0 之前
has
在您的情况下,无法通过多查询(批量查询)优化来优化索引范围之外的步骤。
从 JanusGraph 1.0.0 开始
has
步骤无法利用多查询优化,这应该会显着加速您的第二个 gremlin 查询。然而,由于额外的数据获取,它仍然会比第一个查询慢。
假设2:
id
和entity_type
都已编入索引,但具有两个不同的索引(即它们不属于同一索引)。
在这种情况下,您可能最终会执行跨索引查询(即从两个索引获取数据并在内存中过滤最终结果),这在许多情况下比执行单个索引并按内存中的属性过滤它要糟糕得多。
此问题的一个很好的解决方案是基于 cose 的索引选择,它将选择一个最适合的索引作为您的
GraphIndex
。这项工作也是 WIP,不是 JanusGraph 1.0.0 的一部分,但您可以在此处跟踪进度:https://github.com/JanusGraph/janusgraph/pull/3246
如果是这种情况,我建议在所需索引覆盖的
limit
步骤之后注入 has
步骤,这将强制为您的查询仅执行单个 GraphIndex。换句话说,您可以像下面这样修改查询,这应该会加快查询执行速度(在本例中,其执行效果与 Assumption 1
相同):
g.V().has(id, gte(51200)).has(id, lte(51200000)).limit(Long.MAX_VALUE).has('entity_type', 'Human').count().profile()