在 kdb 中更新磁盘上的序列化 table

Update a serialized table on disk in kdb

我在磁盘上有一个序列化的 table,我想根据条件对其进行更新。 这样做的一种方法是将 table 加载到内存中,更新它,然后在磁盘上再次序列化它。 例如:

q)`:file set ([] id:10 20; l1:("Blue hor";"Antop"); l2:("Malad"; "KC"); pcd:("NCD";"FRB") );
q)t:get `:file;
q)update l1:enlist "Chin", l2:enlist "Gor" from `t where id=10;
q)`:file set t;

我尝试直接在磁盘上更新 table 但收到类型错误:

q)update l1:enlist "Chin", l2:enlist "Gor" from `:file where id=10
'type
  [0]  update l1:enlist "Chin", l2:enlist "Gor" from `:file where id=10

有没有一种方法可以直接在磁盘上更新序列化的 table?(在一种情况下,我们没有足够的主内存来加载序列化的 table)

如果将 table 保存为一个平面文件,则必须加载整个 table,更新然后写入,需要足够的内存来容纳完整的 table. 为避免这种情况,您可以通过在文件路径中添加尾随 / 来展开 table,即

`:file/ set ([] id:10 20; l1:("Blue hor";"Antop"); l2:("Malad"; "KC"); pcd:("NCD";"FRB") );

如果存在符号列,则需要使用 .Q.en.

对其进行枚举

这将垂直拆分 table 并将您的列作为单独的文件保存在名为 file 的目录下。将列保存为单独的文件允许您只加载所需的列而不是整个 table,从而减少内存需求。您只需在 select 查询中指定所需的列。

https://code.kx.com/q4m3/14_Introduction_to_Kdb%2B/#142-splayed-tables

您可以通过分区进一步水平拆分数据,如果个别列太大,则再次产生更小的子集。

https://code.kx.com/q4m3/14_Introduction_to_Kdb%2B/#143-partitioned-tables

当你运行

get`:splayedTable

此内存映射 table 假设您的列是可映射的,而不是将其复制到内存中,如 .Q.w[]

所示

你可以做到

tab:update l1:enlist "Chin", l2:enlist "Gor" from (select id, l1,l2 from get`:file) where id=10
`:file/l1 set tab`l1
`:file/l2 set tab`l2

如果仅将查询所需的列加载到内存中仍然太大,您可以一次加载一个。首先加载 id 并找到所需的索引(其中 id=10),从内存中删除 id,加载 l1 并使用索引进行修改,

@[get`:file/l1;indicies;:;enlist"Chin"]

写下来,然后从记忆中删除。然后对 l2 做同样的事情。这样你在内存中最多只有一列。理想情况下,您的 table 将被适当分区,以便您可以将数据保存在内存中。

您也可以直接更新磁盘上的向量,这样就避免了重新写入整个文件,例如,

ind:exec i from get`:file where id=10

@[`:file/l1;ind;:;enlist"Chin"]

虽然下面提到的文件有一些限制 link https://code.kx.com/q/ref/amend/#functional-amend