Страницы: 1
RSS
PQ: вычислить даты события по неявному условию
 
Добрый день, форумчане!
Есть таблица, в которой отображены дата и время пинга некоторой системы и результат этого пингования (превышение нормативного времени, в таблице это "ИСТИНА"). Когда постоянное пингование проходит с превышением норматива - это одно продолжающееся событие с нарушением и продолжается оно до тех пор, пока не уложится в норматив (в таблице это пока не появится "ЛОЖЬ"). Требуется вычислить дату начала и конца каждого события, чтобы в дальнейшем в PBI проводить анализ по ним.
Я смог сделать нужные преобразования с помощью вычисляемых полей и DAX, но система падает при загрузке более 400 тыс. строк, что и понятно - не под это DAX заточен, поэтому и прошу помощи в решении с помощью PQ.
 
Владимир, от души в душу! Получилось вот такое. Надеюсь сработает быстро на вашем массиве.
ВНИМАНИЕ, КОД КОСЯЧНЫЙ, постом ниже привел корректный код запроса.
Скрытый текст
Изменено: PooHkrd - 18.06.2021 13:34:44
Вот горшок пустой, он предмет простой...
 
Еще такой вариант (Custom1 нагло скопировал у PooHkrd):
Код
let
    Источник = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    #"Измененный тип" = Table.TransformColumnTypes(Источник,{{"ID", Int64.Type}, {"Время_пинг", type datetime}, {"Значение, сек", Int64.Type}, {"Норматив, сек", Int64.Type}, {"True/False", type logical}}),
    Custom1 = Table.FromColumns( 
        Table.ToColumns( #"Измененный тип" ) & {List.RemoveLastN( {false} & #"Измененный тип"[#"True/False"], 1 )}, 
        Table.ColumnNames( #"Измененный тип" ) & {"t_f_prev"} ),

    #"Сортированные строки" = Table.Sort(#"Custom1",{{"Время_пинг", Order.Ascending}}),
    #"Добавлен пользовательский объект" = Table.AddColumn(#"Сортированные строки", "время начала", each if [#"True/False"]=true and [t_f_prev]=false then [Время_пинг] else null, type datetime),
    #"Добавлен пользовательский объект1" = Table.AddColumn(#"Добавлен пользовательский объект", "время конца", each if [#"True/False"]=false and [t_f_prev]=true then [Время_пинг] else null),
    #"Заполнено вверх" = Table.FillUp(#"Добавлен пользовательский объект1",{"время конца"}),
    #"Замененное значение" = Table.ReplaceValue(#"Заполнено вверх",each [время конца],each if [#"True/False"]=true and [t_f_prev]=false then [время конца] else null,Replacer.ReplaceValue,{"время конца"}),
    #"Удаленные столбцы" = Table.RemoveColumns(#"Замененное значение",{"t_f_prev"}),
    #"Измененный тип1" = Table.TransformColumnTypes(#"Удаленные столбцы",{{"время конца", type datetime}})
in
    #"Измененный тип1"
 
Еще вариант. Этот корректный, предыдущий косячит на некоторых строках, пока не понял почему. Разбираюсь. Разобрался, тот вариант поправить не получится - алгоритм хромает.
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    ChangedType = Table.TransformColumnTypes(Source,{{"Время_пинг", type datetime}}),
    SortedRows = Table.Sort(ChangedType,{{"Время_пинг", Order.Descending}}),
    GroupedRows = Table.Group(
        SortedRows, 
        {"True/False"}, 
        {{"tab", each if List.Last([#"True/False"]) 
                then Table.FromColumns( 
                        Table.ToColumns(Table.Sort(_,{{"Время_пинг", Order.Ascending}})) & {{List.Min([Время_пинг])}, {List.Max([Время_пинг])}}, 
                        Table.ColumnNames(_) & {"Время начала", "Время окончания"} ) 
                else _}},
        0,
        (a,b)=>Number.From(not a[#"True/False"] and not b[#"True/False"])),
    Combine = Table.Combine( GroupedRows[tab] ),
    SortedTable = Table.Sort(Combine,{{"Время_пинг", Order.Ascending}})
in
    SortedTable
Изменено: PooHkrd - 18.06.2021 13:44:24
Вот горшок пустой, он предмет простой...
 
PooHkrd, surkenny, как я рад получить этот код - огромное спасибо, пошел тестировать!
 
Тест провалился. Я забыл указать в условии, что ID разные и этот фактор нужно учесть(( Сможете подкорректировать решения? Во вложении два пред. решения от PooHkrd, и surkenny, но они сделаны без учета ID.
П.С. исходник 19 млн. строк, оставляю нужных около 500 тыс. и их обрабатываю. DAX уже не может, а PQ сделал за пару минут! Вот что значит, использовать задачи по прямому назначению. DAX-y - вычисления, PQ - преобразования.
Изменено: Vladimir Chebykin - 18.06.2021 15:51:42
 
Владимир, вам надо чутка подучиться PQ, тут такие расклады неоднократно уже разбирались.
1. Вместо ссылки на таблицу в запрос подсовываете параметр
2. Из запроса формируете связанную функцию
3. обращаетесь к источнику, группируете по ID и применяете полученную функцию к изолированным таблицам. (типа ALLSELECTED  ;) )
4. собираем все обратно
Смотрите запрос Таблица1_1
Можете по указанному алгоритму потренироваться, чтобы сделать функцию из запроса Surkenny, если он сам не заморочится.  :D
Изменено: PooHkrd - 18.06.2021 16:23:48
Вот горшок пустой, он предмет простой...
 
Vladimir Chebykin, вот так попробуйте (по сути в группировке по ID нужно выполнить только одно действие - заполнить время конца вверх):
Код
let
    Источник = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    #"Измененный тип" = Table.TransformColumnTypes(Источник,{{"ID", Int64.Type}, {"Время_пинг", type datetime}, {"Значение, сек", Int64.Type}, {"Норматив, сек", Int64.Type}, {"True/False", type logical}}),
    Custom1 = Table.FromColumns( 
        Table.ToColumns( #"Измененный тип" ) & {List.RemoveLastN( {false} & #"Измененный тип"[#"True/False"], 1 )}, 
        Table.ColumnNames( #"Измененный тип" ) & {"t_f_prev"} ),
    #"Сортированные строки2" = Table.Sort(Custom1,{{"ID", Order.Ascending}, {"Время_пинг", Order.Ascending}}),
 
    #"Добавлен пользовательский объект" = Table.AddColumn(#"Сортированные строки2", "время начала", each if [#"True/False"]=true and [t_f_prev]=false then [Время_пинг] else null, type datetime),
    #"Добавлен пользовательский объект1" = Table.AddColumn(#"Добавлен пользовательский объект", "время конца", each if [#"True/False"]=false and [t_f_prev]=true then [Время_пинг] else null),
    #"Сгруппированные строки" = 
        Table.Group(
            #"Добавлен пользовательский объект1", 
            {"ID"}, 
            {{
                "group", 
                 each Table.FillUp(Table.Sort(_,{{"Время_пинг", Order.Ascending}}),{"время конца"}), 
                 type table [Время_пинг=datetime, #"Значение, сек"=Int64.Type, #"Норматив, сек"=Int64.Type, #"True/False"=logical, #"t_f_prev"=logical, время начала=datetime, время конца=datetime]
            }}
        ),
    #"Развернутый элемент group" = Table.ExpandTableColumn(#"Сгруппированные строки", "group", {"Время_пинг", "Значение, сек", "Норматив, сек", "True/False", "t_f_prev", "время начала", "время конца"}),
    #"Замененное значение" = Table.ReplaceValue(#"Развернутый элемент group",each [время конца],each if [#"True/False"]=true and [t_f_prev]=false then [время конца] else null,Replacer.ReplaceValue,{"время конца"}),
    #"Удаленные столбцы" = Table.RemoveColumns(#"Замененное значение",{"t_f_prev"}),
    #"Измененный тип1" = Table.TransformColumnTypes(#"Удаленные столбцы",{{"время конца", type datetime}})
in
    #"Измененный тип1"
Изменено: surkenny - 18.06.2021 16:59:45
 
Цитата
PooHkrd написал:
Можете по указанному алгоритму потренироваться, чтобы сделать функцию из запроса Surkenny, если он сам не заморочится.  
Я бы еще предложил в качестве тренировки внутри группировки "почистить" строки TRUE без данных времени начала. Если уж это одно событие и время начала/конца указано в первой записи, то зачем остальные записи до окончания события?:)
Как раз и строк поменьше будет.
 
Еще вариант
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    Custom1 = let a=Source, b= Table.ToColumns(a) , c = {{null}&List.RemoveLastN(List.Last(b),1)},
                  d= b&c, e= Table.FromColumns(d, Table.ColumnNames(a)&{"a"}) in e,
    #"Grouped Rows" = Table.Group(Custom1, {"True/False","a"},{{"b", each 
       let d=_, c1= if d[#"True/False"]{0}=false then null else d[Время_пинг]{0}, 
      c2=List.Last(Table.RemoveLastN(d,each [a] <> true)[Время_пинг]),
   e=Table.ToColumns(d)&{{c1}}&{{c2}}, f=Table.ColumnNames(d)&{"время начала","время конца"} 
   in Table.FromColumns(e,f)
    }},0,(a,b)=> Number.From( b[#"True/False"] and not b[#"a"])),
    Custom2 = Table.Combine(#"Grouped Rows"[b]),
    #"Removed Columns" = Table.RemoveColumns(Custom2,{"a"})
in
    #"Removed Columns"
Изменено: Михаил Л - 18.06.2021 19:00:44 (Добавил файл с другим запросом под разные ID)
 
Всех благодарю за участие! Я в понедельник на работе опробую ваши решения.
Цитата
PooHkrd написал:
Владимир, вам надо чутка подучиться PQ
Согласен, надо себя заставлять работать над собой. Я бы мог сказать, что на все не хватает времени, но по факту - просто лень, когда и так 95% задач покрываются мышкоклацканием!
Цитата
surkenny написал:
Я бы еще предложил в качестве тренировки внутри группировки "почистить" строки TRUE без данных времени начала.
Я попробую!
Страницы: 1
Наверх