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

时间:2016-12-28 23:25:29

标签: xquery marklogic

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

<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中工作的最快方法。解决方案似乎确实是一种相对麻烦的方法。有没有更好的方法最初只返回“重要”节点,但仍然可以访问主文档元素?

2 个答案:

答案 0 :(得分:3)

就个人而言,我发现条件逻辑比循环更麻烦,但我认为你可以删除其中一个用于更简单的查询。您可以简单地将它们分配给变量,而不是循环遍历第一个文档序列,这将允许您引用它们。然后在循环中,使用谓词将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)

答案 1 :(得分:3)

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

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

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

如果通常会一起检索和更新问题项目的具体列表,那么就会反对将每个问题拆分为单独的文档。

希望有帮助,