kdb q - 并行保存分区

时间:2018-04-25 11:57:40

标签: kdb

我有一个“检索”(在这种情况下只是创建)一个表并将其存储在新分区中的函数

npertable:100000;
dbname:`:partdb;

newpart:{[date]
    firstofmonth:"d"$"m"$date;
    table:([]date:npertable?firstofmonth+til 25;acc:npertable?`C123`C132`C321`C121`C131;c:npertable?til 100);
    table:`date`acc xasc table;
    partname:`$(("/" sv (string dbname;string "m"$date;enlist "t")),enlist "/");
    partname set .Q.en[dbname;table];
 };

假设在函数内部创建table需要“很长”的时间(例如很多行)。现在,我不能在不同的线程上使用这个方法

newpart peach 2018.03.01 2018.04.01 2018.05.01

因为

ERROR: 'noupdate: `. `sym

这并不奇怪,因为它可能无法异步更新sym文件。

有没有办法在kdb中并行存储分区?

感谢您的帮助

3 个答案:

答案 0 :(得分:2)

另一种方法是重新修改您的功能并将其分解为更小的步骤。我首先将枚举从设置中分离到磁盘 - 这样就可以枚举所有表格'主线程中的sym列,然后将枚举数据设置为线程中的磁盘。注意 - 如果您首先并行化磁盘io,这可能会很有用。

npertable:100000;
dbname:`:partdb;

createTab:{[datep]
    firstofmonth:"d"$"m"$datep;
    table:([]date:npertable?firstofmonth+til 25;acc:npertable?`C123`C132`C321`C121`C131;c:npertable?til 100);
    delete date from `date`acc xasc table
    };

createPath:{[datep]
    .Q.dd[dbname;(datep;`t;`)]
    };

enumTab:{[t]
    .Q.en[dbname;t]
    };

setInParallel:{[datep]
    enummedTabs:{enumTab createTab x} each datep;
    paths:createPath each datep;
    .[set;] peach flip (paths;enummedTabs)
    };

现在,您可以针对日期列表运行setInParallel

bash> q code.q -s 5
q)setInParallel .z.d-til 5
`:partdb/2018.04.25/t/`:partdb/2018.04.24/t/`:partdb/2018.04.23/t/`..

需要注意的一些注意事项:

  • 将表格设置为日期分区时,您不需要日期列。你当然可以拥有它,但当q映射到日期目录时它就变成了虚拟日期列,所以不需要它。因此,为什么我在创建时删除日期列。

  • .Q.dd是一个非常有用的创建路径的函数(比构建字符串更容易)。请注意我如何从根hdb,日期参数,表名和前导`创建路径(在创建路径时表示前导/(即dir))

  • 我从createTab函数中获取的newpart函数。您将输入的日期转换为一个月,然后返回到日期以获取该月的第一个日期。这可能是你正在寻找的,但只是因为你知道你永远不能设置除了本月的第一天之外的日期,即使你输入的参数是2018.01.02例如。

HTH, 肖恩

答案 1 :(得分:1)

你可以做到这一点,但它依赖于你在减记之前知道完整的可能符号世界。如果看起来像是某种帐户ID,那么在我保存之前你可能知道所有可能的值。在这种情况下,您可以先在主线程中创建sym向量,然后将写下来,使用$运算符执行枚举,该运算符不会更新全局变量。例如:

User.findOne({
  where: { id: req.params.id },
  attributes: ['id', 'user_name'],
  include: [
    { model: Post,
      attributes: ['id', 'created_at'],
      include: {
        model: PostTitles,
        attributes: ['title_id',[Sequelize.literal('COUNT(DISTINCT(title_id))'), 'totalcount']]
      }
    }
  ]
})

请注意,在这种情况下,要枚举的列名称是硬编码的 - 在更灵活的实现中,您可以使用npertable:100000; dbname:`:partdb; sym:`C123`C132`C321`C121`C131; //create sym vector (` sv dbname,`sym) set sym; //save sym vector in db newpart:{[date] firstofmonth:"d"$"m"$date; table:([]date:npertable?firstofmonth+til 25;acc:npertable?`C123`C132`C321`C121`C131;c:npertable?til 100); table:`date`acc xasc table; partname:`$(("/" sv (string dbname;string "m"$date;enlist "t")),enlist "/"); table:@[table;`acc;`sym$]; //enumerate acc column with hardcoded column name partname set table; //table already enumerated, don't use .Q.en }; newpart peach 2018.03.01 2018.04.01 2018.05.01 的某些修改来标识需要枚举的列,并自动为所有必需的列执行此操作。 / p>

当然,如果在您的真实.Q.en函数中,有可能将新的值添加到newpart字段,则会产生更大的问题。理想情况下,您可能希望在执行acc之前了解主线程中的任何新值,因此您可以向peach向量添加任何新值。

答案 2 :(得分:1)

编辑 - 发现Kx的一篇较旧的在线帖子表明我的方法不是一个好主意:"一个句柄不能在线程之间同时使用,因为套接字描述符周围没有锁定"。但是我会把它留在这里供参考

有可能(尽管我没有经过彻底的测试)设置一个单独的编写程序来处理写作,然后你将数据发送到编写器,编写器将依次进行枚举和编写。有点像:

{neg[h](`runThisFunc;onThisData);(neg h)[]} peach 1 2

我相信需要冲洗。较新版本的kdb可以允许通过IPC发送大量数据,因此该部分不应成为问题。

我再也没有在制作环境中做过这件事,但从理论上讲,我无法想到你为什么不能这样做。