1

我有一个很大的 xml 数据库(30 000 个文件,1.3 Go)。此数据库中的一个文件列出了数据库中存在的所有其他文件。我的目标是“简单地”检查列出的所有文件是否都存在于数据库中。但我必须不关心文件的名称,而只关心文档中的 XML 代码。

这是这样的:

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>

上面的代码是为一个小型数据库运行的,但对我来说,它需要大量的时间。

所以,我想知道是否有人可以帮助我改进该代码以便在合理的时间内执行它;)

(我的数据库被索引)

谢谢你的帮助 !!

约翰

4

5 回答 5

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 中的Query Info视图告诉我使用了索引:

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。

于 2012-02-13T15:46:35.817 回答
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>

这只需要一次数据库查找,其余的必要工作都在内存中完成。它应该比您的原始查询或我的第一次迭代要好得多。如果您不同意我对结果格式的修改,并且仍然希望查看每个 input 的结果,您可以将子句fileCode重构为原始查询中的内容。...where...return......return...if...then...else...

请务必使用https://github.com/marklogic/cq中的配置文件工具- 它可以帮助您尝试替代方案并发现优化机会。

于 2012-02-13T18:17:27.540 回答
1

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

您可以通过 MarkLogic Admin UI (http:// hostname :8001) 执行此操作:

  • 在数据库下选择您的数据库
  • 选择左侧的属性范围索引
  • 选择添加以定义新的属性范围索引
  • 指定引用范围索引的元素(dmcode)和属性(attribute1,attribute2,attribute3)(如果您的元素在某个命名空间中,请不要忘记指定命名空间)。
  • 单击确定以创建范围索引。

您使用的是哪个版本的 MarkLogic?如果您使用的是 MarkLogic 5,您还可以使用查询控制台来测试您的查询:

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

如果您有任何问题,请随时询问/让我知道情况如何。我来自 MarkLogic,很乐意提供帮助。

于 2012-02-13T20:38:49.637 回答
1

您没有将 eXist-db 包含在您的测试系统列表中,但如果您有兴趣使用您的数据对其进行基准测试,这里有一篇很棒的文章,介绍了优化查询和智能地使用索引来提高 eXist-db 的性能。请参阅http://exist-db.org/exist/tuning.xml。您发布的查询无需修改即可正常工作,但文章中的建议肯定会帮助您提高性能。如果您需要帮助,请随时发布到存在开放邮件列表。

无论您使用哪种系统,我都很想知道您的结果——不仅是我——我认为会有广泛的兴趣。

祝你好运!

于 2012-02-13T16:49:05.987 回答
0

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

于 2012-02-13T15:15:34.217 回答