【问题标题】:How to speed up XQuery string search?如何加快 XQuery 字符串搜索?
【发布时间】:2020-09-07 12:00:27
【问题描述】:

我正在使用 XQuery/BaseX 查看大型 XML 文件以查找某些计数器的历史数据。所有文件都被压缩并存储在驱动器的某个位置。文件的重要部分如下所示:

<measInfo xmlns="http://www.hehe.org/foo/" measInfoId="uplink speed">
  <granPeriod duration="DS222S" endTime="2020-09-03T08:15:00+02:00"/>
  <repPeriod duration="DS222S"/>
  <measTypes>AFD123 AFD124 AFD125 AFD156</measTypes>
  <measValue measObjLdn="PLDS-PLDS/STBHG-532632">
    <measResults>23 42 12 43</measResults>
  </measValue>
</measInfo>

我构建了以下查询:

declare default element namespace "http://www.hehe.org/foo/";
let $sought := ["AFD124", "AFD125"]
let $datasource := collection("C:\Users\Patryk\Desktop\folderwitharchives")
let $filename := concat(convert:dateTime-to-integer(current-dateTime()), ".xml")

for $meas in $datasource/measCollecFile/measData/measInfo return 
  for $measType at $i in $meas/tokenize(measTypes)[. = $sought] return
    file:append($filename,
      <meas
        measInfoId="{data($meas/@measInfoId)}"
        measObjLdn="{data($meas/measValue/@measObjLdn)}"
      >
      
        {$meas/granPeriod}
        {$meas/repPeriod}
        <measType>{$measType}</measType>
        <measValue>{$meas/measValue/tokenize(measResults, " ")[$i]}</measValue>
      </meas>)

脚本有效,但某些计数器 (measType) 需要很长时间。我阅读了有关索引的文档,我的想法是以某种方式索引所有 measTypes(字符串的一部分),这样一旦我需要查看整个存档以查找计数器,就可以快速访问它。我不确定直接对档案进行操作时是否可以?我必须为它们创建一个新数据库吗?由于文件的大小,我不希望这样做。如何为这种情况创建索引?

【问题讨论】:

  • 我认为您不能索引tokenize 调用的结果。简单地使用序列let $sought := (AFD124", "AFD125") 而不是let $sought := ["AFD124", "AFD125"] 中的数组可能会产生一个小的改进,因为这样. = $sought 不必在每次比较完成时展平数组。不过,我还没有测试过它是否表现更好。

标签: xpath indexing xquery basex


【解决方案1】:

这不是我问题的答案,但我注意到当我将 XML 节点写入文件时执行时间要长得多。将任何其他字符串附加到文件中要快得多:

concat($measInfo/@measInfoId, ",", $measInfo/measValue/@measObjLdn, ",", 
$measInfo/granPeriod, ",", $measInfo/repPeriod, ",", $measType, ",", 
$tokenizedValues[$i], "&#10;"))

为什么会这样以及如何加快将 XML 节点写入文件的速度?

另外,我注意到在 for 循环中向文件附加值要长得多,我怀疑这是因为必须在每次迭代中再次打开文件。有没有办法在整个查询过程中保持文件打开?

【讨论】:

  • 您真的要创建一个包含多个顶级 XML 元素的文件吗?这就是您的原始代码似乎要做的事情。使用例如创建具有根的单个文件可能更有意义。 file:write(&lt;root&gt;{for $meas in $datasource/measCollecFile/measData/measInfo return for $measType at $i in $meas/tokenize(measTypes)[. = $sought] return &lt;meas measInfoId="{data($meas/@measInfoId)}" measObjLdn="{data($meas/measValue/@measObjLdn)}"&gt;... &lt;/meas&gt;}&lt;/root&gt;.
  • @MartinHonnen 我想您可以将其发布为答案。
  • 顺便说一句,为了可读性,我宁愿先创建一个数据结构,然后写它:let $resultDoc := &lt;root&gt;{ for ... for ... return &lt;meas ...&gt; ... &lt;/meas&gt; } &lt;/root&gt; let $result := file:write( $resultDoc),但这只是习惯问题。
  • @MartinHonnen 然后我的主内存用完了。我需要在 for 循环中使用 file:append。如果您能建议我如何在追加时创建根,我会很高兴。
  • 好吧,对于 Java 应用程序,您可以先调整内存设置,除非您真的已经为 BaseX 占用了系统的大部分内存。否则我猜你需要考虑将数据存储在 BaseX 数据库中,而不是直接存储在文件系统中。
猜你喜欢
  • 2013-01-20
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 2011-03-01
  • 1970-01-01
  • 2020-04-09
  • 2021-12-27
相关资源
最近更新 更多