2016-02-26 45 views
3

這種情況是這樣的:我有一個包含項目的ArangoDB集合和另一個包含標籤的集合。我正在使用圖形,並且我有一個名爲「Contains」的邊緣集合,用於連接項目和標籤。一個項目有多個標籤。ArangoDB中(n)陣列的交互AQL

現在我正在嘗試搜索包含多個標籤的項目。例如。包含標籤「攝影」,「肖像」和「面孔」的項目。

我的一般方法是從每個標籤頂點開始圖遍歷並找到與該標籤相關的項。這部分工作正常。我得到一個項目列表。

但我的任務的最後一部分是爲了找到包含所有指定標籤的項目的所有列表的交集。我無法解決如何做到這一點。

我想做的事是這樣的:

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) 

但是,這是行不通的:交集功能沒有一個單獨的列表上工作,但多個項目,像這樣的:交會( listA,listB,listC ...)。

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

+1

,並希望得到的路口,你可能希望使用APPLY()來傳播數組,並將每個列表作爲單獨的參數傳遞:'APPLY(「INTERSECTION」,[listA,listB,listC])''。它與'INTERSECTION(listA,listB,listC)'相同,但輸入數組的長度可變。 – CoDEmanX

+0

我認爲你的評論是我正在尋找的答案。儘管其他評論非常有用,但您的回答直接回答了我的問題。但我不能將它標記爲正確的答案,當它是一個評論... –

+0

我張貼了一個擴展的答案:http://stackoverflow.com/a/38484463/2044940如果它解決您的問題,請接受並投票表決,謝謝! – CoDEmanX

回答

4

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) 

    }) 
3

我會考慮將您的標籤作爲屬性存儲在您的項目上。 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

嗯。我在我的系統中廣泛使用標籤,使用它們標記很多不同的項目類型,這些項目類型存在於不同的集合中。因此,由於標籤在我的系統中似乎是一種「主要」數據類型,我有一種直覺認爲將它們降爲屬性可能是一個糟糕的主意:-(然而,這可能只是舊的RDBMS-思考......?關係的概念在我看來是圖DB原理的核心,給定一個標籤,我可以快速找到與該標籤相關的項目。對於這個用例,這個工作正常,我只需要能夠在兩個或多個結果集上交叉... –

+0

如果您考慮遍歷所做的重複性工作(收集所有邊,過濾它們然後遍歷它們),爲了遍歷/保持快速,您希望創建最小值「Hubs」(高度頂點)基本上就是圖形世界的減速帶, – mikewilliamson

+0

標籤本質上是創造集線器,但是和其他所有的東西一樣,有時候你需要它,這都是權衡的嗎?幫助這裏:https://mikewilliamson.wordpress.com/2015/07/16/d ata-modeling-with-arangodb/ – mikewilliamson

0

您可以確保在使用DISTINCT keyword的AQL查詢結果中不會獲得兩次文檔。

讓我們在圖形查詢using the knows graph example demonstate這樣的:

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" 
] 

我們看到你的情況,鮑勃返回兩次。現在,讓我們添加不同的關鍵字:

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" 
]