Vue d’ensemble
L'instruction CALL
vous permet d'exécuter une procédure, soit seule, soit comme partie intégrante d'une requête plus large. Une procédure peut être soit définie par le système (appelée procédure nommée), soit définie manuellement dans la requête (appelée procédure en ligne).
<call procedure statement> ::= [ "OPTIONAL" ] "CALL" <procedure call>
<procedure call> ::= <named procedure call> | <inline procedure call>
Détails
- Le mot-clé
OPTIONAL
peut être utilisé pour gérer les cas où la procédure pourrait ne pas retourner de résultats. Si aucun résultat n'est trouvé, il produit des valeursnull
à la place.
Exemple de Graph
Les exemples suivants s'exécutent sur ce graph :
Pour créer ce graph, exécutez la requête suivante sur un graph vide :
INSERT (rowlock:User {_id:'U01', name:'rowlock'}),
(brainy:User {_id:'U02', name:'Brainy'}),
(purplechalk:User {_id:'U03', name:'purplechalk'}),
(mochaeach:User {_id:'U04', name:'mochaeach'}),
(lionbower:User {_id:'U05', name:'lionbower'}),
(c01:Club {_id:'C01'}),
(c02:Club {_id:'C02'}),
(rowlock)-[:Follows]->(brainy),
(mochaeach)-[:Follows]->(brainy),
(brainy)-[:Follows]->(purplechalk),
(purplechalk)-[:Follows]->(brainy),
(lionbower)-[:Follows]->(purplechalk),
(brainy)-[:Joins]->(c01),
(lionbower)-[:Joins]->(c01),
(mochaeach)-[:Joins]->(c02)
Appels de Procédure Nommée
L'instruction CALL
peut invoquer une procédure prédéfinie déployée dans la base de données. Ultipa offre une gamme de procédures intégrées.
<named procedure call> ::=
<procedure reference> "(" [ <procedure argument list> ] ")" [ <yield clause> ]
<procedure argument list> ::=
<procedure argument> [ { "," <procedure argument> }... ]
<procedure argument> ::= <value expression>
Détails
- La clause
YIELD
peut être utilisée pour sélectionner et renommer les colonnes de la table de liaison (si disponible) produite par la procédure nommée, permettant de les exposer et de les référencer dans les parties suivantes de la requête.
Création d’un Graph HDC
Cette requête appelle la procédure hdc.graph.create
pour projeter tout le graph actuel en tant que graph HDC hdc_g1
sur le serveur HDC hdc-server-1
:
CALL hdc.graph.create("hdc-server-1", "hdc_g1", {
nodes: {"*": ["*"]},
edges: {"*": ["*"]},
query: "query",
type: "Graph",
update: "static",
default: true
})
Affichage du Graph HDC
Cette requête appelle la procédure hdc.graph.show
pour récupérer tous les graphs HDC du graph actuel :
CALL hdc.graph.show()
Résultat : _projectList
project_name | project_type | filter_type | is_default | graph_name | status | stats | hdc_server_name | hdc_server_status | config |
---|---|---|---|---|---|---|---|---|---|
hdc_g1 | central | hdc_graph | true | Doc7 | DONE | {"edge_count":7,"edge_schema":{"Follows":{"id":2,"name":"Follows","properties":null},"Joins":{"id":3,"name":"Joins","properties":null}},"node_count":7,"node_schema":{"Club":{"id":3,"name":"Club","properties":null},"User":{"id":2,"name":"User","properties":[{"id":101,"name":"name","sub_types":null,"type":7}]}}} | hdc-server-1 | ALIVE | {"edge_schema_map":"{"Follows":[],"Joins":[],"default":[]}","hdc_server_name":"hdc-server-1","job_type":"central","node_schema_map":"{"Club":[],"User":["name"],"default":[]}","orientation":"Graph","query":"query","shard_ids":[1],"update":"static"} |
Cette requête appelle la procédure hdc.graph.show
pour récupérer le graph HDC hdc_g1
du graph actuel :
CALL hdc.graph.show("hdc_g1")
Suppression du Graph HDC
Cette requête appelle la procédure hdc.graph.drop
pour supprimer le graph HDC hdc_g2
du graph actuel :
CALL hdc.graph.drop("hdc_g2")
Affichage des Tâches
Cette requête appelle la procédure job.show
pour récupérer toutes les tâches dans le graph actuel :
CALL job.show()
Résultat: result
job_id | graph_name | type | uql | status | err_msg | result | start_time | end_time | progress |
---|---|---|---|---|---|---|---|---|---|
1 | Doc7 | CREATE_HDC_GRAPH | CALL hdc.graph.create("hdc-server-1", "hdc_g1", { nodes: {"": [""]}, edges: {"": [""]}, query: "query", type: "Graph", update: "static", default: true }) | FINISHED | {"edge_count":7,"edge_schema":{"Follows":{"id":2,"name":"Follows","properties":null},"Joins":{"id":3,"name":"Joins","properties":null}},"node_count":7,"node_schema":{"Club":{"id":3,"name":"Club","properties":null},"User":{"id":2,"name":"User","properties":[{"id":101,"name":"name","sub_types":null,"type":7}]}}} | 2024-09-18 17:54:55 | 2024-09-18 17:54:57 |
Cette requête appelle la procédure job.show
pour récupérer la tâche avec job_id
comme 1
dans le graph actuel :
CALL job.show("1")
Exécution de l'Algorithme HDC
Cette requête appelle la procédure hdc.algo.degree
pour exécuter l'algorithme de Centralité de Degré sur le graph HDC hdc_g1
:
call hdc.algo.degree("hdc_g1", {
order: "desc"
}) YIELD r
RETURN r
Résultat: r
_uuid | degree_centrality |
---|---|
13042426719888211970 | 5.000000 |
3602881900919652355 | 3.000000 |
1585269267857670149 | 2.000000 |
3458766712843796484 | 2.000000 |
1008809615065874438 | 2.000000 |
18374688678694879233 | 1.000000 |
576464050838306823 | 1.000000 |
Exécution de l'Algorithme HDC avec Rétroécriture
Cette requête appelle la procédure hdc.algo.degree.write
pour exécuter l'algorithme de Centralité de Degré sur le graph HDC hdc_g1
et écrire les résultats dans le fichier degree.txt
:
CALL hdc.algo.degree.write("hdc_g1", {
params: {
order: "desc"
},
return_params: {
file: {
filename: "degree.txt"
}
}
})
Appels de Procédure En Ligne
<inline procedure call> ::= [ <variable scope clause> ] <nested procedure specification>
<variable scope clause> ::= "(" [ <binding variable reference list> ] ")"
<binding variable reference list> ::=
<binding variable reference> [ { "," <binding variable reference> }... ]
<binding variable reference> ::= <binding variable>
<nested procedure specification> ::= "{" <procedure specification> "}"
<procedure specification> ::=
<catalog-modifying procedure specification>
| <data-modifying procedure specification>
| <query specification>
<catalog-modifying procedure specification> ::= <procedure body>
<nested data-modifying procedure specification> ::=
"{" <data-modifying procedure specification> "}"
<data-modifying procedure specification> ::= <procedure body>
<nested query specification> ::= "{" <query specification> "}"
<query specification> ::= <procedure body>
<procedure body> ::= <statement block>
<statement block> ::= <statement> [ <next statement>... ]
<statement> ::=
<linear catalog-modifying statement>
| <linear data-modifying statement>
| <composite query statement>
<next statement> ::=
"NEXT" [ <yield clause> ] <statement>
L'appel de procédure en ligne peut être construit avec ou sans importation de variables des parties antérieures de la requête en utilisant la clause de portée de variables.
Lorsqu'il y a des variables importées, la procédure en ligne est effectivement une sous-requête, qui s'exécute plusieurs fois, chaque fois opérant sur un seul enregistrement des variables importées.
Une sous-requête se termine généralement par une clause RETURN
. Chaque ligne produite par une exécution est ajoutée sur le côté droit de la ligne d'entrée correspondante. Lorsqu'une exécution ne produit pas de lignes de sortie, la ligne d'entrée associée est supprimée. Inversement, si une exécution produit plusieurs lignes de sortie, la ligne d'entrée correspondante est dupliquée pour chaque ligne de sortie, permettant aux résultats d'être concaténés en conséquence.
Les sous-requêtes sans RETURN
sont utilisées pour des opérations de modification de données telles que INSERT
, SET
, REMOVE
et DELETE
. Comme ces sous-requêtes ne retournent explicitement aucun résultat, le nombre de lignes présentes après la sous-requête reste le même qu'avant la sous-requête.
Lorsqu'il n'y a pas de variables importées, la procédure en ligne ne s'exécute qu'une seule fois.
Requête Isolée
Dans cette requête, la sous-requête CALL
est utilisée pour trouver le club rejoint par chaque utilisateur :
MATCH (u:User)
CALL (u) {
MATCH (u)-[:Joins]-(c:Club)
RETURN c
}
RETURN u.name, c.code
Résultat :
u.name | c.code |
---|---|
mochaeach | C02 |
Brainy | C01 |
lionbower | C01 |
Les sous-requêtes
CALL
améliorent l'efficacité en gérant mieux les ressources, particulièrement lors du traitement de grands ensembles de données, réduisant ainsi la surcharge mémoire.
Agrégation Isolée
Dans cette requête, la sous-requête CALL
est utilisée pour compter le nombre total d'abonnés pour chaque utilisateur qui rejoint un club :
MATCH (u:User)-[:Joins]-(c:Club)
CALL (u) {
MATCH (u)<-[:Follows]-(follower)
RETURN COUNT(follower) AS followersNo
}
RETURN u.name, c.code, followersNo
Résultat :
u.name | c.code | followersNo |
---|---|---|
Brainy | C01 | 3 |
lionbower | C01 | 0 |
mochaeach | C02 | 0 |
Modification de Données Isolée
Dans cette requête, la sous-requête CALL
est utilisée pour définir les valeurs de la property rates
des edges étiquetées Joins
:
MATCH (u:User)-[j:Joins]-(c:Club)
CALL (j) {
SET j.rates = ROUND(RAND()*10, 2)
}
RETURN u.name, j.rates, c.code
Résultat :
u.name | j.rates | c.code |
---|---|---|
Brainy | 9.67 | C01 |
lionbower | 6.14 | C01 |
mochaeach | 6.45 | C02 |
Importation de Variables Multiples
Dans cette requête, la sous-requête CALL
est utilisée pour détecter la relation de suivi inversée entre deux utilisateurs, où il est connu que l'un suit l'autre :
MATCH (u1:User)<-[:Follows]-(u2:User)
CALL (u1, u2) {
OPTIONAL MATCH p = (u1)-[:Follows]->(u2)
RETURN p
}
RETURN u1.name, u2.name,
CASE p WHEN IS NOT NULL THEN "Y"
ELSE "N" END AS MutualFollowing
Résultat :
u1.name | u2.name | MutualFollowing |
---|---|---|
Brainy | rowlock | N |
Brainy | mochaeach | N |
purplechalk | Brainy | Y |
purplechalk | lionbower | N |
Aucune Variable Importée
Dans cette requête, la sous-requête CALL
est utilisée sans importer de variables et elle est exécutée deux fois :
MATCH (c:Club)
CALL {
MATCH (u:User)
RETURN COUNT(u) AS totalUsers
}
RETURN COUNT(c) AS totalClubs, totalUsers
Résultat :
totalClubs | totalUsers |
---|---|
2 | 5 |
Sous-Requêtes CALL
Multiples
Dans cette requête, la première sous-requête CALL
est utilisée pour définir les valeurs de la property rates
des edges étiquetées Joins
, la deuxième sous-requête CALL
est utilisée pour compter la note moyenne que chaque club reçoit :
MATCH (u:User)-[j1:Joins]-(c:Club)
CALL (j1) {
SET j1.rates = ROUND(RAND()*10, 2)
}
CALL (c) {
MATCH (c)-[j2]-()
RETURN ROUND(AVG(j2.rates), 2) as rating
}
RETURN u.name, j1.rates, c.code, rating
Résultat :
u.name | j1.rates | c.code | rating |
---|---|---|---|
Brainy | 8.58 | C01 | 7.37 |
lionbower | 6.15 | C01 | 7.37 |
mochaeach | 8.5 | C02 | 8.5 |
Ordre d’Exécution des Sous-Requêtes
L'ordre dans lequel la sous-requête est exécutée n'est pas prédéterminé. Si un ordre d'exécution spécifique est souhaité, la clause ORDER BY
doit être utilisée avant la sous-requête CALL
pour imposer cette séquence.
Dans cette requête, la sous-requête CALL
est utilisée pour compter le nombre total d'abonnés pour chaque utilisateur ; l'ordre d'exécution des sous-requêtes est déterminé par l'ordre croissant des noms des utilisateurs :
MATCH (u:User)
ORDER BY u.name
CALL (u) {
MATCH (u)<-[:Follows]-(follower)
RETURN COUNT(follower) AS followersNo
}
RETURN u.name, followersNo
Résultat :
u.name | followersNo |
---|---|
Brainy | 3 |
lionbower | 0 |
mochaeach | 0 |
purplechalk | 2 |
rowlock | 0 |