Marklogic 如何重组文档以优化

Marklogic 如何重组文档以优化,marklogic,Marklogic,在我的示例中,我遇到了一个问题,即使用相同的属性名(123)添加到多个元素 我们清理了查询并评估了建议的解决方案,所有查询都保持相同的数量级(对于全尺寸查询为15秒),对于应用程序来说太慢了 为了完整起见,我在这里重复这些问题: 原件: xquery version "1.0-ml"; declare namespace html = "http://www.w3.org/1999/xhtml"; declare namespace p4ns = "http://www.nvsp.n

在我的示例中,我遇到了一个问题,即使用相同的属性名(123)添加到多个元素

我们清理了查询并评估了建议的解决方案,所有查询都保持相同的数量级(对于全尺寸查询为15秒),对于应用程序来说太慢了

为了完整起见,我在这里重复这些问题:

原件:

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","Netto")
let $codes := ("9766","9765","2162","2161","2159") (: full query is 4000 codes:)


let $zoeker0 := cts:search(fn:doc(), cts:element-attribute-range-query(xs:QName("p4ns:postcode"), xs:QName("id"), "=", $codes)) 
(:
let $zoeker1 := cts:search(/p4ns:postcode, cts:element-attribute-range-query(xs:QName("p4ns:postcode"), xs:QName("id"), "=", $codes)) 
let $zoeker2 := cts:search(/p4ns:postcode, cts:element-attribute-value-query(xs:QName("p4ns:postcode"), xs:QName("id"), $codes)) 
:)

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 $inhoud1
接受的答复:

declare namespace p4ns="http://www.nvsp.nl/p4" ;

(: These might be external parameters. :)
let $segment := ("Bruto","Netto")
let $ids := ("9766","9765")
return collection()/p4ns:postcode/p4ns:category/p4ns:variable/p4ns:segment[
  @name = $segment]/string()
这两个查询在大型文档中查找段名称属性的成本仍然很高

公认的答案是没有真正好的解决方案,只有重新组织文档

下一个挑战是如何解决

我的思路是:

  • 重建文档
  • 将文档拆分为两个(或多个)部分
  • 使用片段和片段根
  • 在同一文档中使用单独的命名空间来拆分内容
最初,我们设计文档的方式是将所有内容组织在类别[name=“Oplages”]/variable[name=“Oplage”]/segment[name=“Bruto”]层次结构中。标识符位于“名称”属性中。这就是为什么我们有这么多带有name属性的段元素

因此,一种选择是像这样重建文档

Oplage/Oplage/布鲁托

通过这种方式,我们需要为所有单独的细分市场(400个细分市场)建立一个索引,这就是为什么我们没有这样做的原因

另一个选项是使用片段,在片段元素处设置片段根有意义吗?不确定,因为问题仍然存在(在集合中搜索一个具有特定名称的段以查找400


因此,我的问题是:如何重新构造原始文档,使我的查询在几秒钟内响应。

看起来Mike在上一个问题中没有提到路径索引选项。您可以在
/postcode/category[name=“Oplage”]/variable[name=“Oplage”]/segment[name=“Bruto”]上创建索引
具体地说,就是将其用作路径模式。这将有助于尽可能准确地定位相关片段

但是,我不确定您期望的最终结果是什么。您想要一个Bruto段值列表,还是要查找包含匹配段的邮政编码?这在很大程度上取决于您想要的结果。从头到尾考虑这个问题可能很有用


HTH!

我不喜欢使用子片段。编写一个意外地将所有片段加载到内存中的查询太容易了。这个用例可能是一个例外,片段可能是最好的方法,但我会把它作为最后的手段。我的经验是,它一开始似乎工作得很好,但随后会导致越来越多的问题问题就在你继续

在上一个问题中,我提到了其他可能性。我将在这里回顾它们。主要技巧是记住MarkLogic是一个面向文档的数据库。因此文档URI是主键,文档的行为更像行而不是表。构造文档和URI,以便最常见的查询能够利用这些字符特性

在MarkLogic中,文档URI是主键,按主键进行查找只是
doc($URI)
。这是查询数据库的一种非常有效的方法。要知道这一点,您应该对内容进行结构化,以便最常见的查找就是
doc($URI)
。您提到了一种类似于
Oplages/Oplage/Bruto
的结构。我不确定这到底是什么意思,但如果您将其排列为文档URI而不是XML结构,会怎么样?类似于
/Oplages/{code}/{segment}
?每个文档都非常小,只有一个片段的数据

如果您有不经常使用的元数据,请将其放在一个特殊的文档中,如
/oplages/{code}/metadata.xml
。或者如果每次都使用它,请将其复制到每个片段文档中。您比我更了解您的内容,但单个文档的xml可能如下所示:

<segment xmlns="http://www.nvsp.nl/p4"
 postcode="9728"
 category="Oplages"
 variable="Oplage"
 name="Bruto"
 updated="2014-08-12+02:00">
  1234
</segment>

1234
使用存储在
/oplages/9728/Bruto
的XML,只需调用
doc('/oplages/9728/Bruto')
即可获得值。您还可以使用一系列URI调用
fn:doc
。您可能会看到,在文档大小和数据结构方面存在权衡


我提到的另一种可能性是使用范围索引和或来查询数据。这种方法直接从值索引中提取数据,而不是检查XML树。但是,对于定义良好的小文档,这种方法更容易。对于像原始示例一样的XML,每个文档包含许多值,您需要定位-感知范围索引和仔细编写的位置范围查询。

我测试了Mike和Geert的建议,您可以通过以下方式实现您想要的(我相信这是为了获得邮政编码的bruto和Netto值): 创建两个路径范围索引,一个用于Bruto,一个用于Netto: /p4:邮政编码/p4:类别/p4:变量/p4:段[@name='Bruto'] /p4:邮政编码/p4:类别/p4:变量/p4:段[@name='Netto'] 不要忘记为p4注册名称空间

如果需要将这些段变为变量,则此操作将失败。 然后使用下面的代码,您可以从索引中获得bruto和netto的值

declare namespace p4 = "http://www.nvsp.nl/p4";
let $segment := ("Bruto","Netto")
let $ids := ("9729","9728")
for $id in $ids
return ($id,
  cts:value-co-occurrences(
    cts:path-reference("/p4:postcode/p4:category/p4:variable/p4:segment[@name='Bruto']"),
    cts:path-reference("/p4:postcode/p4:category/p4:variable/p4:segment[@name='Netto']"),(),
    cts:element-attribute-value-query(xs:QName("p4:postcode"),xs:QName("id"),$id)))
这将返回一系列具有bruto和netto值的ID,如:

9729 (: id :)
<cts:co-occurrence xmlns:cts="http://marklogic.com/cts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <cts:value xsi:type="xs:int">4321</cts:value> (: bruto value :)
  <cts:value xsi:type="xs:int">2000</cts:value> (: netto value :)
</cts:co-occurrence>
这将返回邮政编码加上给定的段值:

Bruto (: segment name :)
<cts:co-occurrence xmlns:cts="http://marklogic.com/cts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <cts:value xsi:type="xs:int">9728</cts:value>  (: postcode :)
  <cts:value xsi:type="xs:int">1234</cts:value>  (: segment value :)
</cts:co-occurrence>
Bruto(:段名称:)
9728(:邮政编码:)
1234(:段值:)

是的,我提到了范围索引,但没有建议将段名称硬编码到路径范围索引中。将其与
cts:values
一起使用可能会很好,只要有少量段名称需要优化:例如,可能只是
Bruto
Netto
。但也可能有一个开放的段名称,每个段都需要自己的路径范围索引。
Bruto (: segment name :)
<cts:co-occurrence xmlns:cts="http://marklogic.com/cts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <cts:value xsi:type="xs:int">9728</cts:value>  (: postcode :)
  <cts:value xsi:type="xs:int">1234</cts:value>  (: segment value :)
</cts:co-occurrence>