【问题标题】:Recursive copy of a folder with XQuery使用 XQuery 递归复制文件夹
【发布时间】:2018-02-07 01:32:39
【问题描述】:

我必须在 MarkLogic 服务器中复制整个项目文件夹,而不是手动执行,我决定使用递归函数来执行此操作,但这正在成为我曾经有过的最糟糕的想法。我在交易和语法方面遇到问题,但作为新手,我找不到真正的解决方法。这是我的代码,谢谢你的帮助!

import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";

declare option xdmp:set-transaction-mode "update";

declare function local:recursive-copy($filesystem as xs:string, $uri as xs:string)
{
  for $e in xdmp:filesystem-directory($filesystem)/dir:entry
  return 
    if($e/dir:type/text() = "file")
        then dls:document-insert-and-manage($e/dir:filename, fn:false(), $e/dir:pathname)
    else
      (
          xdmp:directory-create(concat(concat($uri, data($e/dir:filename)), "/")),
          local:recursive-copy($e/dir:pathname, $uri)
      )

};

let $filesystemfolder := 'C:\Users\WB523152\Downloads\expath-ml-console-0.4.0\src'
let $uri := "/expath_console/"

return local:recursive-copy($filesystemfolder, $uri)

【问题讨论】:

  • 您要复印多少份文件?如果您的数据集非常大,好的解决方案会缩小范围。另外,你确定你需要dls吗?你可以接受 good-ol xdmp:document-insert 吗?
  • @SamMefford 好吧,我正在尝试复制一个充当 UI 控制台的整个嵌套项目,以查看服务器本身内部文件和文件夹的层次结构,所以不,只使用 xdmp:document-插入将无济于事。不,我不确定 dls,我只是想找到解决方案。我也尝试使用 mlcp 命令,但无法访问服务器。

标签: recursion transactions xquery marklogic xquery-update


【解决方案1】:

MLCP 会很好用。但是,这是我的版本:

declare option xdmp:set-transaction-mode "update";

declare variable $prefix-replace := ('C:/', '/expath_console/');

declare function local:recursive-copy($filesystem as xs:string){
   for $e in xdmp:filesystem-directory($filesystem)/dir:entry
    return 
      if($e/dir:type/text() = "file")
         then 
           let $source := $e/dir:pathname/text()
           let $dest := fn:replace($source, $prefix-replace[1], $prefix-replace[2]) 
           let $_ := xdmp:document-insert($source,
              <options xmlns="xdmp:document-load">
                <uri>{$dest}</uri>
              </options>)
           return <record>
                     <from>{$source}</from>
                     <to>{$dest}</to>
                  </record>
         else
           local:recursive-copy($e/dir:pathname)

};

let $filesystemfolder := 'C:\Temp'

return <results>{local:recursive-copy($filesystemfolder)}</results> 

请注意以下几点:

  • 我将示例更改为 C:\Temp 目录
  • 输出只是 XML,因为按照惯例,我会尝试这样做,以防我想分析结果。这实际上是我发现与冲突更新相关的错误的方式。
  • 我选择在 URI 上定义一个简单的前缀替换
  • 我发现您的描述中不需要 DLS
  • 我认为在您的用例中不需要显式创建目录
  • 您获得冲突更新的原因是您仅使用文件名作为 URI。在整个目录结构中,这些名称不是唯一的 - 因此对相同 URI 的双重插入的更新冲突。
  • 这不是可靠的代码:
    • 您必须确保 URI 有效。并非所有文件系统路径/名称都适用于 URI,因此您需要对此进行测试并在需要时转义字符。
    • 大型文件系统会超时,因此分批生成可能很有用。
      • 举个例子,我可能会像在我的 XML 中一样收集文档列表,然后通过为每 100 个文档生成一个新任务来处理该列表。这可以通过 xdmp:spawn-function 上的简单循环或使用诸如 @mblakele 的 taskbot 之类的库来完成

【讨论】:

  • 我承认代码质量不是最好的,我理解它的局限性,但由于项目很小,我没有想到大型文件系统。另一方面,这个项目并没有那么小,不能手动复制,所以这是一个自动化复制的尝试。我也尝试过使用 mlcp,但目前我无法告诉他将文件复制到哪个特定数据库,我找到的唯一解决方案是更改从默认服务器(即 App-Services)引用的数据库。我知道这是一种非常残酷的方法,但对这些事情不熟悉,我会尽力面对问题。
  • 不管怎样,谢谢你的解决方案,我会尽快尝试的!
  • mlcp 可以针对端口 8000 运行,并且具有 -output_database 选项。请参阅此处的第 2.4 节:docs.marklogic.com/guide/mlcp.pdf
  • 来自网站上的 marklogic 指南,有一个选项可以针对特定端口运行命令,但它被伪装了,所以我只能在端口 8000 上运行它,但感谢您提供另一个选项,它似乎是解决我发现的问题的合理方法!
猜你喜欢
  • 2019-11-04
  • 2011-01-12
  • 2015-12-03
  • 2012-11-26
  • 2014-10-20
  • 1970-01-01
  • 2017-10-03
  • 1970-01-01
相关资源
最近更新 更多