q中的Allen IntersectsWith运算符

时间:2019-02-06 01:33:39

标签: kdb

我正在尝试在最新kdb +的q中对Allen的IntersectsWith时间运算符进行基准测试。 Allen的IntersectsWith时间运算符是他定义的13个关系区间代数运算符中的11个的并集。实际上,它将返回所有重叠的间隔以及所有与间隔末尾有关的间隔。 (从这个意义上讲,它不作为原始时间运算符存在。)

我有一张表格,用于保存间隔(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 window-join运算符,但无论如何我都不是“ q God”,而且我不确定如何在包含间隔的行上执行wj。另外,我当时想使用Relational Interval Tree数据结构对间隔进行建模,并在“叉节点”上建立索引/键控,但是后来我失去了wj的好处。

虽然这里的样本数据很小,但我的目标是最终对20B行进行基准测试。

编辑:这是一个SQL查询,该查询可复制我想做的事情以及查询的输出。您也可以run the SQL on 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

输出:

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 :(得分:2)

简单的方法(用于内存表)将仅遍历每个QueryPeriods并获取所需的数据。通常,它运行速度非常快,并且可以对其进行某些优化。

dv表(数据值)

     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表(查询值)

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 

我在1亿行具有相同符号和2个不同查询期的表上进行了测试(上面提到的同一张表),花了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. 表属性:在列上使用正确的属性可以帮助缩短查询执行时间。我设置了按开始日期,结束日期排序的数据值表。

  2. 并行执行:在查询之上并行运行非常容易,这也可以缩短执行时间(取决于系统配置和KDB设置)。如果您的KDB进程中正在运行从属服务器,则只需在上面的查询中使用“桃子”而不是“每个”即可。这将在不同的进程中执行不同批次的查询期。