ArangoDB – AQL 示例查询
ArangoDB – AQL 示例查询
在本章中,我们将考虑演员和电影数据库上的一些 AQL 示例查询。这些查询基于图形。
问题
给定一组演员和一组电影,以及一个 actIn 边缘集合(具有年份属性)以连接顶点,如下所示 –
[演员] <- 出演-> [电影]
我们如何获得 –
- 所有在“电影1”或“电影2”中演出的演员?
- 所有在“电影1”和“电影2”中都出演过的演员?
- “actor1”和“actor2”之间的所有常见电影?
- 所有出演过 3 部或更多电影的演员?
- 全部由 6 位演员出演的电影?
- 电影的演员人数?
- 演员的电影数量?
- 2005 年到 2010 年由演员出演的电影数量是多少?
解决方案
在解决和获得上述查询的答案的过程中,我们将使用 Arangosh 创建数据集并对其运行查询。所有 AQL 查询都是字符串,可以简单地复制到您最喜欢的驱动程序而不是 Arangosh。
让我们从在 Arangosh 中创建一个测试数据集开始。首先,下载此文件–
# wget -O dataset.js https://drive.google.com/file/d/0B4WLtBDZu_QWMWZYZ3pYMEdqajA/view?usp=sharing
输出
... 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 文件dataset.js。该文件包含用于在数据库中创建数据集的 Arangosh 命令。我们将使用Arangosh上的–javascript.execute选项以非交互方式执行多个命令,而不是一个一个地复制和粘贴命令。将其视为救生命令!
现在在 shell 上执行以下命令 –
$ arangosh --javascript.execute dataset.js
如上图所示,在提示时提供密码。现在我们已经保存了数据,因此我们将构建 AQL 查询来回答本章开头提出的具体问题。
第一个问题
让我们来回答第一个问题:所有在“电影1”或“电影2”中演出的演员。假设,我们想要找到在“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();
输出
我们将收到以下输出 –
[ "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();
输出
[ "actors/Charlize", "actors/Al", "actors/Laurence", "actors/Keanu", "actors/Carrie", "actors/Emil", "actors/Hugo" ]
第二个问题
现在让我们考虑第二个问题:所有在 “movie1” 和 “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();
输出
我们将收到以下输出 –
[ "actors/Keanu" ]
第三个问题
现在让我们考虑第三个问题:“actor1”和“actor2”之间的所有常见电影。这其实和关于movie1和movie2中共同演员的问题是一样的。我们只需要改变起始顶点。例如,让我们找出雨果·维文(“雨果”)和基努·里维斯共同主演的所有电影 –
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();
输出
我们将收到以下输出 –
[ "movies/TheMatrixReloaded", "movies/TheMatrixRevolutions", "movies/TheMatrix" ]
第四题
现在让我们考虑第四个问题。所有出演过 3 部或更多电影的演员。这个问题不同;我们不能在这里使用邻居功能。相反,我们将使用 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()
输出
[ { "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 终端上运行查询。
第五题
现在让我们考虑第五个问题:恰好 6 位演员出演的所有电影。与之前查询中的想法相同,但使用相等过滤器。但是,现在我们需要电影而不是演员,所以我们返回_to 属性–
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER counter == 6 RETURN movie").toArray()
电影的演员人数?
我们记得在我们的数据集中_to边缘对应于电影,因此我们计算相同_to出现的频率。这是演员的数量。该查询与之前的查询几乎相同,但在 COLLECT 之后没有 FILTER –
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN {movie: movie, actors: counter}").toArray()
第六题
现在让我们考虑第六个问题:演员的电影数量。
我们为上述查询找到解决方案的方式也将帮助您找到此查询的解决方案。
db._query("FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter RETURN {actor: actor, movies: counter}").toArray()