2012-02-13 108 views
1

我有一个很大的xml数据库(30 000个文件,1.3 Go)。此数据库中的一个文件列出数据库中存在的所有其他文件。我的目标是“简单地”检查列出的所有文件是否存在于数据库中。但我不能关心文件的名称,只能处理文档中的XML代码。XQuery - 为BIG数据库优化查询

这是类似的东西:

declare variable $root := fn:collection(); 

declare function local:isValid($fileCode) { 

let $fileSearchedIdentCode := $root/dmodule/identity/dmCode 
return 
$fileCode/@attribute1 = $fileSearchedIdentCode/@attribute1 and 
$fileCode/@attribute2 = $fileSearchedIdentCode/@attribute2 and 
$fileCode/@attribute3 = $fileSearchedIdentCode/@attribute3 

}; 

<result> 
{ 
for $fileCode in $root/file[identity/@fileType eq 'listOfFiles']/fileContent/fileEntry/fileCode 
return 
    if (local:isValid($fileCode)) 
    then <filePresent>1</filePresent> 
    else <fileNonPresent>2</fileNonPresent> 

} 
</result> 

上面的代码运行一个小DATABSE但对于我的,它是需要时间的数量惊人。

SO,我不知道是否有人能帮助我提高,以便在合理的时间来执行它的代码;)

(我的数据库被索引)

感谢您的帮助!

Johann

+0

我不能编辑我的帖子:(对不起,不说“你好” – Johann 2012-02-13 14:30:14

+0

说你好不是自定义的。你能告诉你使用哪个数据库吗?使用索引可能需要使用专有扩展,或者优化表达式以匹配内置优化30k文档并不多,但足以想要使用索引 – grtjn 2012-02-13 14:44:25

+0

我必须在几个数据库(baseX,marklogic,oracle db XML和qizx)上创建一个基准测试,目前我使用的是BaseX。 – Johann 2012-02-13 14:48:54

回答

3

看起来属性索引不适用于local:isValid函数中的属性检查。您可以通过重写他们实现,作为XPath的谓词:

declare variable $root := fn:collection(); 

declare function local:isValid($fileCode) { 
    $root/dmodule/identity/dmCode[@attribute1 = $fileCode/@attribute1 
    and @attribute2 = $fileCode/@attribute2 
    and @attribute3 = $fileCode/@attribute3] 
}; 

<result> { 
    for $fileCode in $root/file[identity/@fileType = 'listOfFiles']/fileContent/fileEntry/fileCode 
    return 
    if (local:isValid($fileCode)) 
     then <filePresent>1</filePresent> 
     else <fileNonPresent>2</fileNonPresent> 
}</result> 

这些变化之后,查询信息鉴于BaseX告诉我,该指数用于:

Compiling: 
- pre-evaluating fn:collection() 
- rewriting And expression to predicate(s) 
- rewriting fn:boolean(@*:attribute1 = $fileCode/@attribute1) 
- rewriting fn:boolean(@*:attribute2 = $fileCode/@attribute2) 
- rewriting fn:boolean(@*:attribute3 = $fileCode/@attribute3) 
- applying attribute index 
- applying attribute index 

和评估时间滴从4'500ms到〜20ms为我的测试数据。

+0

当我测试你的解决方案时,有一些奇怪的东西: BaseX无法执行某些内容......即使对于小测试,它也会以“Please wait ...”运行,运行并再次运行。 我误解了配置吗? – Johann 2012-02-13 16:01:28

+0

您是否可以创建可管理大小的示例集合,以便我们可以测试我们的建议?这样做很容易。 – 2012-02-13 16:38:12

+0

事实上,我只用5个XML文件(28 Mo)进行测试,当我点击“运行”按钮时,它被写为“Please Wait ...”,并且没有任何反应。 – Johann 2012-02-13 17:03:28

0

是否有助于用等号(=)替换“eq”?

+0

它不会改变任何性能......我刚刚测试过 – Johann 2012-02-13 15:33:43

+0

你尝试过不同版本的basex(例如BaseX 7 vs 7.1)?一般来说,像您这样的查询应该使用现有的(自动创建的)值索引进行优化,所以请随时为我们提供一些匿名化的XML片段! – 2012-02-14 08:54:11

1

您没有将eXist-db包含在您的测试系统列表中,但是如果您有兴趣用数据对其进行基准测试,那么有一篇关于优化查询并智能地使用索引来加速eXist性能的文章-D b。见http://exist-db.org/exist/tuning.xml。您发布的查询应该没有修改就能正常工作,但文章中的建议一定会帮助您提高性能。如果您需要帮助,请随时发布到现有的邮件列表。不管你使用哪种系统,我都会非常感兴趣地知道你的结果 - 而不仅仅是我 - 我认为这会引起广泛的兴趣。

祝你好运!

3

对于MarkLogic,您需要注意索引查找仅在某些表达式和函数中发生。在这种情况下,您需要更紧凑的代码。下面是应该产生相同的结果,但会以简单的方式使用索引的一种形式:

<result> 
{ 
    for $fileCode in 
     collection()/ 
     file[identity/@fileType eq "listOfFiles"]/ 
     fileContent/ 
     fileEntry/ 
     fileCode 
    let $fc1 := $fileCode/@attribute1/string() 
    let $fc2 := $fileCode/@attribute2/string() 
    let $fc3 := $fileCode/@attribute3/string() 
    return 
     if (collection()/ 
      dmodule/ 
      identity/ 
      dmCode[ 
      @attribute1 eq $fc1][ 
      @attribute2 eq $fc2][ 
      @attribute3 eq $fc3]) 
     then <filePresent>1</filePresent> 
     else <fileNonPresent>2</fileNonPresent> 
    } 
</result> 

但是该代码将每listOfFiles项,这不是最佳执行一个数据库查询。

可以进一步优化。首先,MarkLogic是一个面向文档的数据库,每个文档都有一个唯一的URI。因此,如果您只将三个属性值编码到每个文档URI中,效率会更高。我们可能会使用类似string-join(($fc1, $fc2, $fc3), '/')来构建URI。然后,您可以使用doc()调用来检查每个值,这比XPath查找更有效率 - 即使在使用索引时也是如此。一旦做出更改,listOfFiles文档可能会存储URI而不是属性值。

二,我认为结果格式不是很有用。它告诉你一些文件丢失,但没有。我会重构,以便代码只返回缺少的文档URI。我们也可能在MarkLogic中启用额外的索引:URI词典。这会自动维护所有文档URI的值索引,有点像您的listOfFiles文档。使用URI的词汇,我可以这样写:

<result>{ 
    let $uris := 
     collection()/ 
     file[identity/@fileType eq "listOfFiles"]/ 
     fileContent/ 
     fileEntry/ 
     fileCode/ 
     string-join(
     (@attribute1/string(), 
     @attribute2/string(), 
     @attribute3/string()), 
     "/") 
    let $uris-present := cts:uris((), "document", cts:document-query($uris)) 
    for $uri in $uris 
    where not($uri = $uris-present) 
    return <missing>{ $uri }</missing> 
}</result> 

,只需要一个数据库查询,并不会在内存中的必要的工作的其余部分。它应该比原始查询或我的第一次迭代缩放得更好。如果你不跟我的结果格式的返工同意,并仍然希望看到的结果对于每个输入fileCode,你可以重构...where...return...条款列入...return...if...then...else...在原始查询。

务必在https://github.com/marklogic/cq使用的配置文件的工具 - 它可以帮助您试试最佳化替代和现货的机会。

+0

快速附录re:剖析。一个类似的配置文件工具现在作为查询控制台的一部分附带(点浏览器到'http:// yourserver:8000/qconsole'),所以如果你运行的是MarkLogic 5,你不会真的需要cq。 – 2012-02-13 21:12:48

1

MarkLogic应该处理您的查询速度快,如果你定义每个您使用在比较属性的属性范围的索引。

您可以通过MarkLogic管理UI做到这一点(HTTP:// 主机名:8001):

  • 在左侧选择在数据库
  • 选择属性范围索引数据库
  • 选择添加到定义一个新的属性范围指数
  • 指定元素(dmcode)和属性(ATTRIBUTE1,attribute2,attribute3)引用该区域指数(不要忘了指定命名空间,如果你的元素是在证书ain命名空间)。
  • 单击确定以创建范围索引。

您正在使用什么版本的MarkLogic的? 如果使用的是MarkLogic 5,你也可以使用查询控制台来测试您的查询:

(HTTP:// 主机名:8000/qconsole)

随意问,如果你有任何问题/让我知道事情的后续。 我来自MarkLogic,很乐意提供帮助。