高阶函数返回商店

时间:2017-01-30 15:53:16

标签: xquery exist-db

我希望在exists-db(v2.2)中转换并存储~450k xml片段。每15k左右记录转换输出一个无效(但形式良好)的结果。在这个MWE中,第二个人的生日不是1225没有2月29日的有效日期。因为尝试查找并修复这些错误非常耗时我希望在将每个转换函数存储到数据库时验证它们的输出,所以每次我寻找异常值时,我都不必进行完整的验证。我意识到有效片段与有效的最终项目之间的区别,但这只是为了让我免于咖啡过量。

我提出了两种解决方案,它们都能实现所需的输出: 基于样本输入,我期望三个tei:xml片段被验证并存储在db中,对于无效的第二个记录,另外的报告也应该存储在db中。两种情况都会产生输出,但我想了解两者的行为差异。

场景1

我使用local:validate-fragments作为其local:biog作为对象,作为xmldb:store的一部分在最终的return子句中。

xquery version "3.0";

import module namespace xmldb="http://exist-db.org/xquery/xmldb";

 declare namespace tei="http://www.tei-c.org/ns/1.0";
 declare namespace no="http://none";

 declare default element namespace "http://www.tei-c.org/ns/1.0";

 declare function local:biog ($persons as node()*) as item()* {

 for $person in $persons
 return 
     element person {
         attribute ana {'historical'}, 
         attribute xml:id {concat('BIO', $person/text())},
         element persName { $person/../no:c_name/text()},
         element birth {
             attribute when {concat($person/../no:c_birthyear, '-', $person/../no:c_by_month, '-', $person/../no:c_by_day)}
            }
        }
};

 declare function local:validate-fragment($frag as node()*, $loc as xs:string?) as item()* {

 let $id := data($frag/@xml:id)

 let $mini := 
 <TEI xmlns="http://www.tei-c.org/ns/1.0">
  <teiHeader>
      <fileDesc>
         <titleStmt>
            <title>TEI-mini</title>
         </titleStmt>
         <publicationStmt>
            <p>testing ouput of individual functions using this mini tei document </p>
         </publicationStmt>
         <sourceDesc>
            <p>cannot replace proper validation of final output</p>
         </sourceDesc>
      </fileDesc>      
  </teiHeader>
  <text>
      <body>       
         {
         switch ($loc)
         case 'person' return <listPerson ana="chunk"><listPerson ana="block">{$frag}</listPerson></listPerson>
         case 'org' return <listOrg>{$frag}</listOrg>
         case 'place' return <listPlace>{$frag}</listPlace>
         case 'bibl' return <listBibl>{$frag}</listBibl>
         default return (<p>some text here {data($frag)}</p>)
         }         
      </body>
  </text>
 </TEI>

 return 
    if (validation:jing($mini, doc('../templates/tei/tei_all.rng')) = true())
    then ($frag)
    else (($frag, 
      xmldb:store('../reports/',  concat('report-',$id,'.xml'),
      validation:jing-report($mini, doc('../templates/tei/tei_all.rng')))))
};

let $data :=
<root xmlns="http://none">
    <row>
        <c_personid>12907</c_personid>
        <c_name>Huang Zhong</c_name>        
        <c_birthyear>1226</c_birthyear>        
        <c_by_month>08</c_by_month>
        <c_by_day>26</c_by_day>        
    </row>
    <row>
        <c_personid>12908</c_personid>
        <c_name>Fang Yifu</c_name>        
        <c_birthyear>1225</c_birthyear>        
        <c_by_month>02</c_by_month>
        <c_by_day>29</c_by_day>        
    </row>
    <row>
        <c_personid>12909</c_personid>
        <c_name>Fang Linsun</c_name>        
        <c_birthyear>1215</c_birthyear>        
        <c_by_month>11</c_by_month>
        <c_by_day>06</c_by_day>
    </row>    
 </root>

 for $n in $data//no:c_personid[. > 12906][. < 12910]
 return
 xmldb:store('../samples/', concat('cbdb-', data($n), '.xml'),
 local:validate-fragment(local:biog($n), 'person')[1])

这是两种方法中较快的一种(在500条记录上测试)。在现有日志中,这似乎执行一次写操作。

登录

2017-01-31 13:08:55,263 [eXistThread-40] INFO  (RpcConnection.java [doQuery]:335) - query took 350ms. 
2017-01-31 13:08:55,263 [eXistThread-40] DEBUG (RpcConnection.java [queryP]:2854) - found 3 
2017-01-31 13:08:55,548 [eXistThread-39] DEBUG (RpcConnection.java [releaseQueryResult]:3053) - removed query result with handle 1 

所以我的问题是为什么上面的版本在db中的同一文档中不断写入和删除?是否有更好的方式来$frag而不是使用俗气的[1]?如果没有此谓词,则整个写入操作在达到<row>时会停止,并且需要同时写入tei.xml数据文件和错误报告。在优势方面,场景1立即向系统写入(并删除)。不像...

场景2

从变换内部调用验证函数,如下所示:

declare function local:biog ($persons as node()*) as item()* {

 for $person in $persons
 return 
    local:validate-fragment(element person {
        attribute ana {'historical'}, 
         attribute xml:id {concat('BIO', $person/text())},
        element persName { $person/../no:c_name/text()},
        element birth {
            attribute when {concat($person/../no:c_birthyear, '-', $person/../no:c_by_month, '-', $person/../no:c_by_day)}
            }
        }, 'person')

};

......并采用这样的最终条款:

for $n in $data//no:c_personid[. > 12906][. < 12910]
 return
 xmldb:store('../samples/', concat('cbdb-', data($n), '.xml'),
 local:biog($n)[1])

这会使用多个write和delete语句污染日志,但在处理完所有片段之前似乎没有推迟写入操作。

登录

2017-01-31 12:59:26,473 [eXistThread-39] INFO  (NativeBroker.java [removeXMLResource]:2641) - Removing document cbdb-12907.xml (752715) ... 
2017-01-31 12:59:26,808 [eXistThread-39] INFO  (NativeBroker.java [removeXMLResource]:2641) - Removing document report-BIO12908.xml (752714) ... 
2017-01-31 12:59:26,814 [eXistThread-39] INFO  (NativeBroker.java [removeXMLResource]:2641) - Removing document cbdb-12908.xml (752720) ... 
2017-01-31 12:59:27,048 [eXistThread-39] INFO  (NativeBroker.java [removeXMLResource]:2641) - Removing document report-BIO12909.xml (752743) ... 
2017-01-31 12:59:27,053 [eXistThread-39] INFO  (NativeBroker.java [removeXMLResource]:2641) - Removing document cbdb-12909.xml (752721) ... 
2017-01-31 12:59:27,056 [eXistThread-39] INFO  (RpcConnection.java [doQuery]:335) - query took 755ms. 
2017-01-31 12:59:27,056 [eXistThread-39] DEBUG (RpcConnection.java [queryP]:2854) - found 3 

这适用于小块,但我担心这会在应用于整个数据集时成为问题。

最重要的是,我不明白在两种情况下如何处理xmldb:store。

是否有更智能的方法来使用xQueries更高级的功能或实现我想要的结果?

0 个答案:

没有答案