ArangoDB AQL中的图形绘制遍历
来源:互联网 发布:java 值传递 引用传递 编辑:程序博客网 时间:2024/06/13 17:24
原文:Graphs in AQL
AQL中的图形
在ArangoDB中可以使用多种方式处理图形,以及使用AQL查询图形的不同方法。
管理图形的两个选项是使用
- ArangoDB管理一个图形中涉及的集合的命名图,或
- 图形功能在文档和边缘集合的组合上。
可以通过图形模块 或通过Web界面定义命名图。该定义包含图形的名称,以及所涉及的顶点和边缘集合。由于管理功能分层在简单的文档和边集合之上,您还可以使用常规的AQL函数来处理它们。
图形查询的AQL语言结构支持两种变体(命名图和松散耦合的集合集,也称为匿名图)。这些构造充分利用优化,因此可以预期最佳性能:
AQL遍历以跟随连接到起始顶点的边缘,直到可变深度。它可以与AQL过滤条件相结合。
AQL最短路径,找到两个给定顶点之间的顶点和边,尽可能少的跳数。
这些类型的查询仅在数据模型中使用边集合和/或图形时才有用。
在AQL中绘制遍历
一般查询想法
遍历从一个特定文档(startVertex)开始,并且跟随连接到该文档的所有边。对于这些边缘所针对的所有文档(顶点),它将再次跟随所有连接到它们的边缘,依此类推。可以定义至少(最小深度)和最多(最大深度)应执行这些后续迭代中有多少次。
对于在此过程中访问的所有顶点,在最小深度和最大深度迭代之间的范围内, 您将获得一组结果,其中包含三个项目:
- 被访问的顶点。
- 边缘指向它。
- 从startVertex到被访问顶点的完整路径,作为具有属性边和属性顶点的对象,每个都是相应元素的列表。这些列表进行排序,这意味着在所述第一元件的顶点 是startVertex和上次被访问的顶点,并且在第n个元件的边缘的第n个元件与在第(n + 1)个元件连接的顶点。
示例执行
让我们来看一个简单的例子来解释它是如何工作的。这是我们将要遍历的图:
我们使用以下参数进行查询:
- 我们从顶点A开始。
- 我们使用最小深度为1。
- 我们使用的最大深度为2。
- 我们只沿着边缘的OUTBOUND方向
现在它走到A的直接邻居之一,说B(注:订购不能保证!):
查询将记住状态(红色圆圈),并将发出第一个结果 A → B(黑盒)。这也将阻止运行器被循环捕获。现在再次访问B的直接邻居之一,说E:
我们限制了最大深度为2的查询,所以它不会选择E的任何邻居,因为从A到E的路径已经需要2个步骤。相反,我们将返回一级到B,并继续与其他直接邻居:
再之后,我们生产这样的结果,我们将回踩乙。但是没有B的邻居,我们还没有访问过。因此,我们再走一步回到A,继续在那里的任何其他邻居。
与我们访问H之前的迭代相同:
和J:
在这些步骤之后,没有进一步的结果。所以这个查询一起返回了以下路径:
- A → B
- A → B → E
- A → B → C
- A → G
- A → G → H
- A → G → J
句法
现在我们来看看我们如何编写遵循这个架构的查询。您有两个选项,您可以使用命名图或一组边集(匿名图)。
使用命名图
FOR vertex[, edge[, path]] IN [min[..max]] OUTBOUND|INBOUND|ANY startVertex GRAPH graphName [OPTIONS options]
FOR
:最多发射三个变量:- vertex(object):遍历中的当前顶点
- edge(object,可选):遍历中的当前边
- path(object,optional):表示当前路径与两个成员:
vertices
:此路径上所有顶点的数组edges
:该路径上所有边的数组
IN
min..max
:遍历的最小和最大深度:- min(number,可选):此查询返回的边和顶点将以min的遍历深度开始(因此下面的边和顶点不会被返回)。如果未指定,则默认为1.最小可能值为0。
- max(number,可选):遍历最大长度路径。如果省略,max默认为min。因此,只返回min范围内的顶点和边。最大不能没有指定分钟。
OUTBOUND|INBOUND|ANY
:沿着在遍历中指向任一方向的传出,传入或边缘; 请注意,这不能被绑定参数替换。- startVertex(string | object):遍历来源的顶点。这可以以ID字符串的形式或具有该属性的文档的形式指定
_id
。所有其他值将导致警告和空的结果。如果指定的文档不存在,结果也是空的,没有警告。 GRAPH
graphName(string):标识命名图形的名称。它的顶点和边缘集合将被查找。OPTIONS
options(object,optional):用于修改遍历的执行。只有以下属性有效果,所有其他属性将被忽略:- uniqueVertices(string):可选地确保顶点唯一性
- “path” - 保证没有路径返回一个重复的顶点
- “global” - 保证在遍历期间每个顶点最多被访问一次,无论从起始顶点到这个顶点有多少路径。如果您从最小深度
min depth > 1
之前发现的顶点开始,可能根本不会返回(它仍然可能是路径的一部分)。注意: 使用此配置,结果不再是确定性的。如果从startVertex到顶点有多条路径,则选择其中一条路径。 - “none”(默认) - 不对顶点应用唯一性检查
- uniqueEdges(string):可选地确保边缘唯一性
- “path”(默认) - 保证没有路径返回一个重复的边
- “global” - 保证在遍历过程中,每个边缘最多被访问一次,无论从起始顶点到该边缘有多少条路径。如果从a开始,
min depth > 1
在最小深度之前发现的边缘根本不会被返回(它仍然可能是路径的一部分)。注意: 使用此配置,结果不再是确定性的。如果有从多个路径startVertex超过边缘的那些中的一个被拾取。 - “none” - 不对边缘应用唯一性检查。注意: 使用此配置,遍历将跟随边沿周期。
- bfs(bool):可选地使用可选的宽度优先遍历算法
- true - 遍历将被执行宽度优先。结果将首先包含深度1的所有顶点。比深度2处的所有顶点等等。
- false(默认) - 遍历将以深度优先执行。它首先将深度1的一个顶点的最小深度的最小深度返回到最大深度。对于深度1处的下一个顶点,依此类推。
- uniqueVertices(string):可选地确保顶点唯一性
使用集合集
FOR vertex[, edge[, path]] IN [min[..max]] OUTBOUND|INBOUND|ANY startVertex edgeCollection1, ..., edgeCollectionN [OPTIONS options]
而不是GRAPH graphName
您可以指定边集合的列表。顶点集合由边集合中的边确定。其余的行为与命名版本相似。如果多次指定相同的边缘集合,它将表现为只被指定一次。仅当集合没有冲突的遍历方向时,才允许指定相同的边集。
横向混合
对于具有边集合列表的遍历,您可以选择指定一些边集合的方向。例如,你有三个边缘集合edge1,edge2和edge3,其中在edge2方向上没有相关性,但是在edge1和edge3中应该考虑方向。在这种情况下,您可以使用OUTBOUND作为通用遍历方向,并且可以使用任何 专门用于edge2的方式,如下所示:
FOR vertex IN OUTBOUND startVertex edges1, ANY edges2, edges3
列表中没有指定自己的方向的所有集合将使用之后定义的方向IN
。这允许在遍历中为每个集合使用不同的方向。
使用过滤器和解释器推断成本
遍历中发出的所有三个变量也可以用在过滤器语句中。对于这些过滤语句中的一些,优化器可以检测到可以更早地修剪遍历的路径,因此滤波结果将不会首先发送到变量。这可能会显着提高查询的性能。每当过滤器不满足时,将跳过完整的顶点,边和路径集。长度大于max的所有路径将永远不会被计算。
在当前状态下,AND
可以优化OR
组合滤波器,但组合滤波器不能。
过滤路径
对路径进行过滤允许最强大的过滤,并可能对性能产生最大影响。使用路径变量可以对特定的迭代深度进行过滤。您可以通过指定一个负数,通过指定一个正数(然后限定优化)或相对于路径末尾的相对位置来过滤路径中的绝对位置。
过滤路径上的边
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.edges[0].theTruth == true RETURN p
将过滤所有路径,其中起始边(索引0)的属性 theTruth等于true。所产生的路径长达5个项目。
过滤路径上的顶点
类似于过滤路径上的边缘,您也可以过滤顶点:
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.vertices[1]._key == "G" RETURN p
组合几个过滤器
当然,您可以以任何您喜欢的方式组合这些过滤器:
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.edges[0].theTruth == true AND p.edges[1].theFalse == false FILTER p.vertices[1]._key == "G" RETURN p
该查询将过滤所有路径,其中第一个边缘的属性 theTruth等于true,第一个顶点为“G”,第二个边缘的属性theFalse等于false。所产生的路径长达5个项目。
注意:虽然我们定义了一个最小的1,我们只会得到深度2的结果,这是因为在深度为1的所有结果第二边缘不存在,因此不能在这里满足的条件。
过滤整个路径
在数组比较运算符的帮助下,也可以在整个路径上定义过滤器,如同所有的边都应该具有的.Truth == true:
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.edges[*].theTruth ALL == true RETURN p
或者NONE的边缘应该有theTruth == true:
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.edges[*].theTruth NONE == true RETURN p
上述两个示例由优化器识别,并且可能使用除边缘索引之外的其他索引。
还可以定义路径上的至少一个边缘必须满足以下条件:
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.edges[*].theTruth ANY == true RETURN p
确保至少有一个,但可能有更多的边缘满足条件。所有上述过滤器都可以以完全相同的方式在顶点上定义。
在路径上进行过滤,而不是对顶点或边缘进行过滤
路径上的过滤会影响图形上的迭代。如果不满足某些条件,则遍历可能会停止沿着该路径继续。
相反,顶点或边缘上的过滤器只表示您是否对这些文档的实际价值感兴趣。因此,它会影响返回文档的列表(如果您返回v或e)与指定非空min
值相似。如果指定最小值为2,则必须执行这些路径的前两个节点上的遍历 - 您将不会在结果数组中看到它们。
类似的是顶点或边缘上的过滤器 - 移动器必须沿着这些节点走动,因为您可能对路径上的文档感兴趣。
例子
我们将创建一个简单的对称遍历演示图:
a 例子> var examples = require(“@ arangodb / graph-examples / example-graph.js”);aangosh> var graph = examples.loadGraph(“traversalGraph”);aangosh> db.circles.toArray();aangosh> db.edges.toArray();
[ { “_key” :“I” , “_id” : “圈/ I” , “_rev” :“_VRZRUTu ---” , “ 标签”:“9” }, { “_key” :“G” , “_id” : “圆圈/ G” , “_rev” :“_VRZRUTq - E” , “ 标记”:“7” }, { “_key” :“F” , “_id” : “圆圈/ F” , “_rev” :“_VRZRUTq - D” , “ 标记”:“6” }, { “_key” :“A” , “_id” : “圆圈/ A” , “_rev” :“_VRZRUTq ---” , “ 标记”:“1” }, { “_key” :“E” , “_id” : “圆圈/ E” , “_rev” :“_VRZRUTq - C” , “ 标记”:“5” }, { “_key” :“C” , “_id” : “圆圈/ C” , “_rev” :“_VRZRUTq - A” , “ 标记”:“3” }, { “_key” :“D” , “_id” : “圆圈/ D” , “_rev” :“_VRZRUTq - B” , “ 标记”:“4” }, { “_key” :“J” , “_id” : “圆圈/ J” , “_rev” :“_VRZRUTu --_” , “ 标记”:“10” }, { “_key” :“B” , “_id” : “圆圈/ B” , “_rev” :“_VRZRUTq --_” , “ 标记”:“2” }, { “_key” :“H” , “_id” : “圆圈/ H” , “_rev” :“_VRZRUTq - F” , “ 标记”:“8” }, { “_key” :“K” , “_id” : “圆圈/ K” , “_rev” :“_VRZRUTu - A” , “ 标记”:“11” } ]aangosh> db.edges.toArray();[ { “_key” :“7561” , “_id” : “边缘/ 7561” , “_from” : “圆圈/ A” , “_to” : “圆圈/ B” , “_rev” :“_VRZRUTu - B” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_bar“ }, { “_key” :“7586” , “_id” : “边缘/ 7586” , “_from” : “圆圈/ G” , “_to” : “圆圈/ J” , “_rev” :“_VRZRUTy - C” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_zip“ }, { “_key” :“7568” , “_id” : “边缘/ 7568” , “_from” : “圆圈/ C” , “_to” : “圆圈/ D” , “_rev” :“_VRZRUTu - D” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_blorg“ }, { “_key” :“7577” , “_id” : “边缘/ 7577” , “_from” : “圆圈/ A” , “_to” : “圆圈/ G” , “_rev” :“_VRZRUTy --_” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_foo“ }, { “_key” :“7589” , “_id” : “边缘/ 7589” , “_from” : “圆圈/ J” , “_to” : “圆圈/ K” , “_rev” :“_VRZRUTy - D” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_zup“ }, { “_key” :“7565” , “_id” : “边缘/ 7565” , “_from” : “圆圈/ B” , “_to” : “圆圈/ C” , “_rev” :“_VRZRUTu - C” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_blarg“ }, { “_key” :“7583” , “_id” : “边缘/ 7583” , “_from” : “圆圈/ H” , “_to” : “圆圈/ I” , “_rev” :“_VRZRUTy - B” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_blub“ }, { “_key” :“7571” , “_id” : “边缘/ 7571” , “_from” : “圆圈/ B” , “_to” : “圆圈/ E” , “_rev” :“_VRZRUTu - E” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_blub“ }, { “_key” :“7580” , “_id” : “边缘/ 7580” , “_from” : “圆圈/ G” , “_to” : “圆圈/ H” , “_rev” :“_VRZRUTy - A” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_blob“ }, { “_key” :“7574” , “_id” : “边缘/ 7574” , “_from” : “圆圈/ E” , “_to” : “圆圈/ F” , “_rev” :“_VRZRUTy ---” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_schubi“ } ]
要开始我们选择完整的图表。为了更好的概述,我们只返回顶点ID:
arangosh> db._query(“FOR v IN 1..3 OUTBOUND”circles / A'GRAPH'遍历图'RETURN v._key“);[ “B” , “C” , “D” , “E” , “F” , “G” , “H” , “I” , “J” , “K” ][object ArangoQueryCursor,count:10,hasMore:false ]arangosh> db._query(“FOR v IN 1..3 OUTBOUND”circles / A'edges RETURN v._key“);[ “B” , “C” , “D” , “E” , “F” , “G” , “H” , “I” , “J” , “K” ][object ArangoQueryCursor,count:10,hasMore:false ]
我们可以很好地看到它正在朝向第一个外部顶点,然后返回到分支下降到下一个树。之后,它返回到我们的开始节点,再次下降。我们可以看到两个查询返回相同的结果,第一个使用命名图,第二个使用边缘集合直接。
现在我们只想要一个特定深度(min = max = 2)的元素,即后面的元素:
aangosh> db._query(“FOR v IN 2..2 OUTBOUND”circles / A'GRAPH'traversalGraph'return v._key“);[ “C”, “E”, “H”, “J” ][对象ArangoQueryCursor,count:4,hasMore:false ]aangosh> db._query(“FOR v IN 2 OUTBOUND”circles / A'GRAPH'遍历图返回v._key“);[ “C”, “E”, “H”, “J” ][对象ArangoQueryCursor,count:4,hasMore:false ]
可以看到,我们可以用两种方式表达:表达式中有或没有max参数。
过滤示例
现在我们开始添加一些过滤器。我们想在图表的右侧切割分支,我们可以通过两种方式进行过滤:
- 我们知道深度1的顶点为
_key
==G
- 我们知道
label
连接A到G的边的属性是right_foo
arangosh> db._query(“FOR v,e,p IN 1..3 OUTBOUND”circles / A'GRAPH'遍历图'FILTER p.vertices [1] ._ key!='G'RETURN v._key“);[ “B”, “C”, “D”, “E”, “F” ][object ArangoQueryCursor,count:5,hasMore:false ]arangosh> db._query(“FOR v,e,p IN 1..3 OUTBOUND”circles / A'GRAPH'遍历图'FILTER p.edges [0] .label!='right_foo'RETURN v._key“);[ “B”, “C”, “D”, “E”, “F” ][object ArangoQueryCursor,count:5,hasMore:false ]
我们可以看到G中的所有顶点在两个查询中被跳过。顶点上的第一个过滤器_key
,第二个在边缘标签上。再次注意,只要过滤器不符合三个要素中的任何一个 v
,e
或者p
完整的一组将被从结果中排除。
我们也可以组合几个过滤器,例如过滤右分支(G)和E分支:
arangosh> db._query(“FOR v,e,p IN 1..3 OUTBOUND”circles / A'GRAPH'遍历图'FILTER p.vertices [1] ._ key!='G'FILTER p.edges [1]。 label!='left_blub'return v._key“);[ “B”, “C”, “D” ][对象ArangoQueryCursor,count:3,hasMore:false ]aangosh> db._query(“FOR v,e,p IN 1..3 OUTBOUND”circles / A'GRAPH'traversalGraph'FILTER p.vertices [1] ._ key!='G'AND p.edges [1]。 label!='left_blub'return v._key“);[ “B”, “C”, “D” ][对象ArangoQueryCursor,count:3,hasMore:false ]
您可以看到,将两个FILTER
语句与一个AND
结果相结合。
比较OUTBOUND / INBOUND / ANY
所有我们以前的例子在OUTBOUND边缘方向上遍历图形。但是,您也可以反向(INBOUND)或两者(ANY)。因为circles/A
只有出站的边缘,我们开始从查询circles/E
:
aangosh> db._query(“FOR v IN 1..3 OUTBOUND”circles / E'GRAPH'遍历图返回v._key“);aangosh> db._query(“FOR v IN 1..3 INBOUND”circles / E'GRAPH'遍历图返回v._key“);arangosh> db._query(“FOR v IN 1..3 ANY”circles / E'GRAPH'遍历图返回v._key“);
第一个遍历只能沿前进(OUTBOUND)方向行进。因此,从Ë我们只能看到˚F。走向相反方向(INBOUND),我们看到A:B → A的路径。
走向正反方向(ANY),我们可以看到更多样化的结果。首先,我们看到了F和A的简单路径。然而,这些顶点在其他方向上具有边,它们将被遍历。
注意:运行器可以多次使用相同的边。举例来说,如果它行走Ë到˚F,它将继续从走路˚F到Ë 再次使用相同的边缘。因此,我们将在结果中看到重复的节点。
请注意,方向不能通过绑定参数传入。
使用AQL解释器进行优化
现在让我们看看优化器在幕后做什么,并使用explainer来检查遍历查询:
aangosh> db._explain(“FOR v,e,p IN 1..3 OUTBOUND”circles / A'GRAPH'遍历图'LET localScopeVar = RAND()> 0.5 FILTER p.edges [0] .theTruth!= localScopeVar RETURN v ._key“,{},{colors:false});arangosh> db._explain(“FOR v,e,p IN 1..3 OUTBOUND”circles / A'GRAPH'遍历图'FILTER p.edges [0] .label =='right_foo'RETURN v._key“,{} ,{colors:false});
我们现在看到两个查询:在一个中,我们添加一个变量localScopeVar,它不在遍历本身的范围内 - 在遍历器内部是不知道的。因此,该过滤器只能在遍历之后执行,这在大图中可能是不期望的。另一方面,第二个查询仅在路径上运行,因此在执行遍历期间可以使用此条件。根据此条件筛选出的路径将不会被处理。
最后再次清理一下:
a 例子> var examples = require(“@ arangodb / graph-examples / example-graph.js”);arangosh> examples.dropGraph(“traversalGraph”);真正
如果这种遍历对您的需求不够强大,就像您无法将条件描述为AQL过滤器语句,那么您可能需要查看 手动设计的运行程序。
另请参阅如何组合图遍历。
AQL最短路径
一般查询想法
这种类型的查询应该在图中找到两个给定文档(startVertex和targetVertex)之间的最短路径。对于这个最短路径上的所有顶点,您将得到一个具有两个项目的集合的结果:
- 这个路径上的顶点。
- 边缘指向它。
示例执行
让我们来看一个简单的例子来解释它是如何工作的。这是我们要找到最短路径的图表:
现在我们使用以下参数进行查询:
- 我们从顶点A开始。
- 我们完成与顶点ð。
所以很明显,我们将按照这个顺序在最短路径上有顶点A,B,C和D。比最短的路径语句将返回以下对:
顶点 边缘 一个空值乙A→BCB→CðC→D注意:第一个边缘将始终是
null
因为没有边缘指向startVertex。句法
现在我们来看看如何编写最短路径查询。您有两个选项,您可以使用命名图或一组边集(匿名图)。
使用命名图
FOR vertex[, edge] IN OUTBOUND|INBOUND|ANY SHORTEST_PATH startVertex TO targetVertex GRAPH graphName [OPTIONS options]
FOR
:最多发射两个变量:- vertex(object):当前顶点在最短路径上
- 边(对象,可选):指向顶点的边
IN
OUTBOUND|INBOUND|ANY
:定义沿着哪个方向边缘(传出,传入或两者)- startVertex
TO
targetVertex(两个字符串|对象):两个顶点之间的最短路径将被计算。这可以以ID字符串的形式或具有该属性的文档的形式指定_id
。所有其他值将导致警告和空的结果。如果其中一个指定的文档不存在,结果也是空的,没有警告。 GRAPH
graphName(string):标识命名图形的名称。它的顶点和边缘集合将被查找。OPTIONS
options(object,optional):用于修改遍历的执行。只有以下属性有效果,所有其他属性将被忽略:- weightAttribute(string):应用于读取边缘权重的顶级边缘属性。如果属性不存在或不是数字,则将使用defaultWeight。
- defaultWeight(number):如果边缘文档中没有weightAttribute,或者不是数字,则此值将用作回退。默认值为1。
使用集合集
FOR vertex[, edge] IN OUTBOUND|INBOUND|ANY SHORTEST_PATH startVertex TO targetVertex edgeCollection1, ..., edgeCollectionN [OPTIONS options]
而不是GRAPH graphName
您可以指定边缘集合列表(匿名图)。所涉及的顶点集合由给定边集合的边确定。其余的行为与命名版本相似。
横向混合
对于具有边集合列表的最短路径,您可以选择指定某些边集合的方向。例如,你有三个边缘集合edge1,edge2和edge3,其中在edge2方向上没有相关性,但是在edge1和edge3中应该考虑方向。在这种情况下,您可以使用OUTBOUND作为常规搜索方向,并且任何 专门用于edge2的方式如下:
FOR vertex IN OUTBOUND SHORTEST_PATH startVertex TO targetVertex edges1, ANY edges2, edges3
列表中没有指定自己的方向的所有集合将使用IN(此处:OUTBOUND)之后定义的方向。这允许在您的路径搜索中为每个集合使用不同的方向。
条件最短路径
SHORTEST_PATH计算将只找到一个无条件的最短路径。使用这个结构,不可能定义一个条件,如:“找到所有边都是X类型的最短路径”。如果你想这样做,使用正常的横越代替与选项{bfs: true}
组合LIMIT 1
。
例子
我们将创建一个简单的对称遍历演示图:
a 例子> var examples = require(“@ arangodb / graph-examples / example-graph.js”);aangosh> var graph = examples.loadGraph(“traversalGraph”);aangosh> db.circles.toArray();[ { “_key” :“I” , “_id” : “圈/ I” , “_rev” :“_VRZRUPK - E” , “ 标签”:“9” }, { “_key” :“G” , “_id” : “圆圈/ G” , “_rev” :“_VRZRUPK - C” , “ 标记”:“7” }, { “_key” :“F” , “_id” : “圆圈/ F” , “_rev” :“_VRZRUPK - B” , “ 标记”:“6” }, { “_key” :“A” , “_id” : “圆圈/ A” , “_rev” :“_VRZRUPG ---” , “ 标记”:“1” }, { “_key” :“E” , “_id” : “圆圈/ E” , “_rev” :“_VRZRUPK - A” , “ 标记”:“5” }, { “_key” :“C” , “_id” : “圆圈/ C” , “_rev” :“_VRZRUPK ---” , “ 标记”:“3” }, { “_key” :“D” , “_id” : “圆圈/ D” , “_rev” :“_VRZRUPK --_” , “ 标记”:“4” }, { “_key” :“J” , “_id” : “圆圈/ J” , “_rev” :“_VRZRUPK - F” , “ 标记”:“10” }, { “_key” :“B” , “_id” : “圆圈/ B” , “_rev” :“_VRZRUPG --_” , “ 标记”:“2” }, { “_key” :“H” , “_id” : “圆圈/ H” , “_rev” :“_VRZRUPK - D” , “ 标记”:“8” }, { “_key” :“K” , “_id” : “圆圈/ K” , “_rev” :“_VRZRUPO ---” , “ 标记”:“11” } ]aangosh> db.edges.toArray();[ { “_key” :“7505” , “_id” : “边缘/ 7505” , “_from” : “圆圈/ J” , “_to” : “圆圈/ K” , “_rev” :“_VRZRUPS - C” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_zup“ }, { “_key” :“7499” , “_id” : “边缘/ 7499” , “_from” : “圆圈/ H” , “_to” : “圆圈/ I” , “_rev” :“_VRZRUPS - A” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_blub“ }, { “_key” :“7487” , “_id” : “边缘/ 7487” , “_from” : “圆圈/ B” , “_to” : “圆圈/ E” , “_rev” :“_VRZRUPO - C” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_blub“ }, { “_key” :“7493” , “_id” : “边缘/ 7493” , “_from” : “圆圈/ A” , “_to” : “圆圈/ G” , “_rev” :“_VRZRUPS ---” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_foo“ }, { “_key” :“7496” , “_id” : “边缘/ 7496” , “_from” : “圆圈/ G” , “_to” : “圆圈/ H” , “_rev” :“_VRZRUPS --_” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_blob“ }, { “_key” :“7490” , “_id” : “边缘/ 7490” , “_from” : “圆圈/ E” , “_to” : “圆圈/ F” , “_rev” :“_VRZRUPO - D” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_schubi“ }, { “_key” :“7502” , “_id” : “边缘/ 7502” , “_from” : “圆圈/ G” , “_to” : “圆圈/ J” , “_rev” :“_VRZRUPS - B” ,“ theFalse“:false, ”theTruth“:true, ”label“:”right_zip“ }, { “_key” :“7481” , “_id” : “边缘/ 7481” , “_from” : “圆圈/ B” , “_to” : “圆圈/ C” , “_rev” :“_VRZRUPO - A” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_blarg“ }, { “_key” :“7484” , “_id” : “边缘/ 7484” , “_from” : “圆圈/ C” , “_to” : “圆圈/ D” , “_rev” :“_VRZRUPO - B” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_blorg“ }, { “_key” :“7477” , “_id” : “边缘/ 7477” , “_from” : “圆圈/ A” , “_to” : “圆圈/ B” , “_rev” :“_VRZRUPO --_” ,“ theFalse“:false, ”theTruth“:true, ”label“:”left_bar“ } ]
我们从A到D的最短路径开始如上:
aangosh> db._query(“FOR v,e IN OUTBOUND SHORTEST_PATH”circles / A'TO'circles / D'GRAPH'遍历图'返回[v._key,e._key]“);[ [ “A”, null ] [ “B”, “7477” ] [ “C”, “7481” ] [ “D”, “7484” ] ][对象ArangoQueryCursor,count:4,hasMore:false ]aangosh> db._query(“FOR v,e IN OUTBOUND SHORTEST_PATH”circles / A'TO'circles / D'edges RETURN [v._key,e._key]“);[ [ “A”, null ] [ “B”, “7477” ] [ “C”, “7481” ] [ “D”, “7484” ] ][对象ArangoQueryCursor,count:4,hasMore:false ]
我们可以看到我们的期望得到实现。我们发现顶点的顺序是正确的,第一个边是空的,因为没有边缘指向他的路径上的起始顶点。
我们还可以根据集合中的文档计算最短路径:
arangosh> db._query(“FOR a IN circles FILTER a._key =='A'FOR d IN圈FILTER d._key =='D'FOR v,e IN OUTBOUND SHORTEST_PATH a TO d GRAPH'遍历图'返回[v ._key,e._key]“);[ [ “A”, null ] [ “B”, “7477” ] [ “C”, “7481” ] [ “D”, “7484” ] ][对象ArangoQueryCursor,count:4,hasMore:false ]aangosh> db._query(“FOR a IN circles FILTER a._key =='A'FOR d IN圈FILTER d._key =='D'FOR v,e IN OUTBOUND SHORTEST_PATH a TO d edges RETURN [v._key, e._key]“);[ [ “A”, null ] [ “B”, “7477” ] [ “C”, “7481” ] [ “D”, “7484” ] ][对象ArangoQueryCursor,count:4,hasMore:false ]
最后再次清理一下:
a 例子> var examples = require(“@ arangodb / graph-examples / example-graph.js”);arangosh> examples.dropGraph(“traversalGraph”);
- ArangoDB AQL中的图形绘制遍历
- 图形绘制中的PorterDuffXfermode
- 使用Office2000中的图表控件绘制图形~
- 利用python中的turtle库绘制图形
- 绘制图形
- 绘制图形
- 绘制图形
- 绘制图形
- 绘制图形
- 图形绘制
- 绘制图形
- 图形绘制
- 绘制图形
- 绘制图形
- 图形绘制
- 图形绘制
- 绘制图形
- 图形绘制
- java发送手机验证码
- sqlserver 表被哪个过程引用
- Perl脚本中Expect模块的学习使用
- 通俗、有逻辑的写一篇说下Xgboost的原理,供讨论参考
- 输入相应类型的字符串并显示
- ArangoDB AQL中的图形绘制遍历
- Application.mk的文件梳理
- 学习SpringMVC
- 在windows上部署使用Redis
- PAT 1055集体照
- Java学习之抽象类
- centOS7 iptables防火墙配置脚本
- AtCoder Grand Contest 018 E
- 向oralce表中添加数据时如何让主键自增