ArangoDB AQL 中 (n) 个数组的交集
INTERSECTION of (n) arrays in ArangoDB AQL
场景是这样的:我有一个包含项目的 ArangoDB 集合,另一个包含标签的集合。我正在使用一个图表,并且我有一个名为 "Contains" 的边集合,用于连接项目和标签。一个项目有多个标签。
现在我正在尝试搜索包含多个标签的项目。例如。包含标签 "photography"、"portrait" 和 "faces".
的项目
我的一般做法是从每个标签顶点开始图遍历,并找到与该标签相关的项目。那部分工作正常。我得到了一个项目列表。
但我任务的最后一部分是对所有列表进行交集,以找到包含所有指定标签的项目。我不知道该怎么做。
我想做的是这样的:
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 块中找到的列表的交集?
我会考虑将您的标签作为属性存储在您的商品上。
ArangoDB 2.8 包括 array indexes which are exactly aimed at your scenario. From their 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 的需求,从而简化您的应用程序。
您可以使用 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"
]
我们看到你的情况,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"
]
ArangoDB 3.0 引入了特殊的 array comparison operators(ANY
、ALL
、NONE
)。 ALL IN
可用于测试左侧数组中的每个元素是否也在右侧数组中:
[ "red", "green", "blue" ] ALL IN [ "purple", "red", "blue", "green" ]
// true
请注意,这些运算符还不能使用索引。给定一个将标签直接嵌入到文档中的数据模型,一种解决方法是使用索引来查找包含其中一个标签的所有文档(例如,取第一个元素,["red","green","blue"][0]
)以减少结果集而不完整集合扫描,然后 post-如果其他标签也在列表中,则使用 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)
})
场景是这样的:我有一个包含项目的 ArangoDB 集合,另一个包含标签的集合。我正在使用一个图表,并且我有一个名为 "Contains" 的边集合,用于连接项目和标签。一个项目有多个标签。
现在我正在尝试搜索包含多个标签的项目。例如。包含标签 "photography"、"portrait" 和 "faces".
的项目我的一般做法是从每个标签顶点开始图遍历,并找到与该标签相关的项目。那部分工作正常。我得到了一个项目列表。
但我任务的最后一部分是对所有列表进行交集,以找到包含所有指定标签的项目。我不知道该怎么做。
我想做的是这样的:
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 块中找到的列表的交集?
我会考虑将您的标签作为属性存储在您的商品上。 ArangoDB 2.8 包括 array indexes which are exactly aimed at your scenario. From their 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 的需求,从而简化您的应用程序。
您可以使用 DISTINCT
keyword.
让我们在图形查询中演示这一点 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"
]
我们看到你的情况,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"
]
ArangoDB 3.0 引入了特殊的 array comparison operators(ANY
、ALL
、NONE
)。 ALL IN
可用于测试左侧数组中的每个元素是否也在右侧数组中:
[ "red", "green", "blue" ] ALL IN [ "purple", "red", "blue", "green" ]
// true
请注意,这些运算符还不能使用索引。给定一个将标签直接嵌入到文档中的数据模型,一种解决方法是使用索引来查找包含其中一个标签的所有文档(例如,取第一个元素,["red","green","blue"][0]
)以减少结果集而不完整集合扫描,然后 post-如果其他标签也在列表中,则使用 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)
})