USQL - Как выбрать все строки между двумя строками в USQL

Вот полное описание моей задачи:

Мне нужно извлечь данные из нескольких файлов с помощью u-sql и вывести их в файл csv. Каждый входной файл содержит несколько отчетов, основанных на некоторых строковых строках («НАЧАЛО ...» и «КОНЕЦ ...», работающие как разделители отчетов). Вот пример (формат данных) единственного исходного (входного) файла:

START OF DAILY ACCOUNT
some data 1
some data 2
some data 3
some data n
END OF DAILY ACCOUNT
START OF LEDGER BALANCE
some data 1
some data 2
some data 3
some data 4
some data 5
some data n
END OF LEDGER BALANCE
START OF DAILY SUMMARY REPORT
some data 1
some data 2
some data 3
some data n
END OF DAILY SUMMARY REPORT

Итак, теперь мой вопрос: как мне получить записи между строками «НАЧАЛО ...» и «КОНЕЦ ...» для всех файлов?

Я хочу что-то вроде этого в конце:

@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]

Нужно ли мне для этого писать собственный экстрактор? Если да, то подскажите, пожалуйста, как.


person Kishan Gupta    schedule 13.12.2016    source источник
comment
Все еще неясно. По крайней мере для меня.   -  person Imad    schedule 13.12.2016
comment
Какого размера ваш файл?   -  person Jamil    schedule 13.12.2016


Ответы (2)


Я думаю, что это возможно с использованием обычного U-SQL без специального экстрактора. Я создал простой пример на основе ваших образцов данных:

// 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;

Попробуйте и дайте мне знать, как у вас дела.

person wBob    schedule 13.12.2016
comment
Спасибо большое за вашу помощь. Это сработало, как и ожидалось. :) - person Kishan Gupta; 13.12.2016

Соответствующие вопросы, которые следует задать:

  1. In a distributed processing system, will all input data (which could be TBs) be processed by 1 Extractor instance?
    • Definitely not! For confirmation, see EXTRACT documentation (msdn.microsoft.com/en-us/library/azure mt621320.aspx).
  2. Given multiple extractor instances, where can data get split? Put another way, generically, what determines the unit of atomicity of data in U-Sql? Specifically for your case, what guarantee do you have that entire START...END sequences will be processed by one instance and not split up in the middle?
    • Data Lake Tools documentation suggests the generic unit of data atomicity is "line" (row-structured file) - and that this is a property of the data upload itself.
    • Per Руководство по программированию USQL, [SqlUserDefinedExtractor(AtomicFileProcessing = true)] гарантирует, что весь ввод обрабатывается последовательно одним экземпляром, что достаточно и может быть осуществимо для этого случая в зависимости от размера ввода.
  3. Есть ли порядок в наборах строк?

    • Нет! Наборы строк - это неупорядоченные концепции - думайте о них как о не дедупликационных наборах HashSet.

      var input = new HashSet<string>(File.ReadLines(@In_Data)); File.WriteAllLines(@Out_NewData, input)

      не ожидается, что будет сохранен исходный порядок строк (даже если это произойдет для некоторых входных данных, это детали реализации, а не гарантированное семантическое поведение).
      То же самое для наборов строк - порядок ввода строк теряется (не гарантируется) в момент данных переводится в набор строк. Таким образом, попытки использовать ROW_NUMBER () бесплодны - нет порядка, который нужно сохранить к тому времени, когда ROW_NUMBER () может быть вызван. Единственный способ использовать ROW_NUMBER () - это если в наборе строк был какой-то ключ, порядок сортировки которого мог бы воссоздать исходный порядок строк.

Поскольку наборы строк не имеют порядка, вам понадобится специальный экстрактор, несмотря ни на что - это единственная часть скрипта, способная соблюдать порядок строк в файле, учитывая

  • он использует AtomicFileProcessing или
  • вы выясняете способ гарантировать, что не произойдет разделения данных между последовательностями START ... END. AFAIK нет способа сделать это (кроме предварительной обработки целых последовательностей в строки перед загрузкой).

Вы можете включить всю свою логику в настраиваемый экстрактор или просто добавить пронумерованный столбец для имитации ROW_NUMBER и использовать собственный U-Sql для логики.

person Nabeel    schedule 19.04.2017
comment
Интересные комментарии @Nabeel. Было бы неплохо получить дополнительную информацию о том, когда это произойдет, например, при ограничении экстента 250 МБ. У вас есть дополнительная информация? - person wBob; 30.04.2017
comment
Из документации, которую я видел до сих пор, когда кажется, что это деталь реализации (и в настоящее время может быть 250 МБ), когда это может произойти (семантическая гарантия), похоже, будьте в любое время ›1 строчка. Если при необходимости вы можете определить разделитель строк в настраиваемом экстракторе, но это ограничивает формат; тот, что здесь, не является форматом с разделителями строк. - person Nabeel; 01.05.2017