2010-02-20 20 views
8

Ho un framework che genera l'XML, in base alla richiesta HTTP e allo stato corrente della sessione. Posso testare in HTML, ma l'output di produzione sarà VXML, forse uno o due "sapori" per ragioni diverse.Voglio migliorare le prestazioni di xslt

Ecco la parte lenta della mia HttpServlet:

jsp InputStream ms = new java.io.ByteArrayInputStream(sb.toString().getBytes()); 
Source xmlSource = new javax.xml.transform.stream.StreamSource(ms); 
String filePath = getServletContext().getRealPath(("/GetNextEvent-"). 
     concat(req.getSession().getAttribute("client").toString().toUpperCase()).concat(".xsl")); 
Source xsltSource = new javax.xml.transform.stream.StreamSource(filePath); 
Result result = new javax.xml.transform.stream.StreamResult(resp.getWriter()); 
TransformerFactory tf = TransformerFactory.newInstance(); 
Transformer t = tf.newTransformer(xsltSource); 
t.transform(xmlSource, result); 

prende questo momento ~ 200 ms. Mi piacerebbe che fosse molto più veloce. Forse < 10 ms?

  1. Suggerimenti per la memorizzazione nella cache? - visto che i file xsl rimangono uguali per tutta la distribuzione, gli oggetti Transformer possono essere memorizzati nella cache a tempo indeterminato. Sto pensando di metterlo in cache nel livello Session, quindi ogni sessione (1000 in simultanea) ha il suo. Eventuali suggerimenti? Dovrei usare qualsiasi framework per il caching, per qualsiasi motivo?
  2. C'è un modo più veloce per trasformare l'xml nel flusso di risposta?
  3. Devo rottamare questo e andare un altro percorso? Se hai notato sb.toString, sto usando un StringBuilder per ottenere la rappresentazione XML degli oggetti (gli oggetti usano un costruttore di stringhe per creare una stringa XML). Ci vuole circa 1 millesimo di secondo per creare il documento XML usando StringBuilders, quindi non sono preoccupato al momento.

Edit:

Ecco il documento XSL. Il documento XML è in genere molto piccolo. Solo un paio di elementi. XML di esempio è sotto XSL:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:regexp="http://exslt.org/regular-expressions" 
    xmlns:str="http://exslt.org/strings" xmlns:twc="http://twc.com/2009/01/ivr/framework" 
    exclude-result-prefixes="twc regexp str" extension-element-prefixes="str"> 
    <xsl:output method="xml" encoding="ISO-8859-1" /> 
    <xsl:template match="/"> 
     <vxml xmlns="http://www.w3.org/2001/vxml" version="2.1" xml:lang="en-US" 
      application="root.xml"> 
      <xsl:attribute name="xml:lang"><xsl:value-of 
       select="//twc:response/@language" /></xsl:attribute> 
      <form id="ivrFramework"> 
       <var name="logDebug"> 
        <xsl:attribute name="expr"><xsl:value-of 
         select="//twc:response/@debug" /></xsl:attribute> 
       </var> 
       <var name="event" expr="'OK'" /> 
       <var name="lastResult" expr="''" /> 
       <var name="lastResultMode" expr="''" /> 
       <var name="lastResultValue" expr="''" /> 
       <var name="srConfidence" expr="'1000'" /> 

       <xsl:apply-templates select="//twc:command" /> 
       <xsl:if test="count(//twc:command)=0"> 
        <block> 
         <log cond="logDebug" expr="'No more commands. Exiting.'" /> 
         <exit /> 
        </block> 
       </xsl:if> 
      </form> 
     </vxml> 
    </xsl:template> 

    <xsl:template 
     match="twc:command[@type='prompt' and contains(text(), 'TransferDialog')]"> 
     <transfer name="quicktransfer" type="consultation"> 
      <xsl:attribute name="destexpr"><xsl:choose> 
       <xsl:when test="//twc:parameter[twc:name='destination']">'<xsl:value-of 
       select="//twc:parameter[twc:name='destination']/twc:value" />'</xsl:when> 
       <xsl:otherwise>'tel:1136300'</xsl:otherwise> 
      </xsl:choose> 
      </xsl:attribute> 
      <xsl:if test="//twc:parameter[twc:name='initial']"> 
       <prompt> 
        <xsl:call-template name="process_prompt"> 
         <xsl:with-param name="prompt_type" select="'initial'" /> 
        </xsl:call-template> 
       </prompt> 
      </xsl:if> 
     </transfer> 
    </xsl:template> 

    <xsl:template 
     match="twc:command[@type='prompt' and contains(text(), 'BasicDialog')]"> 
     <xsl:choose> 
      <xsl:when test="//twc:parameter[twc:name='grammar']/twc:value"> 
       <field> 
        <xsl:attribute name="name"><xsl:value-of 
         select="//twc:parameter[twc:name='variable']/twc:value" /></xsl:attribute> 
        <noinput count="3"> 
         <assign name="event" expr="'noinput'" /> 
         <submit next="GetNextEvent2.jsp" 
          namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
        </noinput> 
        <nomatch count="3"> 
         <assign name="event" expr="'invalid'" /> 
         <submit next="GetNextEvent2.jsp" 
          namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
        </nomatch> 

        <xsl:for-each select="//twc:parameter[twc:name='grammar']/twc:value"> 
         <grammar> 
          <xsl:attribute name="src"><xsl:if test="//twc:response/@base!=''"><xsl:value-of select="//twc:response/@base" /></xsl:if><xsl:value-of 
           select="." /></xsl:attribute> 
         </grammar> 
        </xsl:for-each> 
        <xsl:if test="//twc:parameter[twc:name='help']"> 
         <help> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'help'" /> 
          </xsl:call-template> 
         </help> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='noinput1']"> 
         <noinput count="1"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'noinput1'" /> 
          </xsl:call-template> 
         </noinput> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='noinput2']"> 
         <noinput count="2"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'noinput2'" /> 
          </xsl:call-template> 
         </noinput> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='invalid1']"> 
         <nomatch count="1"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'invalid1'" /> 
          </xsl:call-template> 
         </nomatch> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='invalid2']"> 
         <nomatch count="2"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'invalid2'" /> 
          </xsl:call-template> 
         </nomatch> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='initial']"> 
         <prompt> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'initial'" /> 
          </xsl:call-template> 
         </prompt> 
        </xsl:if> 
        <filled> 
         <log cond="logDebug" expr="'Filled.'" /> 
         <assign name="event" expr="'OK'" /> 
         <assign name="lastResult" expr="application.lastresult$.utterance" /> 
         <assign name="lastResultMode" expr="application.lastresult$.inputmode" /> 
         <assign name="lastResultValue" expr="application.lastresult$.interpretation" /> 
         <assign name="srConfidence" expr="application.lastresult$.confidence " /> 
         <submit next="GetNextEvent2.jsp" 
          namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
        </filled> 

       </field> 
      </xsl:when> 
      <xsl:when test="//twc:parameter[twc:name='initial']/twc:value"> 
       <block> 
        <xsl:if test="//twc:parameter[twc:name='initial']"> 
         <prompt> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'initial'" /> 
          </xsl:call-template> 
         </prompt> 
        </xsl:if> 
        <submit next="GetNextEvent2.jsp" 
         namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
       </block> 
      </xsl:when> 
      <xsl:otherwise> 
       <block> 
        <log cond="logDebug" expr="'Didn't find values for grammar or initial. Exiting.'" /> 
        <exit /> 
       </block> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template name="process_prompt"> 
     <xsl:param name="prompt_type" /> 
     <xsl:for-each select="//twc:parameter[twc:name=$prompt_type]/twc:value"> 
      <xsl:if test="contains(., '::')"> 
       <audio> 
        <xsl:for-each select="str:split(., '::')"> 
         <xsl:if test="position()=1"> 
          <xsl:attribute name="src"><xsl:if test="//twc:response/@base!=''"><xsl:value-of select="//twc:response/@base" /></xsl:if><xsl:value-of 
           select="." /></xsl:attribute> 
         </xsl:if> 
         <xsl:if test="position()=2"> 
          <xsl:value-of select="." /> 
         </xsl:if> 
        </xsl:for-each> 
       </audio> 
      </xsl:if> 
      <xsl:if test="contains(., 'Date:')"> 
       <say-as interpret-as="date" format="ymd"> 
        <xsl:for-each select="str:split(., ':')"> 
         <xsl:if test="position()=2"> 
          <xsl:value-of select="." /> 
         </xsl:if> 
        </xsl:for-each> 
       </say-as> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Ecco alcuni XML:

<?xml version="1.0"?> 
<response xmlns="http://twc.com/2009/01/ivr/framework" language="en-us" debug="true" 
    base="/IVRFrameworkResources/Outage/"> 
    <command type="prompt"> BasicDialog <parameter> 
      <name>initial</name> 
      <value>en-us/prompts/OutageCleared.wav::Hello. I'm letting you know the 
       incident that caused your outage has been fixed. </value> 
     </parameter> 
    </command> 
</response> 
+0

Puoi mostrarci il tuo XSLT con un documento di input di esempio? È possibile che il tuo XSLT contenga query inefficienti che possono essere ottimizzate (le query inefficienti possono essere create in quasi tutti i linguaggi di query btw, quindi accusare XLST di essere lento non è generalmente corretto). –

+0

Aggiungerò XSLT, ma forse può essere un'altra domanda :) – ericp

+1

Puoi mostrare anche il documento * input *? Questo è più importante dell'output. –

risposta

12

È difficile diagnosticare problemi di prestazioni senza vedere l'XSLT o sapere quanto sono grandi/complessi XML e XSLT.

Si potrebbe pagare il costo di analisi del file, dell'XSLT o dell'XML e/o si potrebbe avere un foglio di stile XSLT molto inefficiente.

Per esempio:

  1. sacco di // istruzioni XPath, che, se non necessario, può compromettere le prestazioni per grandi file XML.
  2. Logica interrata all'interno dei modelli che potrebbe essere spostata nei criteri modello @match, che offre l'opportunità di ottimizzare i motori XSLT.

Ci sono profilatori XSLT che è possibile utilizzare per vedere dove sono i colli di bottiglia nel proprio XSLT. Per esempio, oXygen ha un bel debugger/profiler: alt text alt text

Se si eseguirà i XSLT molte volte, allora si dovrebbe cache the transformer object.In questo modo, si paga solo il costo per caricare e istanziare una volta e riutilizzare molte volte.

Per esempio, spostare l'istanza del vostro oggetto XSLT Template nella vostra severlet init()

TransformerFactory transFact = TransformerFactory.newInstance(); 
Templates cachedXSLT = transFact.newTemplates(xsltSource); 

e poi dove si esegue la trasformazione, utilizzare la cache TransformerFactory obj:

Transformer t= cachedXSLT.newTransformer(); 
t.transform(xmlSource, result); 
+3

+1 per usare i modelli. Se si utilizza Xalan come trasformatore XSLT, provare a utilizzare la versione XSLTC che compila i fogli di stile ed è molto più veloce. Vedi http://xml.apache.org/xalan-j/xsltc_usage.html#api Se si utilizza Xalan, controllerei il DOM utilizzato, in alcuni casi TinyTree presenta alcuni importanti vantaggi rispetto al normale DOM Java (i risultati potrebbero variare, ma l'utilizzo della memoria è molto meglio per TinyTree). –

-1

ho incontrato qualche strumento che converte file XSLT nel codice di analisi Java, ma non riesce a trovare alcun riferimento al momento. Scusa per una risposta incompleta, ma sono interessante anche a trovarla.

+0

Questo strumento è Saxon e Michael Kay ha appena chiesto la lista di aiuto di saxon se qualcuno ne avesse avuto bisogno, in modo da sapere se continuare a mantenerlo. Pubblica la tua risposta lì. –

5

Anche con il caching, la ragione per le prestazioni inaccettabili è spesso nel codice XSLT stesso - che non hai mostrato affatto.

Nella mia esperienza ci sono stati casi in cui sono stato in grado di modificare un'implementazione XSLT inefficiente in modo che fosse accelerata migliaia di volte.

Molto spesso l'autore implementa un algoritmo O (N^2) o peggio, quando esistono algoritmi O (N) o anche O (log (N)).

Specificare il problema da risolvere e fornire il codice XSLT che lo risolve. Quindi potrebbe essere possibile che qualcuno ti dia una soluzione migliore dal punto di vista operativo.

Problemi correlati