powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Добавить недостающие данные
9 сообщений из 9, страница 1 из 1
Добавить недостающие данные
    #39807055
olegsng
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый вечер, коллеги

прошу подсказать как сделать правильно - решение я нашел, но оно явно не оптимальное.
Итак, есть регистратор, который отслеживает некие процессы и в определенной периодичностью записывает данные в таблицу вида
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE RAW_DATA (
    PAIRBASKET_ID  ID_FIELD /* ID_FIELD = INTEGER NOT NULL */,
    TFDATETIME     STR50 /* STR50 = VARCHAR(50) DEFAULT '' */,
    PAIRDATETIME   TIMESTAMP,
    Данные.....      
);

CREATE DESCENDING INDEX RAW_DATA_IDX1 ON RAW_DATA (TFDATETIME);
CREATE DESCENDING INDEX RAW_DATA_IDX2 ON RAW_DATA (PAIRBASKET_ID, TFDATETIME);
CREATE DESCENDING INDEX RAW_DATA_IDX3 ON RAW_DATA (PAIRDATETIME);
CREATE DESCENDING INDEX RAW_DATA_IDX4 ON RAW_DATA (PAIRBASKET_ID, PAIRDATETIME);



Формально в поле TFDATETIME хранится время в таком формате '2019.04.26 10:01', и данные в нем соответствуют PAIRDATETIME. Источник данных дает дату в виде строки, которая записывается в исходном виде, и идет доп преобразование в формат TIMESTAMP в поле PAIRDATETIME.

Регистрируемых процессов может быть несколько (до 30) и иногда некоторые из них пропускают выдачу данных на каком-либо интервале. Ну вот пример реальных данных


PAIRBASKET_IDTFDATETIMEBALANCE101.02.2018 10:0810001.83201.02.2018 10:0810001.83101.02.2018 10:0910001.83201.02.2018 10:0910001.83101.02.2018 10:1010001.83201.02.2018 10:1010001.83201.02.2018 10:1110001.83201.02.2018 10:1210001.83201.02.2018 10:1310003.66101.02.2018 10:1510003.66101.02.2018 10:1610003.66201.02.2018 10:1610003.66101.02.2018 10:1710003.66201.02.2018 10:1710003.66101.02.2018 10:1810003.66201.02.2018 10:1810003.66


Видно что процесс ID=1 не дал показания в 10:11, 10:12, 10:13, 10:14, процесс ID=2 не дал показания в 10:14 и 10:15.

Необходимо обработать исходные данные, добавив отсутствующие показатели, использовав ближайшие по времени ранее полученные данные. Т.е. для первого процесса необходимо добавить записи для времени 10:11, 10:12, 10:13, 10:14, использовав для заполнения данные за 10:10.

Время 10:14 не будет заполнено для обоих процессов, т.е. его нет в исходных измерениях.

Вот так должны выглядеть нормализованные/дополненные данные

PAIRBASKET_IDTFDATETIMEBALANCE101.02.2018 10:0810001.83201.02.2018 10:0810001.83101.02.2018 10:0910001.83201.02.2018 10:0910001.83101.02.2018 10:1010001.83201.02.2018 10:1010001.83101.02.2018 10:1110001.83201.02.2018 10:1110001.83101.02.2018 10:1210001.83201.02.2018 10:1210001.83101.02.2018 10:1310001.83201.02.2018 10:1310003.66101.02.2018 10:1510003.66201.02.2018 10:1510003.66101.02.2018 10:1610003.66201.02.2018 10:1610003.66101.02.2018 10:1710003.66201.02.2018 10:1710003.66101.02.2018 10:1810003.66201.02.2018 10:1810003.66


Я написал процедуру получения недостающих данных вида

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
CREATE OR ALTER PROCEDURE GET_CSV_DATA (
    CSV_DATETIME TYPE OF COLUMN RAW_DATA.TFDATETIME,
    GET_PAIRBASKET_ID TYPE OF COLUMN RAW_DATA.PAIRBASKET_ID)
RETURNS (
    PAIRBASKET_ID TYPE OF COLUMN RAW_DATA.PAIRBASKET_ID,
    R_DATETIME TYPE OF COLUMN RAW_DATA.TFDATETIME,
    G_DATETIME TYPE OF COLUMN RAW_DATA.TFDATETIME,
    BALANCE TYPE OF COLUMN RAW_DATA.BALANCE)
AS
BEGIN
 /* Procedure Text */
 /* v.1.0 23.04.2019 */
 /* Выдача данных с учетом пропусков по времени */

 PAIRBASKET_ID = NULL;

 /* проверяем на наличие в соответствии зс заданным временем */
 SELECT FIRST 1  rd.PAIRBASKET_ID, rd.TFDATETIME, :CSV_DATETIME,
                          rd.BALANCE
  FROM  RAW_DATA rd
  WHERE (rd.PAIRBASKET_ID = :GET_PAIRBASKET_ID) AND (rd.TFDATETIME <= :CSV_DATETIME)
  ORDER BY rd.PAIRDATETIME DESC
  INTO  :PAIRBASKET_ID, :R_DATETIME, :G_DATETIME,
            :BALANCE;

  IF (PAIRBASKET_ID IS NULL) THEN  BEGIN
  /* тоже нет, ищем первую запись по времени */

   SELECT FIRST 1  rd.PAIRBASKET_ID, rd.TFDATETIME, :CSV_DATETIME,
                            rd.BALANCE
    FROM  RAW_DATA rd
    WHERE (rd.PAIRBASKET_ID = :GET_PAIRBASKET_ID)
    ORDER BY rd.PAIRDATETIME ASC
    INTO  :PAIRBASKET_ID, :R_DATETIME, :G_DATETIME,
             :BALANCE;
  END -- IF ((PAIRBASKET_ID IS NULL) THEN  BEGIN

  SUSPEND;
 END

PLAN (RD ORDER RAW_DATA_IDX3 INDEX (RAW_DATA_IDX2))SORT ((RD INDEX (RAW_DATA_IDX2)))



Процедура прекрасно работает, выбирая 1 индексированную запись.

Дальше я решил сделать перебор всех возможных вариантов следующим образом
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
FOR SELECT rd.TFDATETIME
 FROM RAW_DATA rd
 GROUP BY rd.TFDATETIME
 ORDER BY rd.TFDATETIME ASC
 INTO CSV_TFDATETIME DO BEGIN

  FOR SELECT rd.PAIRBASKET_ID
  FROM RAW_DATA rd
  GROUP BY rd.PAIRBASKET_ID
  INTO CSV_PAIR DO BEGIN
   EXECUTE PROCEDURE GET_CSV_DATA(:CSV_TFDATETIME, :CSV_PAIR)
   RETURNING_VALUES :PAIRBASKET_ID, :R_TFDATETIME, :G_TFDATETIME,
                     :BALANCE;

  ........


Это как бы тоже работает, но перебор в циклах FOR SELECT идет натуралом и получается квадрат количества исходных строк - это количество неиндексированных чтений. Т.е., если всего записей 2 000, то чтений 4 000 000. Реально цикл измерений может дать и миллион записей - соответственно ждать окончания расчета можно будет до конца времен.

Куда рыть, собственно, как это сделать хотя бы до конца нашей эры?
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807078
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
olegsng,

пусть при добавлении сразу выполняется проверка.
Смотри перед добавлением на последнюю запись запись данного процесса. Если есть пропуски - добавляй не одну запись, а столько, сколько раз было пропущено. Можно даже табличку завести для хранения последней записи по каждому процессу.
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807084
olegsng
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ёёёёёolegsng,

пусть при добавлении сразу выполняется проверка.
Смотри перед добавлением на последнюю запись запись данного процесса. Если есть пропуски - добавляй не одну запись, а столько, сколько раз было пропущено. Можно даже табличку завести для хранения последней записи по каждому процессу.

Не, не взлетит. Я упустил еще одну важную деталь. Сырые данные пишутся в файлы, индивидуальные для каждого процесса, формально в формате сsv, потом анализатор последовательно читает файлы и их содержимое, разбирает на компоненты и скидывает в базу. Так что выяснить, какой будет distinct состав времен замеров можно выяснить только после добавления всех записей.
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807093
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
olegsngёёёёёolegsng,

пусть при добавлении сразу выполняется проверка.
Смотри перед добавлением на последнюю запись запись данного процесса. Если есть пропуски - добавляй не одну запись, а столько, сколько раз было пропущено. Можно даже табличку завести для хранения последней записи по каждому процессу.

Не, не взлетит. Я упустил еще одну важную деталь. Сырые данные пишутся в файлы, индивидуальные для каждого процесса, формально в формате сsv, потом анализатор последовательно читает файлы и их содержимое, разбирает на компоненты и скидывает в базу. Так что выяснить, какой будет distinct состав времен замеров можно выяснить только после добавления всех записей.

Ну, при записи сырых данных в файл дописывай пропущенные.
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807096
olegsng
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ёёёёёolegsngпропущено...


Не, не взлетит. Я упустил еще одну важную деталь. Сырые данные пишутся в файлы, индивидуальные для каждого процесса, формально в формате сsv, потом анализатор последовательно читает файлы и их содержимое, разбирает на компоненты и скидывает в базу. Так что выяснить, какой будет distinct состав времен замеров можно выяснить только после добавления всех записей.

Ну, при записи сырых данных в файл дописывай пропущенные.

Процессы записи сырых данных ничего не знают друг о друге и в каком периоде они получают/не получают данные. Допустим, первый процесс может видеть, что пропущен период 10:11-10:14, но он никак не может узнать, что время 10:11-10:13 появятся в другом процессе, а время 10:14 не появится никогда и добавлять запись для первого процесса со временем 10:14 не нужно.

Выяснить, какой будет distinct состав времен замеров можно выяснить только после добавления всех записей по всем процессам.
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807098
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
olegsngёёёёёпропущено...


Ну, при записи сырых данных в файл дописывай пропущенные.

Процессы записи сырых данных ничего не знают друг о друге и в каком периоде они получают/не получают данные. Допустим, первый процесс может видеть, что пропущен период 10:11-10:14, но он никак не может узнать, что время 10:11-10:13 появятся в другом процессе, а время 10:14 не появится никогда и добавлять запись для первого процесса со временем 10:14 не нужно.

Выяснить, какой будет distinct состав времен замеров можно выяснить только после добавления всех записей по всем процессам.
А чем определяется необходимость добавления отсутствующих данных? Я изначально понял, что просто каждую секунду нужно. А теперь вроде и не уверен.
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807099
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
olegsng,

ты подгоняешь данные к псевдофакту, что все процессы якобы заносят данные в одинаковые моменты времени?
То есть, в случае события от процесса А, должно имитироваться наступление события и других процессов?
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807102
olegsng
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ёёёёё,

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

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

Короче, если временная дырка есть во всех процесах - ничего не делаем, а если данные появились только в одном процессе из, например, 20, то в 19 дописываем это фиктивное для них время и значащие данные получаем по алгоритму - создаем 19 дополнительных записей.
...
Рейтинг: 0 / 0
Добавить недостающие данные
    #39807103
vvvait
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
olegsng, не уверен как это будет работать на миллионе записей, но по крайней мере нет квадрата
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
select
  p.PAIRBASKET_ID,
  dt.PAIRDATETIME,
  coalesce(rd.BALANCE, (select first 1 BALANCE from RAW_DATA where PAIRBASKET_ID = p.PAIRBASKET_ID and PAIRDATETIME < dt.PAIRDATETIME order by PAIRDATETIME desc))
from (select distinct rd.PAIRBASKET_ID from RAW_DATA rd) as p
join (select distinct rd.PAIRDATETIME from RAW_DATA rd) as dt on 1 = 1
left join RAW_DATA rd on rd.PAIRBASKET_ID = p.PAIRBASKET_ID and rd.PAIRDATETIME = dt.PAIRDATETIME
order by 2, 1


чтобы ещё более ускорить, нужна таблица со списком процессов
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
create table PAIRBASKETS(PAIRBASKET_ID integer primary key)

select
  p.PAIRBASKET_ID,
  dt.PAIRDATETIME,
  coalesce(rd.BALANCE, (select first 1 BALANCE from RAW_DATA where PAIRBASKET_ID = p.PAIRBASKET_ID and PAIRDATETIME < dt.PAIRDATETIME order by PAIRDATETIME desc))
from PAIRBASKETS p
join (select distinct rd.PAIRDATETIME from RAW_DATA rd) as dt on 1 = 1
left join RAW_DATA rd on rd.PAIRBASKET_ID = p.PAIRBASKET_ID and rd.PAIRDATETIME = dt.PAIRDATETIME
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Добавить недостающие данные
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]