首页 > 解决方案 > OrientDB中如何高效遍历多个顶点

问题描述

我在 orientdb 中构建了一棵树,在自下而上的方向上有大量的节点和边。我想接收@class LEAF匹配某个范围条件(例如 val > 150 和 val < 300)的那棵树的所有叶子(每个叶子都有 ):

例子:

       o
     /   \
    o     o 
   /    /  \ 
  o    o    o
 210  120   /\
          270 180

结果:210、180、270

到目前为止,我尝试的是使用以下查询:

SELECT FROM(TRAVERSE IN() FROM #123:123) WHERE value > 150 and value < 300

这适用于一些元素,但性能会随着叶子数量的增加而下降。所以我的问题是:

  1. 这是在 OrientDB 中执行此操作的最有效方法,特别是如果我假设每个节点下有 300000 个叶子?
  2. 我从文档中知道,使用索引可以帮助提高范围查询的性能,但是在这种情况下会使用索引吗?我的第一个假设是否定的,因为 orient 首先遍历然后过滤遍历的元素,不是吗?

标签: orientdbquery-performance

解决方案


为了提高性能,试着考虑查询应该做的最小工作量来找到正确的叶子:你想找到属于某个树的具有特定值的叶子。

因此,您只想选择这两个条件都为真的叶子。但是,叶子不知道它们属于哪棵树,除非您以某种方式向它们提供该信息。幸运的是,OrientDB 允许您将属性添加到边缘(或叶子本身),从而使这变得非常容易。

因此,在这种情况下,我建议您将树的名称添加到该树的每个边缘。这样,每个叶子“通过关联”“知道”它属于哪棵树。

例如,让我们创建示例树:

CREATE CLASS Node EXTENDS V
CREATE PROPERTY Node.name INTEGER
CREATE VERTEX Node SET name = 1
CREATE VERTEX Node SET name = 2
CREATE VERTEX Node SET name = 3
CREATE VERTEX Node SET name = 4

CREATE CLASS LEAF EXTENDS V
CREATE PROPERTY LEAF.val FLOAT
CREATE VERTEX LEAF SET val = 210
CREATE VERTEX LEAF SET val = 120
CREATE VERTEX LEAF SET val = 270
CREATE VERTEX LEAF SET val = 180

CREATE CLASS C EXTENDS E
CREATE PROPERTY C.tree STRING
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 1) TO (SELECT * FROM Node WHERE name = 2) SET tree = 'example'
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 1) TO (SELECT * FROM Node WHERE name = 3) SET tree = 'example'
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 3) TO (SELECT * FROM Node WHERE name = 4) SET tree = 'example'
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 2) TO (SELECT * FROM LEAF WHERE val = 210) SET tree = 'example'
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 3) TO (SELECT * FROM LEAF WHERE val = 120) SET tree = 'example'
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 4) TO (SELECT * FROM LEAF WHERE val = 270) SET tree = 'example'
CREATE EDGE C FROM (SELECT * FROM Node WHERE name = 4) TO (SELECT * FROM LEAF WHERE val = 180) SET tree = 'example'

注意EDGE类如何C包含属性C.tree(字符串)。Nodes在和之间创建边时LEAFs,将树的名称赋予每个EDGE。在这种情况下,我添加SET tree = 'example'到每个边缘。

结果如下所示:

树示例

接下来,创建一个索引LEAF.val(以加快值搜索)和一个索引C.tree以快速识别每个叶子所属的树:

CREATE INDEX leafIndex ON LEAF (val) NOTUNIQUE
CREATE INDEX connectIndex ON C (tree) NOTUNIQUE

您现在可以对叶子执行非常高性能的查询,如下所示:

SELECT * FROM LEAF WHERE inE('C').tree = ["example"] AND val > 150 and val < 300

此查询执行以下操作:

  1. 选择所有叶子...
  2. 具有属性等于“示例”的in类边缘Ctree
  3. 并且拥有val150到300之间的房产

这种方法也避免了使用traverse,这比使用更昂贵select

结果正是您想要的:

查询示例

从查询解释中我们也可以看出优化引擎正在使用索引:

+ FETCH FROM INDEX leafIndex
  val > 150 and val < 300
+ EXTRACT VALUE FROM INDEX ENTRY
  filtering clusters [273,274,275,276,277,278,279,280]
+ FILTER ITEMS WHERE 
  inE('C').tree = ["example"]
+ FILTER ITEMS BY CLASS 
  LEAF
+ CALCULATE PROJECTIONS
  *

这个查询应该执行得很好,即使你有很多叶子。

祝你好运!

PS。您还可以将树的名称添加到每个顶点(而不是边),这也是一种解决方案!但在这种情况下,请注意当一片叶子是多棵树的一部分时会发生什么。


推荐阅读