2017-01-09 1 views
0

Je migre actuellement une fonction TRAVERSAL d'arangoDB 2 vers arangoDB 3. L'aql a un visiteur de feuille personnalisé et une option filterVertices avec une fonction AQL personnalisée (pour un filtrage plus spécifique).Migration d'un UDF de filtre d'ArangoDB 2.8 vers ArangoDB 3

FOR result IN TRAVERSAL(
    page, 
    menu, 
    "page/99999999999999", 
    "inbound", 
    {filterVertices : "udf::customFilter", visitor : "udf::customVisitor", } 
) RETURN result 

La feuille visiteur UDF a été relativement facile à transférer car il crée simplement un objet personnalisé, mais je rencontre des problèmes avec les filterVertices UDF puisque dans Arango 3 les fonctions graphiques ont été supprimés.

Il y a quelques cas comme celui ci-dessous dans la filterVertices UDF

//check the page status 
    if (mismatch == 1) { 
     //stop traversal and not return mismatched 
     return ['exclude', 'prune']; 
    } else if (mismatch == 2) { 
     //stop but return mismatched 
     return 'prune'; 
    } else { 
     //exclude mismatched but continue 
     return 'exclude'; 
    } 

Ma question est de savoir comment devrait pruneau et ne comprennent ni être traduit en cas de filtre dans le aql ci-dessous exactement?

FOR v, d, p IN 1..10 INBOUND "page/99999999999999" menu 
    LET filtered = CALL('udf::customFilter',v,p) 
    LET result = CALL('udf::customVisitor',v,d,p) 
RETURN {filtered:filtered,result:result} 

Est-ce que la performance sera affectée si j'utilise l'UDF comme il est et passer le résultat dans un param LET et exclure (filtre) les manuellement?

Répondre

2

vous pouvez décider de manière générale "prune", "exclude" lorsque vous écrivez le filtre basé sur l'objet path (dans votre cas p) Ici l'optimiseur reconnaîtra que tout chemin plus long ne peut pas répondre à une certaine condition. exemples ici sont:

FILTER p.edges[1].type == 'FOO' 
FILTER p.edges[*].label ALL == 'BAR' 
FILTER p.vertices[*].age ALL >= 18 

d'abord élague chaque fois que le second bord n'a pas de type FOO. La seconde efface chaque fois qu'elle trouve label != BAR etc. Seules les vérifications de profondeur spécifiques ou les vérifications globales ALL, NONE, ANY peuvent être reconnues par l'optimiseur.

Vous pouvez décider "exclude" si vous définissez le filtre sur la sortie vertex ou edge, dans votre cas v et d:

FILTER d.type != "BAR" 
FILTER v.name == "BAZ" 

Le premier exclura tous les bords qui ont le type « BAR », la deuxième inclura seulement les sommets ayant le nom "BAZ". Dans les deux cas, la traversée continuera.

À l'heure actuelle, il n'y a pas d'option pour dire PRUNE, INCLUDE.

L'utilisation d'une fonction définie par l'utilisateur pour mettre en œuvre le filtrage uniquement est extrêmement mauvaise pour les performances. C'est parce que l'UDF est une "boîte noire" pour AQL et surtout ne peut pas être optimisée dans le Traversal pour l'élagage. Néanmoins, les performances de la traversée AQL sont encore meilleures dans nos tests internes, c'est pourquoi nous avons décidé d'aller dans ce sens.

Malheureusement, les fonctions UDF sont légèrement plus flexibles qu'AQL seulement, il peut donc y avoir certaines fonctions qui ne peuvent pas être traduites en instructions FILTER. Cependant, il existe toujours une option pour exécuter ces Traversals de la même manière qu'avant 3.0 en définissant simplement Traversal entier comme une fonction définie par l'utilisateur. Cela devrait avoir des performances identiques à celles d'avant (l'algorithme de haut niveau est identique, mais nous avons changé beaucoup d'autres parties internes dans 3.0 qui ont ici des effets de performance).

Ceci est expliqué plus en détail ici: https://docs.arangodb.com/3.1/Manual/Graphs/Traversals/UsingTraversalObjects.html

Et votre nouvelle UDF devrait à peu près ressembler à ceci et prendre la startVertex en entrée:

var db = require("internal").db; 
var traversal = require("@arangodb/graph/traversal"); 
var config = { 
    datasource: traversal.collectionDatasource("menu"), 
    filter: db._aqlfunctions.document("UDF::CUSTOMFILTER").code, 
    visitor: db._aqlfunctions.document("UDF::CUSTOMVISITOR").code, 
    maxDepth: 1 // has to be defined 
}; 
var result = { 
    visited: { 
    vertices: [ ], 
    paths: [ ] 
    } 
}; 
var traverser = new traversal.Traverser(config); 
traverser.traverse(result, startVertex); 
[...] // Do stuff with result here 

Si vous avez besoin d'aide pour la traduction de l'UDF Pour FILTER ou pour obtenir le plein parcours UDF en cours d'exécution s'il vous plaît contactez-nous directement via le https://groups.google.com/forum/#!forum/arangodb. Nous pouvons exiger des courriels pour trier tous les détails dont vous avez besoin.

+0

Tellement intéressant! Je m'attendais à une réponse dans ce sens. Je devais juste être sûr de ne rien manquer de la documentation. Malheureusement mes fonctions dépendent des résultats des entrées et des collectes de l'utilisateur, donc je ne suis pas sûr que ce soit faisable de tout convertir en instructions FILTER, mais je comprends ce que vous dites et je le garderai en tête pour le prochain refactoring . Je sais que c'est un longhot mais si vous parvenez à inclure des instructions "if" dans l'AQL, cela ajouterait beaucoup de flexibilité! J'utilise l'option isDeterministic pour le moment, juste pour être prêt pour les futures mises à jour. – GeorgeKaf