我有一个问题需要解决,包括阅读大文件,我有一个大致的想法如何处理它,但我希望看到它可能有更好的方法。
问题如下:我有几个巨大的磁盘文件(每个64GB
)填充了每个2.5KB
的记录(总共大约25,000,000
个记录)。除其他字段外,每条记录还包含时间戳和 isValid 标志,指示时间戳是否有效。当用户输入时间跨度时,我需要返回时间戳为指定范围的所有记录。
数据的布局使得对于标记为“有效”的所有记录,时间戳单调增加。根本不应该考虑无效的记录。所以,这就是文件通常的样子(尽管范围要大得多):
a[0] = { Time=11, IsValid = true };
a[1] = { Time=12, IsValid = true };
a[2] = { Time=13, IsValid = true };
a[3] = { Time=401, IsValid = false }; // <-- should be ignored
a[4] = { Time=570, IsValid = false }; // <-- should be ignored
a[5] = { Time=16, IsValid = true };
a[6] = { Time=23, IsValid = true }; // <-- time-to-index offset changed
a[7] = { Time=24, IsValid = true };
a[8] = { Time=25, IsValid = true };
a[9] = { Time=26, IsValid = true };
a[10] = { Time=40, IsValid = true }; // <-- time-to-index offset changed
a[11] = { Time=41, IsValid = true };
a[12] = { Time=700, IsValid = false }; // <-- should be ignored
a[13] = { Time=43, IsValid = true };
如果时间戳和计数器之间的偏移量是常量,那么寻找第一条记录将是O(1)
操作(我只是跳转到索引)。既然不是,我正在寻找一种不同的方法(快速)找到这些信息。
一种方法可能是修改后的二进制搜索,但我不完全确定如何处理更大的无效记录块。我想我也可以创建一个“索引”来加速查找,但由于会有很多像这样的大文件,并且提取的数据大小会比整个文件小得多,我不想遍历这些文件中的每一个,按记录记录,以生成索引。我在想,当构建索引时,二进制搜索也会有所帮助。
更不用说我不确定索引的最佳结构是什么。平衡二叉树?
答案 0 :(得分:2)
您可以使用修改后的二进制搜索。我们的想法是通常进行二进制搜索以找出下限和上限,然后在有效的条目之间返回。
修改位于当前条目无效的部分。在这种情况下,您必须找出具有有效条目的两个端点。 例如,如果中点是3,
a[0] = { Time=11, IsValid = true };
a[1] = { Time=12, IsValid = true };
a[2] = { Time=401, IsValid = false };
a[3] = { Time=570, IsValid = false }; // <-- Mid point.
a[4] = { Time=571, IsValid = false };
a[5] = { Time=16, IsValid = true };
a[6] = { Time=23, IsValid = true };
在上述情况下,算法将返回两个点a [1]和[5]。现在算法将决定二分搜索下半部分或上半部分。
答案 1 :(得分:1)
这样的时候,使用别人的数据库代码开始看起来像个好主意,
无论如何,你需要摸索,直到你找到有效数据的开头,然后阅读,直到你到达终点,
首先拍摄底池并相应地移动标记,与普通的二分搜索相同 除非您点击无效记录时开始搜索有效记录,只需从猜测中向前读取就像任何事情一样好
在文件上运行维护任务以将有效时间戳替换为有效时间戳或者维护外部索引可能是值得的,
答案 2 :(得分:1)
您可以在二进制搜索中带来一些随机性。实际上,随机算法对大数据集表现良好。
答案 3 :(得分:1)
听起来像修改后的二进制搜索可能是一个很好的解决方案。如果大块无效记录是一个问题,你可以通过跳过指数增加大小的块来处理它们,例如1,2,4,8 ......如果这使你超过当前括号的末尾,则返回到支架的末端并以1,2,4,8的步长向后跳,...以找到合理靠近中心的有效记录。