Arangodb 简明教程
ArangoDB - AQL Example Queries
在本章中,我们将思考一个 @ {s0} 数据库上的几个 AQL 示例查询。这些查询都基于图表。
Problem
给定一组演员和一组电影,以及一个 actIn 边缘集合(带有一个 year 属性)以按照如下所示的方式连接顶点 −
@ {s1}
我们如何获得 −
-
在“movie1”或“movie2”中演出的所有演员?
-
在“movie1”和“movie2”中都演出的所有演员?
-
“actor1”和“actor2”之间的所有公共电影?
-
在 3 部或更多电影中演出的所有演员?
-
正好 6 位演员出演的所有电影?
-
根据电影的演员数量?
-
根据演员的电影数量?
-
在 2005 年到 2010 年之间演员出演的电影数量?
Solution
在解决上述查询并获取答案的过程中,我们将使用 Arangosh 创建数据集并在其上运行查询。所有 AQL 查询都是字符串,可以轻松复制到您的首选驱动程序中,而不是 Arangosh。
我们首先在 Arangosh 中创建一个测试数据集。首先,下载 @ {s2} −
# wget -O dataset.js
https://drive.google.com/file/d/0B4WLtBDZu_QWMWZYZ3pYMEdqajA/view?usp=sharing
Output
...
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘dataset.js’
dataset.js [ <=> ] 115.14K --.-KB/s in 0.01s
2017-09-17 14:19:12 (11.1 MB/s) - ‘dataset.js’ saved [117907]
您可以在以上输出中看到,我们下载了一个 JavaScript 文件 @ {s3}。该文件包含用于在数据库中创建数据集的 Arangosh 命令。我们不会逐个复制和粘贴这些命令,而是使用 Arangosh 上的 @ {s4} 选项来非交互式地执行多个命令。这简直是救命命令!
现在在 shell 上执行以下命令 −
$ arangosh --javascript.execute dataset.js
当提示时提供密码,如您在上述屏幕截图中看到的。现在我们已经保存了数据,因此我们将构建 AQL 查询来回答本章开头提出的具体问题。
First Question
我们来看第一个问题:@ {s5}。假设,我们想要找到在“TheMatrix”或“TheDevilsAdvocate”中演出的所有演员的姓名 −
我们将每次处理一部电影,以获取演员姓名 −
127.0.0.1:8529@_system> db._query("FOR x IN ANY 'movies/TheMatrix' actsIn
OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN x._id").toArray();
Output
我们将接收以下输出 −
[
"actors/Hugo",
"actors/Emil",
"actors/Carrie",
"actors/Keanu",
"actors/Laurence"
]
现在,我们继续形成两个 NEIGHBORS 查询的 UNION_DISTINCT,这将是解决方案 −
127.0.0.1:8529@_system> db._query("FOR x IN UNION_DISTINCT ((FOR y IN ANY
'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN
y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true,
uniqueVertices: 'global'} RETURN y._id)) RETURN x").toArray();
Output
[
"actors/Charlize",
"actors/Al",
"actors/Laurence",
"actors/Keanu",
"actors/Carrie",
"actors/Emil",
"actors/Hugo"
]
Second Question
现在,我们考虑第二个问题: All actors who acted in both "movie1" AND "movie2" 。这几乎与上述问题完全相同。但这次,我们不感兴趣于 UNION,而感兴趣于 INTERSECTION −
127.0.0.1:8529@_system> db._query("FOR x IN INTERSECTION ((FOR y IN ANY
'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN
y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true,
uniqueVertices: 'global'} RETURN y._id)) RETURN x").toArray();
Third Question
现在,我们考虑第三个问题: All common movies between "actor1" and "actor2" 。这实际上与电影 1 和电影 2 中的共同演员问题完全相同。我们只需要更改起始顶点即可。例如,让我们找出让休·杰克曼(Hugo)和基努·里维斯共同主演的所有电影 −
127.0.0.1:8529@_system> db._query(
"FOR x IN INTERSECTION (
(
FOR y IN ANY 'actors/Hugo' actsIn OPTIONS
{bfs: true, uniqueVertices: 'global'}
RETURN y._id
),
(
FOR y IN ANY 'actors/Keanu' actsIn OPTIONS
{bfs: true, uniqueVertices:'global'} RETURN y._id
)
)
RETURN x").toArray();
Output
我们将接收以下输出 −
[
"movies/TheMatrixReloaded",
"movies/TheMatrixRevolutions",
"movies/TheMatrix"
]
Fourth Question
现在,我们考虑第四个问题。 All actors who acted in 3 or more movies 。这个问题有所不同;我们不能在此处使用邻居函数。相反,我们将利用 AQL 的边缘索引和 COLLECT 语句进行分组。基本思想是按 startVertex (在该数据集始终为演员)对所有边缘进行分组。然后,我们从结果中删除电影数量少于 3 的所有演员,因为此处我们已纳入演员参演的电影数量 −
127.0.0.1:8529@_system> db._query("FOR x IN actsIn COLLECT actor = x._from WITH
COUNT INTO counter FILTER counter >= 3 RETURN {actor: actor, movies:
counter}"). toArray()
Output
[
{
"actor" : "actors/Carrie",
"movies" : 3
},
{
"actor" : "actors/CubaG",
"movies" : 4
},
{
"actor" : "actors/Hugo",
"movies" : 3
},
{
"actor" : "actors/Keanu",
"movies" : 4
},
{
"actor" : "actors/Laurence",
"movies" : 3
},
{
"actor" : "actors/MegR",
"movies" : 5
},
{
"actor" : "actors/TomC",
"movies" : 3
},
{
"actor" : "actors/TomH",
"movies" : 3
}
]
对于剩余的问题,我们将讨论查询形成,并仅提供查询。读者应在 Arangosh 终端上自行运行查询。
Fifth Question
现在,我们考虑第五个问题: All movies where exactly 6 actors acted in 。思路与之前的查询相同,但使用等式筛选器。然而,现在我们需要电影而不是演员,所以我们返回 _to attribute −
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER
counter == 6 RETURN movie").toArray()
根据电影的演员数量?
我们记得在我们的数据集 _to 中,边缘对应于电影,所以我们统计 _to 出现的次数。这是演员数量。该查询几乎与之前的查询相同,但 without the FILTER after COLLECT −
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN
{movie: movie, actors: counter}").toArray()