【问题标题】:Migrating a filterVertice UDF from ArangoDB 2.8 to ArangoDB 3将 filterVertice UDF 从 ArangoDB 2.8 迁移到 ArangoDB 3
【发布时间】:2017-01-09 16:50:23
【问题描述】:

我目前正在将 TRAVERSAL 函数从 arangoDB 2 迁移到 arangoDB 3。aql 有一个自定义叶子访问者和一个带有自定义 AQL 函数的 filterVertices 选项(用于更具体的过滤)。

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

叶子访问者 UDF 相对容易传输,因为它只是创建一个自定义对象,但我在使用 filterVertices UDF 时遇到了问题,因为在 arango 3 中,图形函数已被删除。

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';
    }

我的问题是应该如何在下面的 aql 中的 FILTER 案例中准确翻译 prune 和 exclude ?

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}

如果我按原样使用 UDF 并将结果传递给 LET 参数并手动排除(过滤)它们,性能会受到影响吗?

【问题讨论】:

    标签: arangodb nosql


    【解决方案1】:

    一般来说,当您根据path 对象编写过滤器时,您可以决定"prune", "exclude"(在您的情况下为p) 在这里,优化器将认识到任何更长的路径都不能满足某个条件。 这里的例子是:

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

    只要第二条边的类型不为FOO,First 就会修剪。 第二个将在找到label != BAR 时进行修剪 等等。 优化器只能识别特定的深度检查或全局检查ALLNONEANY

    如果您在vertexedge 输出上定义过滤器,您可以决定"exclude",在您的情况下为vd

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

    第一个将排除所有类型为“BAR”的边,第二个将仅包含名称为“BAZ”的顶点。在这两种情况下,遍历都会继续。

    目前没有选择说PRUNE, INCLUDE

    仅使用 UDF 实现过滤对性能非常不利。这是因为 UDF 是 AQL 的“黑匣子”,尤其不能优化到 Traversal 以进行修剪。 在我们的内部测试中,AQL 遍历的性能仍然要好几个数量级,这就是我们决定采用这种方式的原因。

    不幸的是,UDF 函数比仅 AQL 更灵活,因此可能有些函数无法转换为仅 FILTER 语句。 但是,仍然可以选择以与 3.0 之前相同的方式执行这些 Traversal,只需将整个 Traversal 定义为用户定义的函数。这应该具有与以前相同的性能(高级算法相同,但我们在 3.0 中更改了许多其他内部部分,这些部分在此处具有性能副作用)。

    这里有更详细的解释: https://docs.arangodb.com/3.1/Manual/Graphs/Traversals/UsingTraversalObjects.html

    您的新 UDF 应该大致如下所示,并将 startVertex 作为输入:

    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
    

    如果您在从 UDF 转换为 FILTER 方面需要一些帮助,或者要启动和运行完整的遍历 UDF,请直接通过 https://groups.google.com/forum/#!forum/arangodb 联系我们。我们可能需要一些邮件来整理您需要的所有详细信息。

    【讨论】:

    • 太有趣了!我期待着这些方面的答案。我只需要确保我没有遗漏文档中的任何内容。不幸的是,我的函数依赖于用户输入和收集结果,所以我不太确定在 FILTER 语句中将其全部转换是否可行,但我明白你所说的,我会记住它,以进行下一轮重构。我知道这是一个远景,但如果您设法在 AQL 中包含“if”语句,它将增加大量的灵活性!我现在使用 isDeterministic 选项只是为了为将来的更新做好准备。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多