想象一下,如果我有一个以下列格式存储在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中工作的最快方法。解决方案似乎确实是一种相对麻烦的方法。有没有更好的方法最初只返回“重要”节点,但仍然可以访问主文档元素?
答案 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表达式是从文档中提取值的有效方法。
一种可能的改进是在文档建模中采用更细粒度的方法:即将每个问题项放在单独的文档中。这样,搜索将只检索重要的问题项。
如果文件很大,那么这种变化就会变得很重要。为了获得最佳性能,您可以在问题,答案和重要元素上放置范围索引,并直接从索引中获取每个问题项的一个元组。
如果通常会一起检索和更新问题项目的具体列表,那么就会反对将每个问题拆分为单独的文档。
希望有帮助,