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

Hug*_*ans 3 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>
Run Code Online (Sandbox Code Playgroud)

我需要根据postcode元素中的id属性找到docs的子集,并仅返回特定元素.

要返回的元素是cat Oplages var Oplage,我需要段Bruto和Netto

现在我们有一个rest 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
Run Code Online (Sandbox Code Playgroud)

现在,如果我描述这个测试查询,那么缓慢的部分就是在cts:search返回的de docs中查找"Bruto"段.我知道我应该避免通过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")))
Run Code Online (Sandbox Code Playgroud)

查询结果:

1234
4567
3456
Run Code Online (Sandbox Code Playgroud)

现在我的问题:

1)"@name ="Bruto""是什么意思,为什么它变慢?

2)理想情况下,我会将docs的搜索与通过xpath查找segment元素组合成一个组合但如果我将$ zoeker放入cts:搜索它是不可搜索的...什么是将我的结果恢复为一个的最佳方法走?

提前thx!

雨果

mbl*_*ele 6

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

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

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

然而,出现的另一个原因@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()
Run Code Online (Sandbox Code Playgroud)

如果我插入您的示例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()
Run Code Online (Sandbox Code Playgroud)

现在我们告诉评估者,预计只有一场比赛.因此它会在找到之后停止Bruto,而且在文档的早期.在这种情况下,它是第一个,但平均(...)[1]应该将表达式的数量减少一半.其他树修剪技术也应该有所帮助:例如,您可以将输入categoryvariable名称添加到输入中,并将它们表示为XPath谓词.

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

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

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