我正在寻找一个快速过滤器,它将在标准输入上获取文本文件,将每行散列到第一个制表符,然后根据散列值将该行放入不同的文件中(对某些文件数取模)。例如,类似这样的内容:
$ cat > foo
a 1
b 2
c 3
d 4
^D
$ hashit -o bar -n2 < foo
$ cat bar.0
b 2
$ cat bar.1
a 1
c 3
d 4
哈希函数在调用之间必须保持一致。
这有点像标准split
实用程序,但我想根据行的散列内容进行拆分,而不仅仅是每个组件的行数。
答案1
因此你需要速度。这种速度可能需要 C(尽管 Perl 可能经过充分优化)。不幸的是,在 C 中手动缓冲很复杂,而在 Perl/Python/Java 中自动缓冲很慢。
因此,假设您可以在 64 位系统上运行并且处理的数据不会超过几十亿 TB,那么有一种可能的路径可以实现最不痛苦的 C 解决方案:
- 打开输出文件
mmap
整个输入文件- 记住当前位置
- 扫描直到找到一个制表符,将 ASCII 值乘以文件数的模(可能先从每个字符中减去 31),得到代码
- 扫描直到换行符或 EOF
- 内容是
mmap
'd。这是一个数组。从起始位置到新行写入输出文件。使用write(2)
、 notfputs
或类似的东西,以使 C 库的缓冲不受影响。 - 返回 3 直到文件完成
当您到达末尾时,友好的内核将负责将内容分页到内存中,因此您不必自己进行缓冲。
请注意,内存映射 IO 并不一定比批量 I/O 调用更快read
,write
但实际上确实如此,但它会使代码比自己尝试编写缓冲逻辑简单得多。基于这种通用设计的 Python 解决方案可能也足够快。
答案2
您可以编写一个 python 脚本来执行此操作...因为您说它需要快速,所以 CRC 可能是哈希函数的合理选择。
尝试这样的操作:
import fileinput
import binascii
for line in fileinput.input():
modulo = binascii.crc32(line.split()[0]) % splits
该变量splits
应设置为您希望将输入拆分成的文件数。您可以使用该变量modulo
来构造应放置每行的文件名。
答案3
这个问题(看起来有点儿像家庭作业;)听起来像是awk
awk '{ print > "FilePrefix."$1%YourModValueHere }'
例如
awk '{ print > "bar."$1%3 }'
更新以修复误解:
1) define outputfilePrefix and modoloValue
2) load inputfile linewise as positional parameters
3) iterate over all entries in the first column
a) calculate CRC (cksum), and modolo CRC
b) output first positional parameter ($1) to file (prefix.modoloOfCRC )
c) shift positional parameters one to the left (discarding the current line in position 1)
代码:只需在 bash 中输入一行即可
preFix="bar"; modolo=3;IFS=$'\n';set $(cat foo); for i in $(cut -f1 foo);do target=$(( $(echo $i | cksum | cut -d ' ' -f1;) % $modolo ));echo $1 >> $preFix.$target; shift; echo $target; done
更易于理解
1) preFix="bar"; modolo=3;
2) IFS=$'\n';set $(cat foo);
3) for i in $(cut -f1 foo);do
target=$(( $(echo $i | cksum | cut -d ' ' -f1;) % $modolo ));
echo $1 >> $preFix.$target; shift; echo $target;
done
如果你把它放在 shellscript 中,你甚至可以通过 stdin 将文件导入管道(只需稍加修改)
答案4
据我所知,没有标准的实用程序可以做到这一点,并且用 Python 进行简单的实现太慢了。
因此,我在需要它的开源项目中用 C 语言实现了它,夸克。希望这对其他人有用。(我还没有推送,但几天内应该就会推送。)