XSLT 流在 if 条件下太慢

XSLT streaming is too slow with if conditions

我们正在使用 saxon-ee 流处理大文件。在这种情况下,文件大小约为 1gb。转换正在执行订单查找数据并过滤匹配 order_id.

改造大约需要1.5小时。当我使用 lookup/filtering.

如果我注释掉查找和检查,只需 2 分钟即可转换完整文件。

我使用查找和 if 条件的方式似乎有问题。请提供一些建议来解决此性能问题。 示例输入 XML

<?xml version="1.0" encoding="UTF-8"?>
<orders>
   <order>
      <guid>3079866431</guid>
      <name>name1</name>
   </order>
   <order>
      <guid>3079866431</guid>
      <name>name2</name>
   </order>
   <order>
      <guid>2583715475</guid>
      <name>name3</name>
   </order>
</orders>

lookup.xml 文件内容

<?xml version="1.0"?><IndexControl><entry id="2521202370" status="true"/><entry id="2583715475" status="true"/></IndexControl>

具有查找功能的 XSLT 模板需要 1.5 小时

<?xml version="1.0"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:mode streamable="yes"/>    
    <xsl:variable name="IndexLookup" select="document('https://test.com/lookup.xml')/IndexControl"/>
    <xsl:template match="orders">
        <xsl:element name="Batch">            
            <xsl:for-each select="order ! copy-of(.)">              
                 <xsl:variable name="order_id" select="guid"/>
              <xsl:if test="$IndexLookup/entry[@id=$order_id]/@status = 'true'">
                <xsl:element name="Order">
                    <xsl:element name="Field">
                        <xsl:attribute name="name">id</xsl:attribute>
                        <xsl:attribute name="value">
                            <xsl:value-of select="guid"/>
                        </xsl:attribute>
                    </xsl:element>
                    <xsl:element name="Field">
                        <xsl:attribute name="name">name</xsl:attribute>
                        <xsl:attribute name="value">
                            <xsl:value-of select="name"/>
                        </xsl:attribute>
                    </xsl:element>                  
                </xsl:element>               
                </xsl:if>
            </xsl:for-each>           
        </xsl:element>       
    </xsl:template>
</xsl:stylesheet>

没有查找的 XSLT 需要 2 分钟

<?xml version="1.0"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:mode streamable="yes"/>    
    <!-- <xsl:variable name="IndexLookup" select="document('https://test.com/lookup.xml')/IndexControl"/> -->
    <xsl:template match="orders">
        <xsl:element name="Batch">            
            <xsl:for-each select="order ! copy-of(.)">               
                <xsl:variable name="order_id" select="guid"/>
              <!-- <xsl:if test="$IndexLookup/entry[@id=$order_id]/@status = 'true'"> -->
                <xsl:element name="Order">
                    <xsl:element name="Field">
                        <xsl:attribute name="name">id</xsl:attribute>
                        <xsl:attribute name="value">
                            <xsl:value-of select="guid"/>
                        </xsl:attribute>
                    </xsl:element>
                    <xsl:element name="Field">
                        <xsl:attribute name="name">name</xsl:attribute>
                        <xsl:attribute name="value">
                            <xsl:value-of select="name"/>
                        </xsl:attribute>
                    </xsl:element>                  
                </xsl:element>               
               <!--  </xsl:if> -->
            </xsl:for-each>           
        </xsl:element>       
    </xsl:template>
</xsl:stylesheet>

声明一个键<xsl:key name="lookup" match="IndexControl/entry" use="@id"/>然后使用<xsl:for-each select="order ! copy-of(.)[key('lookup', guid, doc('https://test.com/lookup.xml'))/@status = 'true']">

我原以为 Saxon-EE 优化器会为查找表达式生成一个索引,如果有机会我会调查为什么这没有发生。但可以肯定的是,按照 Martin Honnen 的建议使用显式密钥应该可以解决这个问题。

对于流式传输大文件,我通常认为每 GB 大约 1 分钟是一个合理的目标,但这显然取决于您所做的工作和您使用的机器 运行。

顺便说一句,它不会影响性能,但我确实发现这种代码非常不可读:

 <xsl:element name="Field">
      <xsl:attribute name="name">name</xsl:attribute>
      <xsl:attribute name="value">
           <xsl:value-of select="name"/>
      </xsl:attribute>
 </xsl:element>

什么时候可以改写:

<Field name="name" value="{name}"/>