Вычисление разницы во времени в задании U-SQL Azure Data Lake Analytics

В нашем проекте нам приходится периодически вычислять агрегаты и дальнейшие расчеты на основе полученных входных данных.

Одним из частых требований является вычисление разницы во времени между определенными строками в нашем потоке входных данных.

Например, это мой входной поток данных:

Отметка времени Значение события
21.05.2017 11:33 e1 17
21.05.2017 11:37 e2 18
21.05.2017 11:38 e3 18
2017 -05-21 11:39 e1 19
2017-05-21 11:42 e2 19

Теперь я хочу рассчитать все промежутки времени между событиями e2 и последним полученным событием e1 (упорядоченные по отметке времени).

я ожидаю, что результат будет: 3 (минуты) 4 (минуты)

Аналогичным требованием было бы вычислить временные промежутки между событиями одного типа (т.е. все различия между событиями e1), где я ожидал бы этот результат: 6 (минуты)

Мои попытки до сих пор:

Такого рода аналитика может быть довольно легко достигнута с помощью функции LAG в сочетании с предложением WHEN, но, к сожалению, предложение WHEN отсутствует в U-SQL. Если бы это был T-SQL, это также можно было бы решить с помощью подвыборки в предложении SELECT оператора, но, к сожалению, это также невозможно в U-SQL.

Есть ли у вас какие-либо предложения или примеры сценариев, как решить эту проблему? Большое спасибо за Вашу помощь!


person Markus S.    schedule 21.05.2017    source источник


Ответы (2)


В U-SQL вы можете использовать методы С# для простой арифметики дат. Если ваши данные так же просты, как вы описываете, вы можете просто ранжировать события e1 и e2, а затем соединить их, примерно так:

@data =
    EXTRACT Timestamp DateTime,
            Event string,
            Value int
    FROM "/input/input58.csv"
    USING Extractors.Csv();

//@data = SELECT *
//     FROM (
//        VALUES
//        ( "2017-05-21 11:33", "e1", 17 ),
//        ( "2017-05-21 11:37", "e2", 18 ),
//        ( "2017-05-21 11:38", "e3", 18 ),
//        ( "2017-05-21 11:39", "e1", 19 ),
//        ( "2017-05-21 11:42", "e2", 19 )
//     ) AS T(Timestamp, Event, Value);


@e1 =
    SELECT ROW_NUMBER() OVER(ORDER BY Timestamp) AS rn,
           *
    FROM @data
    WHERE Event == "e1";

@e2 =
    SELECT ROW_NUMBER() OVER(ORDER BY Timestamp) AS rn,
           *
    FROM @data
    WHERE Event == "e2";

@working =
    SELECT
        (e2.Timestamp - e1.Timestamp).TotalSeconds AS diff_sec,
        (e2.Timestamp - e1.Timestamp).ToString() AS diff_hhmmss,
        e1.Timestamp AS ts1,
        e2.Timestamp AS ts2
    FROM @e1 AS e1
            INNER JOIN @e2 AS e2 ON e1.rn == e2.rn;


OUTPUT @working TO "/output/output.csv"
USING Outputters.Csv(quoting:false);

Мои результаты, показывающие 4 и 3 минуты для выборочных данных:

Результаты

Будет ли это работать для вас? Если нет, предоставьте более реалистичную выборку данных.

person wBob    schedule 21.05.2017
comment
Я чувствую, что это может быть проще, и в U-SQL возможны подзапросы. Напоминает мне, что я должен найти свои пробелы и острова от Ицика Бен-Гана! - person wBob; 21.05.2017
comment
Хороший материал, Боб! Это выглядит разумно! Благодарю вас! - person Markus S.; 22.05.2017
comment
Расширяя реалистичную выборку данных, это решение (по задумке) требует идеального соответствия 1:1 между событиями e1 и e2. Это действительно серьезное требование — всего один ошибочный журнал времени, пропущенное событие, повторяющееся событие и т. д. могут все испортить. По моему опыту, такие аберрации, как правило, возникают в реальных данных - например, при сопоставлении инструментов с несколькими машинами. - person Nabeel; 24.05.2017

@data =
    SELECT
        LAST_VALUE(Event == "e1" ? Timestamp : (DateTime?)null) OVER (ORDER BY Timestamp) AS E1Time
        // MAX(Event == "e1" ? Timestamp : DateTime.MinValue) OVER (ORDER BY Timestamp) AS E1Time
        , Timestamp AS E2Time
    FROM @events
    HAVING Event == "e2"
    ;

потому что агрегаты/WF игнорируют null (по крайней мере, должны, документация по U-SQL для LAST_VALUE ничего не говорит, поэтому требуется проверка). Это позволяет эмулировать условное поведение, такое как WHEN. Аналогичное поведение можно получить с MAX/MIN и соответствующим значением по умолчанию.

Тем не менее, вы должны подробно указать входные данные и ожидаемый результат, что может изменить решение. А именно, могут ли возникнуть аномальные последовательности данных и какое поведение ожидается (или, по крайней мере, допустимо для простоты), если они происходят:

  1. e1, e1, e2 — приведенный выше код игнорирует более ранний e1
  2. e1, e2, e2 — приведенный выше код вычисляет 2 значения относительно одного и того же e1.
  3. e1, e1, e2, e2 — приведенный выше код не распознает вложенность, как и в случае 2.
  4. e2 — приведенный выше код может дать сбой (null) или сбросить результаты при использовании DateTime.MinValue.

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

person Nabeel    schedule 23.05.2017
comment
Спасибо за комментарий, Набил! Однако, честно говоря, в итоге я полностью отказался от DataLake Analytics и использовал оптимизированные для памяти таблицы в SQL Server для необходимой нам аналитики. Нам нужны частые вычисления структурированных данных, и T-SQL отлично справляется с этим. Насколько я понимаю Data Lake Analytics, он лучше подходит, если мы хотим включать неструктурированные данные и выполнять пакетную обработку через более короткие промежутки времени. - person Markus S.; 24.05.2017