代码之家  ›  专栏  ›  技术社区  ›  John Zabroski

q中带算子的Allen相交

kdb
  •  1
  • John Zabroski  · 技术社区  · 7 年前

    我正试图在最新的kdb+上用q中的时态操作符对Allen的IntersectsWith进行基准测试。Allen的IntersectsWith-temporal运算符是他定义的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窗口连接操作符有点熟悉,但无论如何我都不是一个“q神”,我也不知道如何在包含区间的行上执行wj。或者,我正在考虑使用 Relational Interval Tree “fork节点”上的数据结构和索引/键控,但我失去了wj的好处。

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

    编辑:这里有一个SQL查询,它复制了我想要做的事情,以及查询的输出。你也可以 run the SQL on rextester ,但由于它是使用CTEs构建的,因此在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 回复  |  直到 7 年前
        1
  •  2
  •   Rahul    7 年前

    简单的方法(对于内存中的表)就是迭代每个QueryPeriod并获取所需的数据。通常情况下,它运行得非常快,并且可以使用它进行某些优化。

         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
    

    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亿行相同符号和两个不同查询周期的表(上面提到的同一个表)上测试了它,执行它需要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排序的datavalues表。

    2. 并行执行 :并行运行上述查询非常容易,这也会缩短执行时间(取决于系统配置和KDB设置)。如果KDB进程中有从进程,那么在上面的查询中使用“peach”而不是“each”。这将在不同的进程中执行不同批次的查询周期。

    推荐文章