kdb q-有效计数平面文件中的表

时间:2018-10-05 07:21:39

标签: kdb

我有很多表存储在平面文件中(在名为basepath的目录中),我想检查它们的行数。我现在能做到的最好的是:

c:([] filename:system "ls ",basepath; 
      tablesize:count each get each hsym `$basepath,/:system "ls ",basepath)

它将每个表完全加载到内存中,然后执行计数(这很慢)。将其保存为扩展表是使其更快的唯一方法(因为我只加载1列并对其进行计数)还是q上有技巧可以使用?

感谢您的帮助

4 个答案:

答案 0 :(得分:4)

如果将basepath定义为存储所有平面表的目录的路径字符串,则可以创建行计数字典,如下所示:

q)cnt:{count get hsym x}
q)filename:key hsym `$basepath
q)filename!cnt each filename
t| 2
g| 3

这是我在basepath目录中保存平面表t和g的地方。这使您不必使用效率通常较低的system命令。 函数cnt采用每个平面表的路径(作为符号)并返回行数,而不将其保存到内存中。

如果您可以控制将这些文件保存下来的过程,那么最好的解决方案是添加一个额外的步骤,即在保存原始数据的同时将行计数的元信息保存在单独的某个位置。这样一来,您可以快速从该文件访问表的大小,而不必每次都读取完整的tbale。

但是,请注意,为避免完全将它们拉入内存,您将不得不使用read1并查看二进制数据的标头。正如您所说,最好另存为展开的表格并读入一列。

更新:我不建议这样做,强烈建议您执行上述操作,但是出于好奇,在考虑使用read1之后,以下示例说明了一个骇人解决方案的外观:

f:{
  b:read1(y;0;x);
  if[not 0x62630b~b[2 4 5];'`$"not a table"];
  cc:first first((),"i";(),4)1:b 7+til 4;
  if[null ce:first where cc=sums 0x0=11 _ b;:.z.s[x*2;y]];
  c:`$"\000" vs "c"$b[11+til ce];
  n:first first((),"i";(),4)1:b[(20+ce)+til 4];
  :`columns`rows!(c;n);
  }[2000]

q二进制文件格式未在任何地方记录,找出它的唯一方法是保存不同的内容并查看字节如何变化。各个版本之间也可能会发生变化-以上内容是针对3.5编写的,可能仅对3.0-3.5有效,而对最新的3.6版本或任何2.X无效。

给定的代码以下列方式工作:

  1. 从文件开头读取一个块

  2. 验证它看起来像一个平坦的无键表(带有符号[11]键的字典[99]的翻转[98])

  3. 将列列表中的符号计数读取为小端4字节int
  4. 在空终止的字符串中扫描那么多零字节
  5. 如果列太多或太冗长,以至于我们没有它们 全部都在此块中,它将使块的大小加倍,然后重试
  6. 将字符串转换为符号
  7. 使用从列列表末尾得到的偏移量,略过 列混合列表的更多标题
  8. 然后从第一列的标题中读取计数

希望这能回答您的问题!

答案 1 :(得分:2)

从试验二进制文件开始,当您保存平面文件时,表计数似乎被保存为二进制文件的一部分,在初始对象类型和列标题之后占用了4个字节,这随表的不同而不同。桌子。

public float axisDir;

...

else if (spanCamera == 0 && axisDir == 1)
{
    Camera.main.transform.RotateAround(rb.position, Vector3.up, -1 * Time.fixedDeltaTime * spanSpeed);
}

这应该有助于您了解Fiona发布的功能。

二进制文件保存在低位字节序中,这意味着最高有效字节是最右边的数字-用十进制表示数字100会得到001,其中100(最高有效)在右边,然后是10s最后是1s在二进制文件中,每两位两位是一个字节。

您可以使用`:test set ([]a:1 2 3;b:4 5 6;c:7 8 9;aa:10 11 12;bb:13 14 15) q)read1 `:test 0xff016200630b000500000061006200630061610062620000000500000009000300000 0 7 11 31 bytes | example | meaning --------------------------------------------------------------------------------------- 0 - 5 | 0xff016200630b0 | object is a flat table 7 - 11 | 0x05000000 | number of columns (5) 12- 22 | 0x6100620063006161006262 | one byte for the ascii values of column "a" and "b" in hex followed by the one byte separator 23 - 30 | 0x0000050000000900 | 8 bytes that can be skipped 31 - 34 | 0x0300000 | 4 bytes for row count of first column (3) 读取二进制文件的内容,列表中的其他参数指定偏移量-从何处开始读取以及要读取多少字节。在我们的例子中,我们要从字节31开始读取4个字节,指定输出应为整数并将输入切成4个字节的单独块。

1:

将little-endian字节转换为long可以得到行数。由于只需读取4个字节而不是整个文件,因此速度要快得多。

对于具有10000行和2列的表,差别不大:

q)first first (enlist "i";enlist 4)1:(`:test;31;4)
3i

对于具有100m行和2列的表:

q)\t 0x0 sv reverse first (enlist "x";enlist 1)1:(`:test10000;31;4)
0
q)\t count get `:test10000
0

如果您有一张张开的表,则可以从字节9-13读取其中一列中的元素数量,就像这样,假设该列是一个简单列表:

q)\t 0x0 sv reverse first (enlist "x";enlist 1)1:(`:test10m;31;4)
0
q)\t count get `:test10m
2023

您可以在https://code.kx.com/q/ref/filenumbers/#1-binary-files

上阅读有关从二进制文件读取内容的更多信息。

答案 2 :(得分:1)

您可以使用以下方法来提高当前的效率

  

计数表:{计数每个获取每个hsym`$ basepath}

通过不包括额外读入的数据以及当前正在执行的联接,这将提高计数速度。您是正确的,尽管如果保存的表张开了,您只需要读入一栏中就可以提高效率。

答案 3 :(得分:0)

如果您的表未压缩地存储,则可能会遇到一些麻烦,您可以对文件标题中的read1进行处理,直到找到第一列标题为止。

但是v hacky:-(

您有责任将其保存下来吗?您可以像现在一样保持运行状态吗?