Marklogic xquery 并有效地循环遍历子元素



想象一下,如果我有一个XML文档以以下格式存储在Marklogic中:

<document>
<id>DocumentID</id>
<questions>
<question_item>
<question>question1</question>
<answer>answer1</answer>
</question_item>
<question_item>
<important>high</important>
<question>question2</question>
<answer>answer2</answer2>
<question_item>
</document>

基本上,每个文档都有许多问题,只有其中一些具有元素。我想以平面格式返回所有"重要"问题,其中包含从中提取的文档(例如 id)中提取的元数据。

以下 xquery 似乎有效,并且速度相当快:

for $x in cts:search(/document,
cts:element-query(xs:QName("important"),cts:and-query((
))
), "unfiltered" , 0.0)
return for $y in $x/questions/question_item
return 
if ($y/important) then 
fn:concat($x/id,'|',
$y/question,'|',
$y/answer,
$y/important
)
else ()

这似乎有效并且相当快。但是,我通常发现 for 循环并不是在 xquery 中工作的最快方式。解决方案似乎确实是一种相对繁琐的方法。有没有更好的方法可以最初只返回"重要"节点,但仍然可以访问主文档元素?

就个人而言,我发现条件逻辑比 for 循环更麻烦,但我认为您可以删除每个循环中的一个以进行更简单的查询。与其循环访问第一个文档序列,不如简单地将它们分配给一个变量,这将允许您引用它们。然后在循环中,使用谓词将question_item约束为具有important元素的谓词,从而消除了对条件的需要:

let $documents := cts:search(/document,
cts:element-query(xs:QName("important"), cts:and-query(())
), "unfiltered" , 0.0)
for $y in $documents/questions/question_item[important]
return fn:concat($x/id,'|',
$y/question,'|',
$y/answer,
$y/important)

与代码示例中一样,最佳方法是首先根据索引匹配文档,然后从匹配的文档中提取值。 具有非冗余 XPath 的 FLWOR 表达式是从文档中提取值的有效方法。

一种可能的改进是在对文件进行建模时采用更细粒度的方法:即将每个问题项放在单独的文档中。这样,搜索将仅检索重要的问题项。

如果文件很大,这种变化将变得很重要。 为了获得最佳性能,您可以在问题、答案和重要元素上放置范围索引,并直接从索引中为每个问题项获取一个元组。

但是,如果通常一起检索和更新具体的问题项目清单,则反对将每个问题拆分为单独的文件。

希望有帮助,

最新更新