假设,我有一堆带有根元素的医学期刊作为medicalJournal.All医学期刊属于'mj'集合,'mj'集合只有医学期刊.其他类型的期刊也有自己的集合(physicsJournal - >'pj')为了检索所有医学期刊,我写了世界上最简单的查询:
cts:search(/medicalJournal,cts:and-query(()))
Run Code Online (Sandbox Code Playgroud)
但是,我的同行说为什么不对'pj'而不是空和查询放置一个集合查询,从而添加一个额外的约束.理由是,这可能会避免获取所有片段id的列表虽然当我第一次运行集合查询时,查询表显示了一些列表缓存未命中.请告诉我应该选择哪个选项?
简短的回答是cts:and-query(())没有固有的成本,但是集合查询会比您的可搜索表达式更快.我完全避免使用可搜索的表达式,因此我将其写为:
cts:search(collection(), cts:collection-query($journal-collection))
Run Code Online (Sandbox Code Playgroud)
更长的答案是你可以很容易地测试它,并从xdmp:plan'和'xdmp:query-meters` 获得一些好的信息.您还可以使用查询分析.
让我们从插入一些测试文档开始.这使用https://github.com/mblakele/taskbot
(: insert 500k test documents. :)
import module namespace tb="ns://blakeley.com/taskbot"
at "taskbot.xqm" ;
tb:list-segment-process(
(: Total size of the job. :)
1 to 500 * 1000,
(: Size of each segment of work. :)
500,
"test/asset",
(: This anonymous function will be called for each segment. :)
function($list as item()+, $opts as map:map?) {
(: Any chainsaw should have a safety. Check it here. :)
tb:maybe-fatal(),
let $type-list := ('mj', 'pj', 'aj', 'bj', 'cj', 'dj')
let $type-count := count($type-list)
for $i in $list
let $idx := 1 + xdmp:random($type-count - 1)
let $type as xs:string := subsequence($type-list, $idx, 1)
return xdmp:document-insert(
"test/"||$type||"/"||$i,
element article {
element id { $type||$i },
element type { $type },
element { $type } { $i },
element issue { 1 + xdmp:random(99) },
element article { 1 + xdmp:random(999) },
(1 to xdmp:random(9)) ! element article-ref {
xdmp:random(1000) } },
xdmp:default-permissions(),
($type)),
(: This is an update, so be sure to commit each segment. :)
xdmp:commit() },
(: options - not used in this example. :)
map:new(map:entry('testing', '123...')),
(: This is an update, so be sure to say so. :)
$tb:OPTIONS-UPDATE)
Run Code Online (Sandbox Code Playgroud)
坐下来等待文件加载.您可以检查ErrorLog.txt以查看进度,或刷新数据库状态.或者只是看你的CPU.
加载后,这些测试文档包含大量冗余.这让我们可以测试不同的方法来检索文档.这是一个要查看的示例:
<?xml version="1.0" encoding="UTF-8"?>
<article>
<id>mj192462</id>
<type>mj</type>
<mj>192462</mj>
<issue>31</issue>
<article>432</article>
<article-ref>589</article-ref>
<article-ref>812</article-ref>
<article-ref>316</article-ref>
<article-ref>512</article-ref>
<article-ref>380</article-ref>
</article>
Run Code Online (Sandbox Code Playgroud)
现在,我更喜欢将第一个cts:search参数保留为collection()cts:query参数中的所有内容.它更具有可组合性,并且避免任何试图突破可搜索表达式的界限.所以我从测试开始cts:search(//mj, cts:and-query(()))就相当于cts:search(collection(), cts:element-query(xs:QName('mj'), cts:and-query(()))).使用7.0-4.1,xdmp:plan我发现它们都使用相同的查找,我们可能会将其缩写为OR(element(mj), link-child(descendant(element(mj)))).
<qry:final-plan>
<qry:and-query>
<qry:or-two-queries>
<qry:term-query weight="0">
<qry:key>213142789040258053</qry:key>
<qry:annotation>element(mj)</qry:annotation>
</qry:term-query>
<qry:term-query weight="0">
<qry:key>11205365121816230941</qry:key>
<qry:annotation>link-child(descendant(element(mj)))</qry:annotation>
</qry:term-query>
</qry:or-two-queries>
</qry:and-query>
</qry:final-plan>
Run Code Online (Sandbox Code Playgroud)
请注意计划中没有与您相对应的内容cts:and-query(())?那是因为它是一个noop.查询中的真正工作cts:search(/medicalJournal, cts:and-query(()))是通过处理可搜索的表达式来完成的/medicalJournal.这可能有助于解释为什么我更喜欢将可搜索的表达式保留为collection()并使用cts:query参数进行匹配.
这个link-child词很有意思,但我们现在不再讨论它.
相反,让我们看一些其他方式来获取mj文章.我们可以查询集合mj,或者在哪里type[.='mj']查询元素或查询目录test/mj/.
collection('mj')
cts:search(collection(), cts:collection-query('mj'))
cts:search(collection(), cts:element-value-query(xs:QName('type'), 'mj')
cts:search(collection(), cts:directory-query('test/mj/', 'infinity'))
Run Code Online (Sandbox Code Playgroud)
检查xdmp:plan每个输出,我们看到qry:final-plan显示term-query前两个表单的两个查找.这看起来很像element-queryon mj- 但并不总是相同的术语.然后我们看到最后三个一个.术语查找驱动查询复杂性,因此我们可以说元素查询的复杂性是集合查询的两倍.
我认为这几乎可以回答你的问题:cts:search(collection(), cts:collection-query('mj'))可以更快cts:search(collection(), cts:element-query(xs:QName('mj'), cts:and-query(()))),因为它的查找次数更少.
但是让我们继续前三,看看是否有任何理由使用最后三个替代品中的一个或另一个.集合查找和目录查找都分别使用URI:集合URI和目录URI.这些都经过了大量优化,因此我们可能期望它们比元素值查找更快.
让我们看看我们是否可以使用xdmp:query-meters.以下面的形式运行最后三个表达式中的每一个:
xdmp:describe(
cts:search(collection(), cts:collection-query('mj')))
, xdmp:query-meters()
Run Code Online (Sandbox Code Playgroud)
对于本练习,重点关注xdmp:query-meters树缓存和列表缓存命中和未命中的内容.不要过多关注elapsed-time,因为这将在很大程度上取决于缓存了多少索引数据,我们无法控制它.无论如何,你应该看到相同的总树命中和错过所有三个查询.我看到每个都有9个,但重要的是没有区别因为结果是一样的.但是列表缓存命中和错过总数不同.对于集合或目录,它等于数据库中的站点数量:在我的情况下3.但是对于元素值,它是站点数量的两倍:在我的情况下6.所以其他所有相等,元素值查找冒险做两次很多I/O. 所有其他方面都不相同:URI查找根本不太可能进行任何I/O,因为它们的索引往往会一直保留在内存中.
我们可以得出结论,虽然其他方法都不是非常慢,但是按集合URI或目录URI查找是最好的.
| 归档时间: |
|
| 查看次数: |
312 次 |
| 最近记录: |