ArangoDB - Consultas de exemplo de AQL
Neste capítulo, consideraremos alguns exemplos de consultas de AQL em um Actors and MoviesBase de dados. Essas consultas são baseadas em gráficos.
Problema
Dada uma coleção de atores e uma coleção de filmes, e uma coleção de bordas actIn (com uma propriedade de ano) para conectar o vértice conforme indicado abaixo -
[Actor] <- act in -> [Movie]
Como podemos obter -
- Todos os atores que atuaram em "movie1" OU "movie2"?
- Todos os atores que atuaram em "movie1" E "movie2"?
- Todos os filmes comuns entre "ator1" e "ator2"?
- Todos os atores que atuaram em 3 ou mais filmes?
- Todos os filmes em que exatamente 6 atores atuaram?
- O número de atores por filme?
- O número de filmes por ator?
- A quantidade de filmes atuados entre 2005 e 2010 por ator?
Solução
Durante o processo de resolução e obtenção das respostas às consultas acima, usaremos Arangosh para criar o conjunto de dados e executar consultas sobre ele. Todas as consultas AQL são strings e podem simplesmente ser copiadas para o seu driver favorito em vez do Arangosh.
Vamos começar criando um conjunto de dados de teste na Arangosh. Primeiro, baixe este arquivo -
# wget -O dataset.js
https://drive.google.com/file/d/0B4WLtBDZu_QWMWZYZ3pYMEdqajA/view?usp=sharing
Resultado
...
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]
Você pode ver na saída acima que baixamos um arquivo JavaScript dataset.js.Este arquivo contém os comandos Arangosh para criar o conjunto de dados no banco de dados. Em vez de copiar e colar os comandos um por um, usaremos o--javascript.executeopção no Arangosh para executar os vários comandos de forma não interativa. Considere isso o comando salva-vidas!
Agora execute o seguinte comando no shell -
$ arangosh --javascript.execute dataset.js
Forneça a senha quando solicitado, como você pode ver na imagem acima. Agora que salvamos os dados, construiremos as consultas AQL para responder às questões específicas levantadas no início deste capítulo.
Primeira pergunta
Deixe-nos responder à primeira pergunta: All actors who acted in "movie1" OR "movie2". Suponha que queremos encontrar os nomes de todos os atores que atuaram em "TheMatrix" OU "TheDevilsAdvocate" -
Começaremos com um filme de cada vez para obter os nomes dos atores -
127.0.0.1:[email protected]_system> db._query("FOR x IN ANY 'movies/TheMatrix' actsIn
OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN x._id").toArray();
Resultado
Receberemos a seguinte saída -
[
"actors/Hugo",
"actors/Emil",
"actors/Carrie",
"actors/Keanu",
"actors/Laurence"
]
Agora continuamos a formar um UNION_DISTINCT de duas consultas NEIGHBORS que serão a solução -
127.0.0.1:[email protected]_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();
Resultado
[
"actors/Charlize",
"actors/Al",
"actors/Laurence",
"actors/Keanu",
"actors/Carrie",
"actors/Emil",
"actors/Hugo"
]
Segunda questão
Vamos agora considerar a segunda questão: All actors who acted in both "movie1" AND "movie2". Isso é quase idêntico à pergunta acima. Mas desta vez não estamos interessados em uma UNIÃO, mas sim em uma INTERSECÇÃO -
127.0.0.1:[email protected]_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();
Resultado
Receberemos a seguinte saída -
[
"actors/Keanu"
]
Terceira pergunta
Vamos agora considerar a terceira questão: All common movies between "actor1" and "actor2". Na verdade, isso é idêntico à pergunta sobre atores comuns em movie1 e movie2. Só temos que mudar os vértices iniciais. Como exemplo, vamos encontrar todos os filmes em que Hugo Weaving ("Hugo") e Keanu Reeves estão co-estrelando -
127.0.0.1:[email protected]_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();
Resultado
Receberemos a seguinte saída -
[
"movies/TheMatrixReloaded",
"movies/TheMatrixRevolutions",
"movies/TheMatrix"
]
Quarta Pergunta
Vamos agora considerar a quarta questão. All actors who acted in 3 or more movies. Essa questão é diferente; não podemos fazer uso da função de vizinhos aqui. Em vez disso, faremos uso do índice de borda e da instrução COLLECT de AQL para agrupamento. A ideia básica é agrupar todas as arestas por seusstartVertex(que neste conjunto de dados é sempre o ator). Em seguida, removemos todos os atores com menos de 3 filmes do resultado, pois aqui incluímos o número de filmes em que um ator atuou -
127.0.0.1:[email protected]_system> db._query("FOR x IN actsIn COLLECT actor = x._from WITH
COUNT INTO counter FILTER counter >= 3 RETURN {actor: actor, movies:
counter}"). toArray()
Resultado
[
{
"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
}
]
Para as questões restantes, discutiremos a formação da consulta e forneceremos apenas as consultas. O leitor deve executar a consulta por conta própria no terminal Arangosh.
Quinta pergunta
Vamos agora considerar a quinta questão: All movies where exactly 6 actors acted in. A mesma ideia da consulta anterior, mas com o filtro de igualdade. No entanto, agora precisamos do filme em vez do ator, então devolvemos o_to attribute -
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER
counter == 6 RETURN movie").toArray()
O número de atores por filme?
Lembramos em nosso conjunto de dados _to na borda corresponde ao filme, então contamos quantas vezes o mesmo _toparece. Este é o número de atores. A consulta é quase idêntica às anteriores, maswithout the FILTER after COLLECT -
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN
{movie: movie, actors: counter}").toArray()
Sexta Questão
Vamos agora considerar a sexta questão: The number of movies by an actor.
A maneira como encontramos soluções para nossas dúvidas acima o ajudará a encontrar a solução para essa consulta também.
db._query("FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter
RETURN {actor: actor, movies: counter}").toArray()