处理大型 MRM 消息

当解析输入位流和创建的逻辑树时,MRM 消息的树表示通常比较大,在有些情况下比相应的位流大的多。其原因包含:
  • 将对象链接到一起的指针增加。
  • 将字符数据转换为 Unicode 格式可能是原始大小的两倍
  • 包含了可能在位流中隐含的字段名
  • 存在与代理的操作相关联的控制数据

因此,对大型消息树进行操作可能会需要大量存储。如果您设计一个消息流,处理由重复结构组成的大型消息,则可以编码特定的 ESQL 语句,帮助减少代理上的存储负载。这些语句同时支持对消息的随机和有序访问,但前提是您不需要一次访问整个消息。

这些 ESQL 语句使代理对消息执行有限的解析,并且仅保存消息树中某一部分,该部分每次反映存储器内的一个记录。如果处理操作要求您按记录逐一保留信息(例如,计算订单中各项的重复结构的总价格),您既可以声明、初始化、保留 ESQL 变量,也可以将值保存在消息树的其他部分,如 LocalEnvironment。

此技术将把代理使用的内存减少到保存完整输入和输出位流,加上用于单条记录的树所需的大小。甚至是在消息中遇到少量重复时,它也能节省内存。代理使用部分解析和将指定部分的消息树解析为相应部分的位流,或从部分位流解析为部分消息树的能力。

要在 Compute 节点上使用这些技术,请应用以下一般技术:
  • 将输入消息的主体作为位流复制到输出消息中的某个特定文件夹中。这会为没有解析的输入消息创建可修改的副本,因此耗用的内存量最少。
  • 避免对输入消息进行任何检查;这将避免对解析消息的需要。
  • 使用循环和引用变量单歩遍历消息,一次遍历一条记录。对于每个记录:
    • 使用常规转换在第二个特定文件夹中构建对应的输出子树。
    • 使用 ASBITSTREAM 函数为存储在 BitStream 元素中的输出子树生成位流,该元素放置在树中与在最终位流中要求它所在的位置相对应的位置处。
    • 完成当前输入和输出记录消息树的操作时,使用 DELETE 语句删除它们。
    • 完成处理所有的记录后,拆离特殊的文件夹,这样它们就不会在输出位流中出现了。

您可以变化使用这些技术来适应消息所需的处理。下面的 ESQL 提供了一个实施的示例,它重写了处理大型 XML 消息中的 ESQL 示例,该示例使用具有嵌套 SELECT 函数的单个 SET 语句转换了包含嵌套重复结构的消息。

该 ESQL 从属于称为 LargeMessageExanple 的消息集,已创建该消息集,定义 Invoice 输入格式和 Statement 输出格式的消息。已创建称为 AllInvoices 的消息,该消息包含一个称为 Invoice 的全局元素(可以重复一次或多次)和一条称为 Data 的消息,它包含一个称为 Statement 的全局元素,可以重复一次或多次。

这些元素和属性的定义已经被赋予正确的数据类型,因此,不再需要 XML 示例中 ESQL 使用的 CAST 语句。在消息集中已创建了称为 XML1 的 XML 物理格式,这使您能够使用 MRM 解析与这些消息相应的 XML 消息。

当使用 ASBITSTREAM 函数序列化 Statement 树时,Message SetMessage TypeMessage Format 将被指定为参数。Message Type 参数包含从消息到被序列化元素的路径,在本例中,该路径为 Data/Statement,因为 Statement 元素时 Data 消息的直接子代。

除被包含在标记之间以外,流的输入消息是在其他部分文档中使用的同一个 Invoice 示例消息:
       <AllInvoices> .... </AllInvoices>  

输出消息与处理大型 XML 消息中的输出消息相同。

CREATE COMPUTE MODULE LargeMessageExampleFlow_Compute
   CREATE FUNCTION Main() RETURNS BOOLEAN
	BEGIN
CALL CopyMessageHeaders();
  -- Create a special folder in the output message to hold the input tree
  -- Note : SourceMessageTree is the root element of an MRM parser
  CREATE LASTCHILD OF OutputRoot.MRM DOMAIN 'MRM' NAME 'SourceMessageTree';

  -- Copy the input message to a special folder in the output message
  -- Note : This is a root to root copy which will therefore not build trees
  SET OutputRoot.MRM.SourceMessageTree = InputRoot.MRM;

  -- Create a special folder in the output message to hold the output tree
  CREATE FIELD OutputRoot.MRM.TargetMessageTree;

  -- Prepare to loop through the purchased items
  DECLARE sourceCursor REFERENCE TO OutputRoot.MRM.SourceMessageTree.Invoice;
  DECLARE targetCursor REFERENCE TO OutputRoot.MRM.TargetMessageTree;
  DECLARE resultCursor REFERENCE TO OutputRoot.MRM;
  DECLARE grandTotal FLOAT 0.0e0;

  -- Create a block so that it's easy to abandon processing
  ProcessInvoice: BEGIN
    -- If there are no Invoices in the input message, there is nothing to do
    IF NOT LASTMOVE(sourceCursor) THEN
      LEAVE ProcessInvoice;
    END IF;

    -- Loop through the invoices in the source tree
    InvoiceLoop : LOOP
      -- Inspect the current invoice and create a matching Statement
      SET targetCursor.Statement =
        		THE ( 
          			SELECT
            'Monthly' AS Type,
            'Full' AS Style,
            I.Customer.FirstName AS Customer.Name,
            I.Customer.LastName AS Customer.Surname,
            I.Customer.Title AS Customer.Title,
            			(SELECT 
              FIELDVALUE(II.Title) AS Title,
              II.UnitPrice * 1.6 AS Cost,
                         II.Quantity                     AS Qty
                         FROM I.Purchases.Item[] AS II
                         WHERE  II.UnitPrice > 0.0              )        AS Purchases.Article[],
            			(SELECT
              SUM( II.UnitPrice *
                   			     II.Quantity  *
                   				 1.6                          )
                         FROM I.Purchases.Item[] AS II      )                AS Amount,
            'Dollars' AS Amount.Currency
          FROM sourceCursor AS I
          WHERE I.Customer.LastName <> 'White'
       				 );

      -- Turn the current Statement into a bit stream
      -- The SET parameter is set to the name of the message set
         -- containing the MRM definition
      -- The TYPE parameter contains the path from the from the message
         -- to element being serialized
      -- The FORMAT parameter contains the name of the physical format
         -- name defined in the message
      DECLARE StatementBitStream BLOB        CAST(ASBITSTREAM(targetCursor.Statement
        			OPTIONS FolderBitStream
        			SET 'LargeMessageExample'
        			TYPE 'Data/Statement'
        FORMAT 'XML1') AS BLOB);
                
      -- If the SELECT produced a result (that is, it was not filtered
         -- out by the WHERE clause), process the Statement
      IF StatementBitStream IS NOT NULL THEN
        -- create a field to hold the bit stream in the result tree
        -- The Type of the element is set to MRM.BitStream to indicate
           -- to the MRM Parser that this is a bitstream
        CREATE LASTCHILD OF resultCursor
          			Type  MRM.BitStream
          			NAME  'Statement'
          VALUE StatementBitStream;

        -- Add the current Statement's Amount to the grand total
        SET grandTotal = grandTotal + targetCursor.Statement.Amount;
      END IF;

      -- Delete the real Statement tree leaving only the bit stream version
      DELETE FIELD targetCursor.Statement;

      -- Step onto the next Invoice, removing the previous invoice and any
      -- text elements that might have been interspersed with the Invoices
      		REPEAT
        MOVE sourceCursor NEXTSIBLING;
        DELETE PREVIOUSSIBLING OF sourceCursor;
      UNTIL (FIELDNAME(sourceCursor) = 'Invoice') OR (LASTMOVE(sourceCursor) = FALSE)
  END REPEAT;

      -- If there are no more invoices to process, abandon the loop
      IF NOT LASTMOVE(sourceCursor) THEN
        LEAVE InvoiceLoop;
      END IF;

    END LOOP InvoiceLoop;
  END ProcessInvoice;

  -- Remove the temporary source and target folders
  DELETE FIELD OutputRoot.MRM.SourceMessageTree;
  DELETE FIELD OutputRoot.MRM.TargetMessageTree;

  -- Finally add the grand total
  SET resultCursor.GrandTotal = grandTotal;  		
  -- Set the output MessageType property to be 'Data'
  SET OutputRoot.Properties.MessageType = 'Data';
 
RETURN TRUE;
	END;

       CREATE PROCEDURE CopyMessageHeaders() BEGIN
              DECLARE I INTEGER 1;
              DECLARE J INTEGER CARDINALITY(InputRoot.*[]);
                         WHILE I < J DO
                                 SET OutputRoot.*[I] = InputRoot.*[I];
SET I = I + 1;
END WHILE;
	END;

END MODULE;
相关概念
消息流概述
ESQL 概述
消息建模
相关任务
设计消息流
定义消息流内容
管理 ESQL 文件
开发消息模型
处理大型 XML 消息
相关参考
Compute 节点
Database 节点
Filter 节点
ASBITSTREAM 函数
CREATE 语句
SET 语句
声明 | 商标 | 下载 | 书库 | 支持 | 反馈
Copyright IBM Corporation 1999, 2006 最后一次更新时间:2006/08/14
ac20702_