MarkLogic:将数据写入查询中的文档,然后在同一查询中访问这些文档

时间:2014-07-08 13:41:32

标签: xml xquery marklogic

在MarkLogic中,我想编写创建文档/地图的函数,然后访问该查询中的那些文档/地图 - 我相信这样做可以避免内存问题/超时。

但是,除非我在单独的查询中运行每个函数,否则代码不起作用。如何强制一个函数只在另一个函数完成时运行:即将文档保存到磁盘?

修改 我遇到的问题是我想要找到两个元素的不同值,比如说和文档集合中的元素。我还想知道这些元素的每个值组合的出现频率。

我希望能够创建的结果看起来像是在一个文档集合中,每个文档都包含一个包含id的元素并包含一个代表一个人的字符串:

<pairs>
    <pair frequency="5">
       <thing-1>01257</thing-1>
       <thing-2>John Smith</thing-2>
    </pair>
</pairs>

这是我一直在使用的代码:

xquery version "1.0-ml";
declare namespace local = "http://www.local.com";

declare variable $collections := 'A' ;
declare variable $query-name := 'A-query' ;
declare variable $number-of-documents := count(collection($collections)) ; 
declare variable $map-collection := concat ($query-name, '-maps') ;

(: create a temporary collection to store data saved during the query :)
declare function local:document-set-creator($counter, $iteration) {
 if ($counter > ($number-of-documents + 1000)) 
  then ()
   else (
    let $name := concat($query-name, '-part', $iteration) 
         let $uris := for $i in subsequence(cts:uris( (), (), cts:collection-query($collections) ), $counter, 1000) return $i 
     let $results := 
                <results>
                    {
                        for $i in $uris
                            let $thing-1 := cts:search(/*/element/thing-1 , cts:document-query($i) )
                            let $thing-2 := cts:search(/*/element/thing-2 , cts:document-query($i) )
                          return
                                <pair>
                                 <thing1>{$thing-1/normalize-space(string())}</thing1>
                                 <thing2>{$thing-2/normalize-space(string())}</thing2>
                                </pair>
                            }
                    </results>   
            let $path-name := concat('pairs-', $name, '.xml') 

      return
        xdmp:document-insert($path-name , $results, (), $query-name )
         ,
        xdmp:sleep(1000)
          ,
        local:document-set-creator(($counter + 1000), ($iteration + 1))

    )
} ;

(: take values from the pairs list, concatenate them and put them into a map
  key = concatenated value
  value = frequency
 :) 
 declare function local:create-pair-maps() {
     for $i in collection($query-name) 
     return
        local:write-maps(base-uri($i))
 } ;

  declare function local:write-maps($uri) {
   let $document := doc($uri) 
   let $output-document := concat(substring-before(string($uri), '.xml') , '-MAP.xml')
   let $value-map := map:map()
   let $fill-the-map := for $pair in $document//pair 
                          let $thing-1 := $pair/courtname/string()
                            let $thing-2 := $pair/courtcode/string() 
                            let $value := concat($thing-1, '_', $thing-2)
                            return
                                    if ( $value = map:keys($value-map) )
                                   then map:put($value-map , $value ,
                                        (map:get($value-map , $value) + 1) )
                                   else map:put($value-map , $value , 1)
  let $map-container := <container>{$value-map}</container>

  return
    xdmp:document-insert($output-document , $map-container, (), $map-collection ) 

} ;


(: combine maps :)
declare function local:combine-maps() {
   let $maps := for $i in collection($map-collection) return $i
   let $output-document := concat($query-name, '-combined-map.xml')
   let $value-map-2 := map:map()
   let $fill-the-map := for $_m in $maps
                          let $m := map:map($_m/container/map:map)
                            for $key in map:keys($m)
                              return
                                if ($key = map:keys($value-map-2))
                                                                then map:put($value-map-2 , $key ,
                                                            (map:get($value-map-2 , $key) + map:get($m , $key)))
                                                                   else map:put($value-map-2 , $key , map:get($m , $key))
  let $map-container := <container>{$value-map-2}</container>
  return
    xdmp:document-insert($output-document , $map-container, (), $map-collection)
} ;

(: write results to spreadsheet-friendly XML structure :)
declare function local:maps-to-spreadsheet() {
  let $input-document-name := concat($query-name , '-combined-map.xml')
  return
   <results>{
      for $i in doc($input-document-name)/container/map:map/map:entry
        let $thing-2 := substring-before($i/@key/string(), '_')
        let $thing-1 := substring-after($i/@key/string(), '_')
        order by $thing-2
        return
           <pair frequency="{$i/map:value/string()}">
             <thing-1>{$thing-1}</thing-1>
             <thing-2>{$thing-1}</thing-2>
          </pair>
     }
   </results>
};

local:document-set-creator(1, 1) ,
local:create-pair-maps()  ,
local:combine-maps() ,
local:maps-to-spreadsheet() 

1 个答案:

答案 0 :(得分:0)

请考虑将https://docs.marklogic.com/cts:valueshttps://docs.marklogic.com/cts:value-co-occurrences与范围索引一起使用,而不是构建自己的频率计数文档。尝试使用这些功能之一的map选项。这比自己构建类似的功能要快得多,也更可靠。

那就是说,您可能对多语句交易感兴趣:https://docs.marklogic.com/guide/app-dev/transactions - 我写了一篇可能有用的教程:http://blakeley.com/blogofile/2013/06/21/introduction-to-multi-statement-transactions

但是,使用MST可能无法解决内存消耗或超时的原始问题。通过插入这些临时文档,您可能最终会使用更多内存和更多时间,而不是仅仅在功能之间传递map:map项目。

相关问题