关于分析器结果的Marklogic查询优化

时间:2014-08-13 13:29:31

标签: performance xpath xquery marklogic

你好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!

雨果

1 个答案:

答案 0 :(得分:6)

我看到两个基本问题:太多次访问数据库,这些旅行带回了太多你并不真正想要的数据。目标是最小化数据库查找次数,并使每次查找尽可能精确。

在这种情况下,执行数据库查找的主要方式是cts:search。有几个:可能太多,有时结果从未使用过。我认为其中一些是剩下的实验。当您描述配置干净代码非常重要时。

接下来,大多数探查器时间都在@name=$segment XPath谓词中。这也是重复的,而且没有充分的理由。摆脱重复,它会更快。

然而,显示@name=$segment的另一个原因是因为MarkLogic索引文档而不是节点。它索引节点的名称和值,但每个索引条目指向一个文档 - 或者更具体地说是一个片段,但是不要去那里。因此,当您有一个文档具有数个或数百个segment/@name值的索引条目时,所有这些索引条目都指向文档根目录。当您仅请求与特定名称匹配的段时,索引查找与整个文档匹配。因此评估必须遍历每个文档树。这在CPU周期中可能很昂贵,而且这是分析器向您展示的内容。

如果没有对文件进行重组,或者在共同发生的情况下做一些聪明的事情,那就无法解决这个问题。但是,我们可以清理您的查询,并使用完整路径将其转换为单个XPath表达式。让我们看一下这个用例是否足够快。

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]应该将表达式的数量减少一半。其他树修剪技术也应该有所帮助:例如,您可以将categoryvariable名称添加到输入中,并将它们表示为XPath谓词。

这可能是您备份并审视大局的好时机。你用这个查询试图完成的是什么?可能有更有效的方法来实现您的目标。

如果这是您最常见的用例,那么理想情况下,您将重新构建文档,以便每个id-segment查找都成为可计算的doc($uri)调用。在这种特殊情况下,我不确定这是一个好主意,但我不完全了解您的申请。

另一种方法是使用内存中的值索引和https://docs.marklogic.com/cts:value-co-occurrences来避免查看XML。然而,这是一个复杂的方法,我不打算在这里探讨它。