ArangoDB - AQL 示例查询
在本章中,我们将考虑演员和电影数据库上的一些 AQL 示例查询。 这些查询基于图表。
问题
给定演员集合和电影集合,以及用于连接顶点的 actIn 边集合(具有年份属性),如下所示 −
[Actor] <- act in -> [Movie]
我们如何获得 −
- 所有出演过"电影 1"或"电影 2"的演员?
- 所有在"电影 1"和"电影 2"中出演过的演员?
- "actor1"和"actor2"之间所有常见的电影?
- 所有出演过 3 部或以上电影的演员?
- 所有电影均由 6 名演员出演?
- 每部电影的演员人数?
- 演员出演的电影数量?
- 演员在 2005 年至 2010 年间出演了多少部电影?
解决方案
在解决并获得上述查询的答案的过程中,我们将使用 Arangosh 创建数据集并对其运行查询。 所有 AQL 查询都是字符串,可以简单地复制到您最喜欢的驱动程序而不是 Arangosh。
让我们首先在 Arangosh 中创建一个测试数据集。 首先,下载C:\Apache24\htdocs\arangodb\dataset.js 这个文件 −
# 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" ]
第二个问题
现在让我们考虑第二个问题:同时出演"电影 1"和"电影 2"的所有演员。 这与上面的问题几乎相同。 但这一次我们对并集不感兴趣,而是对交集感兴趣 −
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()