marklogic delete>插入> cpf对新文件的行动

时间:2014-01-20 11:11:50

标签: transactions xquery marklogic

请参阅下面的更新!

我有以下问题:我们正在收集(数百万)文档(推文)到ML中,在插入时,我们有一个cpf作业,为每个文档创建元数据。更精确的是,它根据位置添加地理标记(如果存在位置或坐标)。

现在我们有一个数据库,它一直在收集推文而没有激活地理标记。我们希望通过删除并重新插入尚未具有正确元数据地理标记元素的每个文档来处理存储的推文与此cpf作业。 然后cpf完成它的工作并对“新”文档进行地理标记。

我们编写了以下代码来删除和插入文档,但是我们收到了XDMP-CONFLICTUPDATES错误。我一直在阅读有关交易的内容并尝试了几件事,“;”特技。包装在xdmp中:eval或拆分删除并插入来自xdmp:spawn的两个单独的函数调用。

仍然没有运气。

菌种-rename.xqy

xquery version "1.0-ml";

declare namespace j = "http://marklogic.com/xdmp/json/basic";
declare variable $to_process external;

declare function local:document-rename(
   $old-uri as xs:string, $new-uri as xs:string)
  as empty-sequence()
{
    (:xdmp:set-transaction-mode("update"),:)
    xdmp:eval(xdmp:document-delete($old-uri)),
    (:xdmp:commit():)

    let $permissions := xdmp:document-get-permissions($old-uri)
    let $collections := xdmp:document-get-collections($old-uri)
    return xdmp:document-insert(
      $new-uri, doc($old-uri),
      if ($permissions) then $permissions
      else xdmp:default-permissions(),
      if ($collections) then $collections
      else xdmp:default-collections(),
      xdmp:document-get-quality($old-uri)
    )
};

for $d in map:keys($to_process)
let $rename := local:document-rename($d, map:get($to_process,$d))
return true()

并为我们使用的特定文档集运行作业:

xquery version "1.0-ml";
declare namespace j = "http://marklogic.com/xdmp/json/basic";
declare namespace dikw = 'http://www.example.com/dikw_functions.xqy';
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";

let $foo := cts:uris((),(), cts:not-query(cts:element-query(xs:QName("j:dikwmetadata"), cts:element-query(xs:QName("j:data"), cts:and-query(())))))
let $items := cts:uri-match("/twitter/403580066367815680.json") (:any valid uri or set of uris:)

let $map := map:map()

    let $f := doc($items[1])
    let $id := $f/j:json/j:id/text()
    let $oldUri := xdmp:node-uri($f)
    let $newUri := fn:concat("/twitter/", $f/j:json/j:id/text(), ".json")
    let $put := map:put($map,$oldUri,$newUri)

    let $spawn := xdmp:spawn("/Modules/DIKW/spawn-rename-split.xqy", (xs:QName("to_process"), $map))

return ($oldUri, " - ", $newUri) 

问题:

如何设置代码,以便先在单独的事务中删除地图中的文档,然后再将其插入,以便cpf可以进行地理标记?


更新

好的,按照grtjn他的评论(到目前为止!) 我尝试重写我的代码,如:

xquery version "1.0-ml";
declare namespace j = "http://marklogic.com/xdmp/json/basic";

let $entries := cts:uri-match("//twitter/*")
let $entry-count := fn:count($entries)

let $transaction-size := 100 (: batch size $max :)
let $total-transactions := ceiling($entry-count div $transaction-size)

(: set total documents and total transactions so UI displays collecting :)
(: skip 84 85
let $set-total := infodev:ticket-set-total-documents($ticket-id, $entry-count)
let $set-trans := infodev:ticket-set-total-transactions($ticket-id,$total-transactions)
:)
    (: create transactions by breaking document set into maps
each maps's documents are saved to the db in their own transaction :)
let $transactions :=
    for $i at $index in 1 to $total-transactions
    let $map := map:map()
    let $start := (($i -1) *$transaction-size) + 1
    let $finish := min((($start - 1 + $transaction-size),$entry-count))
    let $put :=
        for $entry in ($entries)[$start to $finish]
        (: 96
        let $id := fn:concat(fn:string($entry/atom:id),".xml")
        :)
        let $id := fn:doc($entry)/j:json/j:id/text()
        return map:put($map,$id,$entry)
    return $map

(: the callback function for ingest 
skip 101 let $function := xdmp:function(xs:QName("feed:process-file"))
:)
let $ingestion :=
    for $transaction at $index in $transactions
    return true()
    return $ingestion (: this second return statement seems odd? :)
    (: do spawn here? :)
    (: xdmp:spawn("/modules/spawn-move.xqy", (xs:QName("to_process"), $map)) :)

现在我感到很困惑,为了让这个'正常',我需要添加最后一个似乎不对的回报。此外,我试图找出究竟发生了什么,如果我运行查询,它返回时出现超时错误。 我想首先了解交易实际上做了什么。 对不起我的无知,但似乎执行一个(相对简单的)任务,重命名一些文档看起来不那么简单?

为了完整性,我的spawn-move.qry在这里:

xquery version "1.0-ml";

declare namespace j = "http://marklogic.com/xdmp/json/basic";
declare variable $to_process external;


declare function local:document-move(
   $id as xs:string, $doc as xs:string)
  as empty-sequence()
{
    let $newUri := fn:concat("/twitter/", $id, ".json")
    let $ins := xdmp:document-insert($newUri,fn:doc($doc))
    let $del := xdmp:document-delete($doc) 
    return true()
};

for $d in map:keys($to_process)
let $move := local:document-move($d, map:get($to_process,$d))
return true()

3 个答案:

答案 0 :(得分:1)

我怀疑你实际上并没有重命名文档,只是重新插入它们。您引用的rename函数不会预测到这种情况,如果document-delete$old-uri相同,那么$new-uri就会多余。在这种情况下,在删除周围添加if以跳过它。保留其他所有内容以保留权限,集合,质量和属性。 document-insert函数已在实际插入之前删除了预先存在的文档。另见:

http://docs.marklogic.com/xdmp:document-insert

您可能还会考虑添加一些逻辑来执行多个生成。您可能希望在100到500个文档的批次中重新插入文档,具体取决于硬件和林配置。有一个很好的例子,说明如何在github上的这个信息集收集器中计算“事务”(从第80行开始):

https://github.com/marklogic/infostudio-plugins/blob/master/collectors/collector-feed.xqy

您还可以考虑在这些交易中进行地理工作,而不是将其委托给CPF。但是,如果您的地理查找涉及外部调用,例如可能很慢,那么请坚持使用CPF ..

HTH!

答案 1 :(得分:0)

在您的示例中,您尝试删除并在同一步骤中将文档写入同一URI。你可以用xdmp:commit()解决这个问题。但是,另一种解决方案是首先在一个批次中重命名文档(将它们全部移出),然后在完成之后,将它们分批移回。

答案 2 :(得分:0)

实际上,如果您将CPF管道配置为处理诸如created之类的更新(这是默认配置),那么只需重新插入文档即可:

xdmp:document-insert($ d,doc($ d))