你好MarkLoggers,
我再次向你提问!我有一系列包含邮政编码信息的文件。 400.000个文档。文档按文档订购一个邮政编码,每个文档包含400个功能,按类别和变量排序如下:
<postcode id="9728" xmlns="http://www.nvsp.nl/p4">
<meta-data>
<!--
Generated by DIKW for NetwerkVSP ST!P
-->
<version>0.3</version>
<dateCreated>2014-06-28+02:00</dateCreated>
</meta-data>
<category name="Oplages">
<variable name="Oplage" updated="2014-08-12+02:00">
<segment name="Bruto">1234</segment>
<segment name="Stickers">234</segment>
<segment name="Netto">1000</segment>
<segment name="Aktief">J</segment>
</variable>
</category>
<category name="Automotive">
<variable name="Leaseauto">
<segment name="Leaseauto">2.68822210725987</segment>
</variable>
<variable name="Autotype">
<segment name="De Oudere Stadsrijder">4.61734781858941</segment>
<segment name="De Dure Tweedehandsrijder">6.02534919813761</segment>
<segment name="De Autoloze">41.187790998448</segment>
<segment name="De Leasende Veelrijder">0.608035868253147</segment>
<segment name="De Modale Middenklasser">13.1996896016555</segment>
<segment name="De Vermogende Autoliefhebber">4.45283669598206</segment>
<segment name="De Vermogende Kilometervreter">2.07690981203656</segment>
<segment name="De Doelmatige Budgetrijder">17.2048629073978</segment>
<segment name="De Doorsnee Nieuw Kopende Automob">10.1595102603897</segment>
</variable>
...
400 more cat/var/segment element
...
</postcode>
我需要根据postcode元素中的id属性找到docs的子集,并且只返回特定的元素。
返回的元素在cat Oplages var Oplage中,我需要段Bruto和Netto
现在我们有一个休息api扩展,可以做到但不够快。
示例查询:
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare namespace p4ns = "http://www.nvsp.nl/p4";
declare namespace wijkns = "http://www.nvsp.nl/wijk";
let $segment := "Bruto"
let $zoeker0 := cts:search(fn:doc(), cts:element-attribute-range-query(xs:QName("p4ns:postcode"), xs:QName("id"), "=", ("2311","2312","2313")))
let $zoeker1 := cts:search(/p4ns:postcode, cts:element-attribute-range-query(xs:QName("p4ns:postcode"), xs:QName("id"), "=", ("2311","2312","2313")))
let $zoeker2 := cts:search(/p4ns:postcode, cts:element-attribute-value-query(xs:QName("p4ns:postcode"), xs:QName("id"), ("2311","2312","2313")))
let $inhoud1 := $zoeker0//p4ns:segment[@name=$segment]
let $inhoud2 := $zoeker1//p4ns:segment[@name=$segment]/text()
let $r1 := cts:search(/p4ns:postcode, cts:element-attribute-range-query(xs:QName("p4ns:segment"), xs:QName("name"), "=", $segment))
return $inhoud2
现在,如果我描述这个测试查询,那么缓慢的部分就是查找&#34; Bruto&#34; cts:search返回的de docs中的段。我知道我应该避免通过xpath在docs中查找元素,但我不知道如何将这两个位组合起来只打出索引......
Profiler结果:
.main:13:44 1446 27 7127 30 7938 @name = "Bruto"
.main:12:44 1446 27 6956 30 7793 @name = "Bruto"
.main:17:11 1 9.3 2431 9.4 2458 cts:search(fn:collection()/p4ns:postcode, cts:element-attribute-range-query(xs:QName("p4ns:segment"), fn:QName("", "name"), "=", $segment))
.main:10:16 1 7.2 1874 7.2 1885 cts:search(fn:collection()/p4ns:postcode, cts:element-attribute-value-query(xs:QName("p4ns:postcode"), fn:QName("", "id"), ("2311", "2312", "2313")))
查询结果:
1234
4567
3456
现在我的问题:
1)&#34; @name =&#34; Bruto&#34;&#34;意思是什么,它为什么慢?
2)理想情况下,我会将文档搜索与通过xpath查找segment元素组合成一个组合,但如果我将$ zoeker放入cts:搜索它是不可搜索的...获取结果的最佳方法是什么?一气呵成?
提前thx!雨果
答案 0 :(得分:6)
我看到两个基本问题:太多次访问数据库,这些旅行带回了太多你并不真正想要的数据。目标是最小化数据库查找次数,并使每次查找尽可能精确。
在这种情况下,执行数据库查找的主要方式是cts:search
。有几个:可能太多,有时结果从未使用过。我认为其中一些是剩下的实验。当您描述配置干净代码非常重要时。
接下来,大多数探查器时间都在@name=$segment
XPath谓词中。这也是重复的,而且没有充分的理由。摆脱重复,它会更快。
然而,显示@name=$segment
的另一个原因是因为MarkLogic索引文档而不是节点。它索引节点的名称和值,但每个索引条目指向一个文档 - 或者更具体地说是一个片段,但是不要去那里。因此,当您有一个文档具有数个或数百个segment/@name
值的索引条目时,所有这些索引条目都指向文档根目录。当您仅请求与特定名称匹配的段时,索引查找与整个文档匹配。因此评估必须遍历每个文档树。这在CPU周期中可能很昂贵,而且这是分析器向您展示的内容。
declare namespace p4ns="http://www.nvsp.nl/p4" ;
(: These might be external parameters. :)
let $segment := "Bruto"
let $ids := ("2311","2312","2313")
return collection()/p4ns:postcode[
@id = $ids]/p4ns:category/p4ns:variable/p4ns:segment[
@name = $segment]/string()
如果我插入示例XML并将其ID更改为2313
,则返回单个值1234
。分析它在不到1毫秒的时间内显示33个表达式,其中66%的时间通过XPath查找数据库。但是,它仍然需要查看所有segment/@name
值:在这种情况下,其中14个值占10%的时间。
请注意,我没有使用cts:search
,也没有使用任何范围索引。 MarkLogic自动为XPath值 - 相等性查找索引节点值。您只需要特殊操作的范围索引:例如构面,排序和不等式查找。
你可以用这个做得更好:
(collection()/p4ns:postcode[
@id = $ids]/p4ns:category/p4ns:variable/p4ns:segment[
@name = $segment])[1]/string()
现在我们告诉评估人员,预计只有一场比赛。因此,它会在找到Bruto
之后停止,并且在文档的早期就会停止。在这种情况下,它是第一个,但平均(...)[1]
应该将表达式的数量减少一半。其他树修剪技术也应该有所帮助:例如,您可以将category
和variable
名称添加到输入中,并将它们表示为XPath谓词。
这可能是您备份并审视大局的好时机。你用这个查询试图完成的是什么?可能有更有效的方法来实现您的目标。
如果这是您最常见的用例,那么理想情况下,您将重新构建文档,以便每个id-segment查找都成为可计算的doc($uri)
调用。在这种特殊情况下,我不确定这是一个好主意,但我不完全了解您的申请。
另一种方法是使用内存中的值索引和https://docs.marklogic.com/cts:value-co-occurrences来避免查看XML。然而,这是一个复杂的方法,我不打算在这里探讨它。