首页 文章

ArangoDB AQL中(n)数组的交集

提问于
浏览
3

场景是这样的:我有一个包含项目的ArangoDB集合,以及另一个包含标签的集合 . 我正在使用图表,我有一个名为“Contains”的边集合连接项目和标签 . 一个项目有多个标签 .

现在我正在尝试搜索包含多个标签的项目 . 例如 . 包含标签“photography”,“portrait”和“faces”的项目 .

我的一般方法是从每个标记顶点开始图遍历,并找到与该标记相关的项 . 那部分工作正常 . 我得到了一个项目清单 .

但我的任务的最后一部分是 Build 所有列表的交集,以便找到包含所有指定标记的项目 . 我无法弄清楚如何做到这一点 .

我想做的是这样的:

let tagnames = SPLIT(@tagnames,',')
let tagcollections = (
    FOR tagname IN tagnames
    LET atag = (FOR t IN tags FILTER LOWER(t.text)==LOWER(tagname) RETURN t)
    let collections = (FOR v IN 1..1 INBOUND atag[0] Contains RETURN v)

    RETURN { tag: atag, collections: collections }
)

RETURN INTERSECTION(tagcollections)

但是,它不起作用:INTERSECTION函数不能在单个列表上工作,而是在多个项目上工作,如下所示:INTERSECTION(listA,listB,listC ...) .

如何在FOR ... RETURN块中找到列表的交集?

3 回答

  • 3

    ArangoDB 3.0引入了特殊的array comparison operatorsANYALLNONE ) . ALL IN 可用于测试左侧数组中的每个元素是否也在右侧数组中:

    [ "red", "green", "blue" ] ALL IN [ "purple", "red", "blue", "green" ]
    // true
    

    请注意,这些运算符尚不能使用索引 . 给定一个将标记直接嵌入到文档中的数据模型,解决方法是使用索引查找包含其中一个标记的所有文档(例如,获取第一个元素, ["red","green","blue"][0] )以减少结果集而不进行完整的集合扫描,如果其他标签也在列表中,则使用 ALL IN 过滤后:

    LET tagsToSearchFor = [ "red", "green", "blue" ]
    FOR doc IN coll
      FILTER tagsToSearchFor[0] IN doc.tags[*] // array index
      FILTER tagsToSeachFor ALL IN doc.tags
      RETURN doc
    

    ALL IN 也可以用于您的数据模型,并为标签添加单独的集合,但您将无法使用上述索引 . 例如:

    FOR doc IN documents
        LET tags = (
            FOR v IN INBOUND doc contains
                RETURN v._key
        )
        FILTER ["red", "green", "blue"] ALL IN tags
        RETURN MERGE(doc, {tags})
    

    或者,如果要使用标记开始遍历并使用基于交集的方法:

    LET startTags = ["red", "green", "blue"] // must exist
    LET ids = (
        FOR startTag IN DOCUMENT("tags", startTags)
            RETURN (
                FOR v IN OUTBOUND startTag contains
                    RETURN v._id
            )
    )
    LET docs = APPLY("INTERSECTION", ids)
    
    FOR doc IN DOCUMENT(docs)
        RETURN MERGE(doc, {
            tags: (FOR tag IN INBOUND doc contains RETURN tag._key)
    
        })
    
  • 5

    我会考虑将您的代码作为属性存储在您的商品上 . ArangoDB 2.8包含array indexes,它们完全针对您的场景 . 从他们的blog post

    { 
      text: "Here's what I want to retrieve...",
      tags: [ "graphdb", "ArangoDB", "multi-model" ]   
    }
    
    FOR doc IN documents 
      FILTER "graphdb" IN doc.tags[*] 
        RETURN doc
    

    这应该更高效,并消除了对AQL的需求,简化了您的应用程序 .

  • 0

    您可以确保在使用DISTINCT keyword的AQL查询结果中不会获取两次文档 .

    让我们在图形查询中证明这一点using the knows graph example

    var examples = require("org/arangodb/graph-examples/example-graph.js");
    
    var g = examples.loadGraph("knows_graph");
    db._query("FOR oneGuy IN persons " +
      "FOR v IN 1..1 OUTBOUND oneGuy GRAPH 'knows_graph' RETURN v.name").toArray()
    [ 
      "Charlie", 
      "Dave", 
      "Alice", 
      "Bob", 
      "Bob" 
    ]
    

    我们看到你的情况,鲍勃两次回来 . 现在让我们添加distinct关键字:

    db._query("FOR oneGuy IN persons " +
      "FOR v IN 1..1 OUTBOUND oneGuy GRAPH 'knows_graph' RETURN DISTINCT v.name"
      ).toArray()
    [ 
      "Bob", 
      "Alice", 
      "Dave", 
      "Charlie" 
    ]
    

相关问题