В этой главе мы рассмотрим несколько примеров запросов AQL к базе данных актеров и фильмов . Эти запросы основаны на графиках.
проблема
Имея коллекцию актеров, коллекцию фильмов и коллекцию ребер actIn (со свойством year) для соединения вершины, как показано ниже —
[Актер] <- сниматься в -> [Фильм]
Как мы получаем —
- Все актеры, которые действовали в «movie1» ИЛИ «movie2»?
- Все актеры, которые снимались в фильмах «кино1» и «кино2»?
- Все общие фильмы между «актер1» и «актер2»?
- Все актеры, которые снимались в 3 и более фильмах?
- Во всех фильмах, где снимались ровно 6 актеров?
- Количество актеров по фильмам?
- Количество фильмов по актеру?
- Количество фильмов, сыгранных актером в период с 2005 по 2010 год?
Решение
В процессе решения и получения ответов на вышеупомянутые запросы мы будем использовать Arangosh для создания набора данных и выполнения запросов по нему. Все запросы AQL являются строками и могут быть просто скопированы в ваш любимый драйвер вместо 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 для создания набора данных в базе данных. Вместо того, чтобы копировать и вставлять команды одну за другой, мы будем использовать опцию —javascript.execute на Arangosh, чтобы выполнять несколько команд неинтерактивно. Считайте, что это команда спасателей жизни!
Теперь выполните следующую команду на оболочке —
$ arangosh --javascript.execute dataset.js
Введите пароль при появлении запроса, как вы можете видеть на скриншоте выше. Теперь мы сохранили данные, поэтому мы создадим запросы AQL, чтобы ответить на конкретные вопросы, поднятые в начале этой главы.
Первый вопрос
Давайте возьмем первый вопрос: все актеры, которые действовали в «movie1» ИЛИ «movie2» . Предположим, мы хотим найти имена всех актеров, которые действовали в «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" ]
Теперь мы продолжаем формировать UNION_DISTINCT из двух запросов NEIGHBORS, которые будут решением —
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» . Это почти идентично вопросу выше. Но на этот раз нас интересует не СОЮЗ, а ПЕРЕКЛЮЧЕНИЕ —
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 и более фильмах . Этот вопрос другой; мы не можем использовать функцию соседей здесь. Вместо этого мы будем использовать краевой индекс и оператор COLLECT AQL для группировки. Основная идея состоит в том, чтобы сгруппировать все ребра по их 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 —
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN {movie: movie, actors: counter}").toArray()
Шестой вопрос
Давайте теперь рассмотрим шестой вопрос: количество фильмов актера .
То, как мы нашли решения для наших вышеупомянутых запросов, поможет вам найти решение и для этого запроса.