如何通过Xquery Map调整我的组?

时间:2015-11-16 21:42:22

标签: xquery marklogic

忙于将SQLServer 2008 R2和MarkLogic 8与简单的Person Entity进行比较。 我的数据集适用于100万条记录/文件。注意:两个数据库都在同一台计算机上(Localhost)。

以下SQLServer查询已准备就绪:

set statistics time on 

select top 10 FirstName + ' ' + LastName, count(FirstName + ' ' + LastName)
from [Person]
group by FirstName + ' ' + LastName
order by count(FirstName + ' ' + LastName) desc

set statistics time off

结果是:

Richard Petter  421
Mark Petter 404
Erik Petter 400
Arjan Petter    239
Erik Wind   237
Jordi Petter    235
Richard Hilbrink    234
Mark Dominee    234
Richard De Boer 233
Erik Bakker 233

SQL Server Execution Times:
  CPU time = 717 ms,  elapsed time = 198 ms.

然而,MarkLogic 8上的XQuery要慢得多:

(                               
  let $m := map:map()
  let $build :=
    for $person in collection('/collections/Persons')/Person
    let $pname := $person/concat(FirstName/text(), ' ', LastName/text())
    return map:put(
      $m, $pname, sum((
        map:get($m, $pname), 1)))
  for $pname in map:keys($m)
  order by map:get($m, $pname) descending
  return
    concat($pname, ' => ', map:get($m, $pname))
)[1 to 10]
, 
xdmp:query-meters()/qm:elapsed-time

结果是:

Richard Petter => 421
Mark Petter => 404
Erik Petter => 400
Arjan Petter => 239
Erik Wind => 237
Jordi Petter => 235
Mark Dominee => 234
Richard Hilbrink => 234
Erik Bakker => 233
Richard De Boer => 233

elapsed-time:PT42.797S

198毫秒对42秒我认为差别很大。 XQuery使用地图按照本指南进行分组:https://blakeley.com/blogofile/archives/560/

我有两个问题:

  • XQuery是否可以以任何方式调整以获得更好的性能?
  • XQuery 3.0 with group by已在MarkLogic 8上使用吗?

感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

正如@wst所说,你当前实施的挑战是它正在加载所有文件,以便取出名字和名字,逐个添加,然后报告前十名。而不是这样做,你会想要使用索引。

假设您在FirstName和LastName上设置了字符串范围索引。在这种情况下,你可以运行:

xquery version "1.0-ml";

for $co in 
  cts:element-value-co-occurrences(
    xs:QName("FirstName"), 
    xs:QName("LastName"), 
    ("frequency-order", "limit=10"))
return
  $co/cts:value[1] || ' ' || $co/cts:value[2] || ' => ' || cts:frequency($co)

这使用索引在同一文档中查找名字和姓氏。 cts:频率表示共现发生的频率。这是所有索引驱动的,所以它会非常快。

答案 1 :(得分:2)

首先,是的,有很多方法可以在MarkLogic中调优查询。一个明显的方法是使用范围索引;但是,我强烈建议先阅读有关该主题的文档:

https://docs.marklogic.com/guide/performance

为了更高层次地了解数据库架构,有一篇名为Inside Marklogic Server的白皮书广泛解释了设计:

https://developer.marklogic.com/inside-marklogic

关于group by,也许MarkLogic的某个人想要正式发表评论,但据我所知,他们的立场是不可能建立一个普遍高效的group by,所以他们选择不实现它。这使开发人员有责任了解编写快速查询的最佳实践。

具体来说,在你的例子中,Mike Blakeley基于地图的分组模式是不可能的。在ML中有几种不同的方式来分析查询,其中任何一种都应该引导您进入任何热点。我的猜测是获取Person数据的IO开销是问题所在。解决此问题的一种常见方法是为FirstNameLastName配置范围索引,并使用cts:value-tuples从范围索引中同时查询它们,这将避免为不在的每个文档转到磁盘缓存。

答案 2 :(得分:0)

两个答案都是相关的。但是根据你的要求,David C的回答最接近你想要的。但是,这个答案假定您需要找到名字和姓氏的组合。

如果您的文档有一个标识的uniq字段(想想主键),那么:

    • 在该字段上添加范围索引
    • 使用cts:element-values --- options :( fragment-frequency,frequency-order,eager,concurrent,limit = 10)
  1. - 计数来自cts:频率
  2. - 然后使用生成的10个ID来获取名称信息
  3. 如果唯一ID字段可以是整数,那么初始搜索的速度也要快许多倍。

    并且..也可以使用我的步骤1-2立即获取Id的列表,并使用这些作为David C的答案的限制器 - 对'中的ID使用元素值范围查询'查询'选项。这使您不必像我的选择那样自己建立名称,并且可以加快David C的方法。

    故事的道德 - 如果没有首先调整数据库的性能(索引)和使用特定的查询(范围查询,共现等),那么结果就没有任何意义。

    故事的道德 - 第2部分:许多方法 - 所有相关和可行的。细微差别 - 全部取决于您的具体数据。

    该文档列在下面

    https://docs.marklogic.com/cts:element-values