Аллен пересекается с оператором в q - PullRequest
0 голосов
/ 06 февраля 2019

Я пытаюсь сравнить временной интервал Аллена с временным оператором в q на последнем kdb +.Временной оператор Аллена IntersectsWith представляет собой объединение 11 из 13 операторов реляционной интервальной алгебры, которые он определяет.По сути, он возвращает все перекрывающиеся интервалы плюс любые, которые касаются концов интервала.(В этом смысле он не существует в качестве примитивного временного оператора).

У меня есть таблица, содержащая измерения прибора за интервал (startDate,endDate) - размер интервала может быть динамическим, но в приведенном ниже примереэто интервалы в одну минуту:

queryPeriods:dataFieldStartDate`dataFieldEndDate!(2019.01.01T00:00:00.000000000; 2019.01.02T00:00:00.000000000)
dataValues:`datafield`startDate`endDate!(`inst1_m`inst1_m`inst1_m;2019.01.01T00:00:00.000000000 2019.01.01T00:01:00.000000000 2019.01.01T00:02:00.000000000; 2019.01.01T00:01:00.000000000 2019.01.01T00:02:00.000000000 2019.01.01T00:03:00.000000000)
queryPeriods
dataFieldStartDate            | dataFieldEndDate 
-----------------------------   -----------------------------
2019.01.01T00:00:00.000000000 | 2019.01.02T00:00:00.000000000
dataValues
datafield | startDate                     | endDate
---------   -----------------------------   -----------------------------
`inst1_m  | 2019.01.01T00:00:00.000000000 | 2019.01.01T00:01:00.000000000 
`inst1_m  | 2019.01.01T00:01:00.000000000 | 2019.01.01T00:02:00.000000000
`inst1_m  | 2019.01.01T00:02:00.000000000 | 2019.01.01T00:03:00.000000000

Я немного знаком с оператором соединения окон wj, но я ни в коем случае не "Бог",и я не уверен, как сделать wj в строке, содержащей интервал.В качестве альтернативы я думал о моделировании интервала с использованием структуры данных Relational Interval Tree и индексировании / вводе ключей на "узле ветвления", но затем я теряю преимущества wj.

Хотяпримерных данных здесь мало, моя цель - в конечном итоге сравнить 20B строк.

РЕДАКТИРОВАТЬ: Вот запрос SQL, который копирует то, что я хочу сделать, плюс вывод запроса.Вы также можете запустить SQL на rextester , но, поскольку он построен с использованием CTE, ему не требуются специальные разрешения для запуска на SQL Server.

;WITH QueryPeriods AS (
    SELECT
        DataFieldStartDate = CAST('2019.01.01 00:00:00.0000000' AS DATETIME2),
        DataFieldEndDate = CAST('2019.01.02 00:00:00.0000000' AS DATETIME2)
), DataValues AS (
    SELECT
        datafield = 'inst1_m',
        startDate = CAST('2019-01-01 00:00:00.0000000' AS DATETIME2),
        endDate = CAST('2019.01.01 00:01:00.0000000' AS DATETIME2)
    UNION ALL
    SELECT
        datafield = 'inst1_m',
        startDate = CAST('2019.01.01 00:01:00.0000000' AS DATETIME2),
        endDate = CAST('2019.01.01 00:02:00.0000000' AS DATETIME2)
    UNION ALL
    SELECT
        datafield = 'inst1_m',
        startDate = CAST('2019.01.01 00:02:00.0000000' AS DATETIME2),
        endDate = CAST('2019.01.01 00:03:00.0000000' AS DATETIME2)
)
SELECT
    qp.*,
    dv.*
FROM QueryPeriods qp
    LEFT JOIN DataValues dv
        ON dv.datafield = 'inst1_m'
        AND dv.startDate < qp.DataFieldEndDate AND dv.endDate > qp.DataFieldStartDate

OUTPUT:

DataFieldStartDate  DataFieldEndDate    datafield startDate           endDate
01.01.2019 00:00:00 02.01.2019 00:00:00 inst1_m   01.01.2019 00:00:00 
  01.01.2019 00:01:00
01.01.2019 00:00:00 02.01.2019 00:00:00 inst1_m   01.01.2019 00:01:00 
 01.01.2019 00:02:00
01.01.2019 00:00:00 02.01.2019 00:00:00 inst1_m   01.01.2019 00:02:00 
 01.01.2019 00:03:00

1 Ответ

0 голосов
/ 07 февраля 2019

Простой подход (для таблицы в памяти) состоит в том, чтобы просто перебирать каждый QueryPeriods и извлекать необходимые данные.Обычно он работает довольно быстро, и с ним можно выполнить определенные оптимизации.

dv table (DataValues)

     datafield   startDate     endDate                      
----------------------------------------------
    ibm 2000.01.01T00:00:03.649z 2000.01.01T00:10:03.649z
    ibm 2011.01.19T12:58:59.098z 2011.01.19T13:08:59.098z
    ibm 2011.01.19T12:59:08.222z 2011.01.19T13:09:08.222z
    ibm 2007.11.11T21:26:07.936z 2007.11.11T21:36:07.936z

qv table (Query Values)

dataFieldStartDate             dataFieldEndDate
-------------------------------------------------
2011.01.19T13:08:53.604z 2011.01.19T14:09:53.604z
2007.03.05T23:46:47.997z 2007.11.11T21:26:08.938z

Функция:

q) raze {[x;y]![select from dv where datafield=x,startDate<y`dataFieldEndDate,
   endDate>y`dataFieldStartDate;();0b;y]}[`ibm]each  qv 

Я проверил ее на таблице с 100 миллионами строк с одинаковым символом и двумя разными периодами запросов (та же таблица, упомянутая выше), для выполнения потребовалось 3,8 секунды.

Вывод:

dataField   startDate          endDate                 dataFieldStartDate   dataFieldEndDate                      
-------------------------------------------------------------------------------------------------------
ibm 2011.01.19T12:58:59.098z 2011.01.19T13:08:59.098z 2011.01.19T13:08:53.604z 2011.01.19T14:09:53.604z
ibm 2011.01.19T12:59:08.222z 2011.01.19T13:09:08.222z 2011.01.19T13:08:53.604z 2011.01.19T14:09:53.604z
ibm 2007.11.11T21:26:07.936z 2007.11.11T21:36:07.936z 2007.03.05T23:46:47.997z 2007.11.11T21:26:08.938z

Оптимизации:

  1. Атрибуты таблицы : Использование правильных атрибутовна столбцы может помочь улучшить время выполнения запроса.Я настраиваю таблицу данных, отсортированную по startdate, enddate.

  2. Параллельное выполнение : очень легко выполнить параллельный запрос выше, что также должно сократить время выполнения (в зависимости отКонфигурация системы и настройка KDB).Если в вашем процессе KDB работают подчиненные, тогда просто используйте «персик» вместо «каждый» в приведенном выше запросе.Это будет выполнять разные пакеты периодов запросов в разных процессах.

...