在我的previous question中,我遇到了许多具有相同属性名称的元素的问题(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属性的段元素。
因此,一个选项是重建文档,如
Oplages / Oplage / Bruto
通过这种方式,我们需要为所有单个段(其中400个)构建索引,这就是我们不这样做的原因。
其他选项是使用片段,在片段元素中设置片段根是否有意义?不确定,因为问题仍然存在(在集合中搜索具有特定名称的一个段为400
所以我的问题是:如何重构原始文档,以便我的查询在子秒响应中执行。
答案 0 :(得分:1)
看起来迈克在上一个问题中没有提到Path索引的选项。您可以在/postcode/category[name="Oplages"]/variable[name="Oplage"]/segment[name="Bruto"]
上专门创建索引,方法是将其用作路径模式。这将有助于尽可能准确地定位相关片段。
但我不确定您对最终结果的期望。您是否需要Bruto段值列表,或者您是否在寻找包含匹配段的邮政编码?很大程度上取决于你想要的结果。从头到尾思考问题可能很有用。
HTH!
答案 1 :(得分:0)
我不喜欢使用子片段。编写一个意外地将所有片段加载到内存中的查询太容易了。这个用例可能是一个例外,碎片可能是最好的方式,但我会把它作为最后的手段。我的经验是,它一开始看起来效果很好,但随着时间的推移会出现越来越多的问题。
在上一个问题中,我提到了其他可能性。我会在这里回顾一下。主要技巧是要记住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>
将该XML存储在/oplages/9728/Bruto
,只需调用doc('/oplages/9728/Bruto')
即可获得该值。您还可以使用多个URI序列调用fn:doc
。您可能会看到围绕文档大小以及如何构建数据进行权衡。
我提到的另一种可能性是使用范围索引和https://docs.marklogic.com/cts:values或https://docs.marklogic.com/cts:value-co-occurrences来查询数据。此方法直接从值索引中提取数据,而不是检查XML树。然而,使用小型,定义明确的文档,这种方法仍然更容易。使用像原始样本的XML,每个文档包含许多值,您需要位置感知范围索引和精心编写的位置范围查询。
答案 2 :(得分:0)
我测试了Mike和Geert的建议,你可以通过以下方式实现你想要的东西(我相信它是为了获得邮政编码的bruto和Netto值): 创建两个路径范围索引,一个用于Bruto,另一个用于Netto: / P4:邮政编码/ P4:类别/ P4:可变/ P4:段[@名称= 'Bruto'] / P4:邮政编码/ P4:类别/ P4:可变/ P4:段[@名称= '内托'] 不要忘记为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>
或者您可以在/ p4:postcode / @ id上创建路径范围索引并执行:
declare namespace p4 = "http://www.nvsp.nl/p4";
let $segments := ("Bruto","Netto")
for $segment in $segments
return ($segment,
cts:value-co-occurrences(
cts:path-reference("/p4:postcode/@id"),
cts:path-reference(fn:concat("/p4:postcode/p4:category/p4:variable/p4:segment[@name='",$segment,"']")),()))
这将返回邮政编码加上给定的段值:
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>