C# USQL-如何选择USQL中两个字符串行之间的所有行

C# USQL-如何选择USQL中两个字符串行之间的所有行,c#,azure-sql-database,azure-data-lake,u-sql,C#,Azure Sql Database,Azure Data Lake,U Sql,以下是我的完整任务描述: 我必须使用u-sql从多个文件中提取数据,并将其输出到csv文件中。每个输入文件都包含基于某些字符串行的多个报告(“开始…”和“结束…”用作报告分隔符)。以下是单个源(输入)文件的示例(数据格式): 所以现在我的问题是如何获取所有文件的“开始…”和“结束…”行之间的记录 我希望在结尾有这样的内容: @dailyAccountResult = [select all rows between "START OF DAILY ACCOUNT" and "END OF DAI

以下是我的完整任务描述:

我必须使用u-sql从多个文件中提取数据,并将其输出到csv文件中。每个输入文件都包含基于某些字符串行的多个报告(“开始…”和“结束…”用作报告分隔符)。以下是单个源(输入)文件的示例(数据格式):

所以现在我的问题是如何获取所有文件的“开始…”和“结束…”行之间的记录

我希望在结尾有这样的内容:

@dailyAccountResult = [select all rows between "START OF DAILY ACCOUNT" and "END OF DAILY ACCOUNT" rows]

@ledgerBalanceResult = [select all rows between "START OF LEDGER BALANCE" and "END OF LEDGER BALANCE" rows]

@dailySummaryReportResult = [select all rows between "START OF DAILY SUMMARY REPORT" and "END OF DAILY SUMMARY REPORT" rows]

我需要为此编写自定义提取器吗?如果是,请建议我如何操作。

我认为使用普通U-SQL而不使用自定义提取器是可能的。我根据您的建议创建了一个简单的示例:


试试看,让我知道你进展如何。

要问的相关问题:

  • 在分布式处理系统中,所有输入数据(可能是TBs)是否都将由1提取器实例处理?
    • 绝对不是!有关确认信息,请参阅摘录文档(msdn.microsoft.com/en-us/library/azure mt621320.aspx)
  • 给定多个提取器实例,在哪里可以分割数据?换句话说,一般来说,是什么决定了U-Sql中数据的原子性单位?特别是对你的情况,你有什么保证,整个开始…结束序列将被处理的一个实例,而不是在中间分裂?
    • 建议数据原子性的通用单位是“行”(行结构文件),这是数据上传本身的属性
    • 根据,
      [SqlUserDefinedExtractor(AtomicFileProcessing=true)]
      确保由一个实例按顺序处理整个输入,这就足够了,并且在这种情况下可能可行,具体取决于输入大小
  • 行集有秩序吗

    • 行集是无序的概念-可以将它们视为非重复数据消除哈希集

      var input=newhashset(File.ReadLines(@In_Data));
      File.writeAllines(@Out\u NewData,input)

      不希望保留原始的行顺序(即使对某些输入是这样,这是实现细节,不保证语义行为)。
      行集也是如此-当数据转换为行集时,行的输入顺序丢失(不保证)。因此,尝试使用ROW_NUMBER()是徒劳的-在调用ROW_NUMBER()时,没有顺序可以保留。使用ROW_NUMBER()的唯一方法是,如果行集有某个键,其排序顺序可以重新创建行的原始顺序

  • 由于行集没有顺序,因此无论发生什么情况,都需要一个自定义提取器-它是脚本中唯一能够观察文件中行的顺序的部分,给定

    • 它使用原子文件处理,或
    • 您可以找到一种方法来保证在开始…结束序列之间不会发生数据拆分。AFAIK没有办法做到这一点(除非将整个序列预处理为预上传行)

    您可以选择将所有逻辑包含在自定义提取器中,或者只需添加一个带编号的列来模拟行号,并使用本机U-Sql进行逻辑处理。

    仍不清楚。至少对我来说。你的文件有多大?非常感谢你的帮助。它按预期工作。:)有趣的评论@Nabeel。最好能得到一些关于何时发生这种情况的进一步信息,例如250MB的数据块限制。您有任何进一步的信息吗?从我到目前为止看到的文档来看,发生的时间似乎是实现细节(目前可能是250MB),发生的时间(语义保证)似乎是您有>1行的任何时候。如果需要,您可以在自定义提取器中定义行分隔符,但这会限制格式;这里的格式不是以行分隔的格式。
    @dailyAccountResult = [select all rows between "START OF DAILY ACCOUNT" and "END OF DAILY ACCOUNT" rows]
    
    @ledgerBalanceResult = [select all rows between "START OF LEDGER BALANCE" and "END OF LEDGER BALANCE" rows]
    
    @dailySummaryReportResult = [select all rows between "START OF DAILY SUMMARY REPORT" and "END OF DAILY SUMMARY REPORT" rows]
    
    // Get raw input
    @input =
        EXTRACT rawData string
        FROM "/input/input36.txt"
        USING Extractors.Tsv();
    
    
    // Add a row number and break out the section;
    // Get all [START OF ...] and [END OF ...] blocks and pair them.
    // !!WARNING code assumes there are no duplicate sections, ie can not be more than one DAILY ACCOUNT section for example
    @working =
        SELECT ROW_NUMBER() OVER() AS rn,
               System.Text.RegularExpressions.Regex.Match(rawData, "(START OF|END OF) (?<sectionName>.+)").Groups["sectionName"].ToString() AS sectionName,
               *
        FROM @input;
    
    
    // Work out the section boundaries
    @sections =
        SELECT sectionName,
               MIN(rn) AS startRn,
               MAX(rn) AS endRn,
               COUNT( * ) AS records
        FROM @working
        WHERE sectionName != ""
        GROUP BY sectionName;
    
    
    // Create the output
    @output =
        SELECT s.sectionName,
               i.rn == s.startRn ? 1 : 0 AS isStartSection,
               i.rn == s.endRn ? 1 : 0 AS isEndSection,
               i.rawData
        FROM @sections AS s
             CROSS JOIN
                 @working AS i
        WHERE i.rn BETWEEN s.startRn AND s.endRn;
    
    
    // Output the file
    OUTPUT @output
    TO "/output/output.txt"
    USING Outputters.Tsv(quoting : false);
    
    @dailyAccount =
        SELECT rawData
        FROM @output
        WHERE sectionName == "DAILY ACCOUNT"
              AND isStartSection == 0
              AND isEndSection == 0;