XSLT 3.0 流式处理 1000 的小型 XML 文件会提高性能吗?

XSLT 3.0 Will streaming of 1000's small XML files improve performance?

提问人:Binsky 提问时间:3/13/2023 最后编辑:Martin HonnenBinsky 更新时间:3/14/2023 访问量:134

问:

我有一个大约 600K XML 文件的存储库,需要审核所有可能的值,这些文件通常很小,最大文件大小为 80k。<country name="Country_Name">

<country name="Country_Name">保存在文章正文之前靠近顶部的 XML 元数据部分,使用流式处理方法是否会大大提高提取县值的性能,因为一旦 Xpath 发现该元素,流式处理就会停止?

这是正确的方法吗,如果是这样,我正在运行 Saxon 专业版,并且想知道流式传输大量小文档是否需要升级到企业版。

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:mode streamable="yes"/>

  <xsl:template match="/">
    <xsl:for-each-stream select="doc('file:///C:/temp/*.xml')">
      <xsl:value-of select="//country"/>
      <!-- Replace the following with your code to dump the current file -->
      <xsl:message select="concat('Processing ', document-uri(.))"/>
    </xsl:for-each-stream>
  </xsl:template>

</xsl:stylesheet>

预期 打印到屏幕上的每条消息。

萨克森 XSLT-3.0

评论

0赞 Martin Honnen 3/13/2023
您是否在 XSLT 3 规范或任何 Saxon 10、11 或 12 的 Saxon 文档中找到有关流式处理的示例?xsl:for-each-stream select="doc('file:///C:/temp/*.xml')"
0赞 Binsky 3/14/2023
你好马丁,首先道歉,我一直在玩 AI 聊天机器人和 PowerShell 问题,并得到了半个体面的回复,所以我用 XSLT 3 问题来推动我的运气。上面的代码是它的响应。我使用 Saxon 运行了代码,但它失败了,并出现错误 xsl:for-each-stream is not known。但我也收到了警告“SXST0068:流式处理请求被忽略:此撒克逊配置不支持流式处理”,所以这就是我提出问题的原因。作为第一次发帖人,我不得不回答“你以前尝试过什么?”的问题,然后粗心地粘贴在代码中。

答:

0赞 Martin Honnen 3/14/2023 #1

我认为您可以使用例如

<xsl:template name="xsl:initial-template">
  <xsl:for-each select="uri-collection('file:///C:/SomePath/SomeFolder?select=*.xml')">
    <xsl:message expand-text="yes">Processing file {.}</xsl:message>
    <xsl:source-document href="{.}" streamable="yes">
      <xsl:value-of select="descendant::country[@name = 'Country_Name'][1]"/>
    </xsl:source-document>
  </xsl:for-each>
</xsl:template>

要使用流媒体,您需要 Saxon EE;如果要检查/测试该方法的性能是否优于传统的 XSLT 3,则可能需要向 Saxonica 申请试用许可证。

但是,我不确定发布的代码在找到第一个元素后是否停止处理文件;需要测试/检查;我认为撒克逊 EE 有一个 / 提前退出的地方。xsl:iteratexsl:break

按照 https://www.saxonica.com/html/documentation11/streaming/partial-reading.html 的文档,我尝试了以下代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

   <xsl:param name="uri" as="xs:string" expand-text="no">file:///C:/SomePath/SomeFolder?select=*.xml</xsl:param>

   <xsl:param name="items-to-select" as="xs:integer" select="1"/>
     
   <xsl:template name="xsl:initial-template">
      <xsl:for-each select="uri-collection($uri)">
        <xsl:message expand-text="yes">Processing file {.}</xsl:message>
        <xsl:source-document href="{.}" streamable="yes">
          <xsl:iterate select="outermost(descendant::country[@name = 'Country_Name'])">
            <xsl:value-of select="."/>
            <xsl:if test="position() eq $items-to-select">
              <xsl:break/>
            </xsl:if>
          </xsl:iterate>
        </xsl:source-document>
      </xsl:for-each>
   </xsl:template>

   <xsl:output method="text" item-separator="&#10;"/>

</xsl:stylesheet>

它通过了可流性分析,并且还指示提前退出(尽管当我处理三个文件(没有选项)时只有一次;如果我使用该选项并处理三个文件,则确实会退出三次:这是在 11.5 EE 中;我现在还使用 12.0 EE 进行了测试,它为每个处理的文件输出,而无需使用该选项)。-t-tSXQP0001 The input file has not been read to completion-t

因此,这意味着,如果您的文件在所有或大量文档中该元素位于早期,则一旦找到该元素,就应该放弃该解析。

在一些简单的测试中,如果文件足够大,并且要查找的元素在每个文档的早期某个时间点,则通过 Saxon 12.0 EE 运行的流式、提前退出解决方案看起来比未流式处理的解决方案更快。

评论

0赞 Binsky 3/14/2023
感谢 Martin 对我的代码错误的理解,我非常感兴趣的是你对处理改进的分析。我已经联系了 Saxonica 的好人,要求试用 EE 版本。xsl:iterate/xsl:break
0赞 Martin Honnen 3/14/2023
@michaelbinks,请参阅我的编辑,在使用流式处理时,您可以通过解析器的含义获得“提前退出”,如果您解析大量文档,其中可以找到该元素仅解析例如文档的 10%,我希望这在性能测试中显示。但最终您需要自己检查。xsl:iterate/xsl:break
0赞 Martin Honnen 3/15/2023
@michaelbinks,你能够测试这种方法吗?您是否为整套“大约 600K XML 文件”实现了任何明显甚至重要的性能改进?
0赞 Michael Kay 3/14/2023 #2

通常,我建议人们流式处理不会使执行速度更快,其目的是减少内存使用。“提前退出”可能会有所作为,但只有测量才能说明问题。对于低于 100K 的文档,我相信相当多的 XML 解析成本是解析的初始化,因此提前退出可能不会像人们希望的那样节省那么多。

对于这种工作负载,使用 Saxon-EE 的最大收益可能来自输入文档的并行处理。Saxon-EE 下的函数会自动进行并行解析,但将其与流式处理相结合可能需要更多考虑。collection()