简介
我们将元组(string,int)
存储在二进制文件中。字符串代表一个单词(没有空格或数字)。为了找到一个单词,我们应用二进制搜索算法,因为我们知道所有元组都是根据单词排序的。
为了存储它,我们使用writeUTF作为字符串,writeInt作为整数。除此之外,我们假设现在没有办法区分元组的开头和结尾,除非事先知道它们。
问题
当我们应用二进制搜索时,我们在文件中得到一个位置(即(a + b)/ 2),我们可以使用Random Access File中的方法读取该位置,即我们可以读取该位置的字节。但是,由于我们可能处于这个词的中间,我们无法知道这些词的开头或结尾。
解决方案
以下是我们提出的两种可能的解决方案,但是,我们正在尝试确定哪一种更节省空间/更快。
方法1:我们考虑将其存储为字符串(使用例如。writeChars或{{3因为在这种情况下,我们可以在元组的末尾插入一个空字符。也就是说,我们可以确定用于序列化数据的方法都不会使用空字符,因为我们存储的信息(数字和数字)具有更高的ASCII值表示。
方法2:我们保持相同的结构,但我们将每个元组与6-8(或更少)字节的随机噪声分开(整个文件中相同)。在这种情况下,我们假设单词具有较低的熵,因此它们不太可能有任何随机性的迹象。即使integer
可能得到与随机噪声中的4个字节完全相同的4个字节,随后的两个字节也不会(很有可能)。
您会推荐以下哪种方法?有没有更好的方法来存储这种信息。注意,我们不能序列化整个文件,然后将其反序列化到内存中,因为它非常大(我们不允许)。
答案 0 :(得分:2)
我认为你正试图优化速度和速度。空间(按此顺序)。
我使用不同的布局,由2个文件构建:
Good
,Hello
,Morning
将显示为GoodHelloMorning
。要迭代数据集,可以直接访问整数/索引文件(recordNum * 8
是记录的字节偏移量),读取整数和字符偏移量,再加上下一条记录的字符偏移量(这是recordNum * 8 + 12
处的4字节整数,然后从您从索引文件中读取的偏移量之间的字符文件中读取字符串。完成!
答案 1 :(得分:0)
它不到200MB。一个单词最多20个字符。
为什么要这么麻烦?除非你在一些受到严格限制的系统上工作,否则将所有内容加载到Map<String, Integer>
并加速几个数量级。
但是,让我们说,我忽略了一些东西,让我们继续。
方法1:我们不是将整数存储为数字,而是将其存储为字符串(使用例如writeChars或writeUTF),因为在这种情况下,我们可以插入一个空字符
你不必像你说的那样说你的话没有数字。因此,您始终可以唯一地解析0124some456word789
之类的内容。
效率取决于分布。您可以赢得4倍(单位数字)或丢失2.5倍(10位数字)。你可以通过使用更高的基数来节省一些东西。但是有字符串的存储空间,它可能占主导地位。
方法2:我们保持相同的结构,但我们将每个元组与6-8(或更少)字节的随机噪声分开(整个文件中相同)。
这太浪费了。在数据字节之间使用四个零可以:
方法3:使用一些黑客,您可以确保该数字不包含零字节(假设它不使用整个范围或用五个字节表示它)。然后就会有一个零字节。
方法4:由于磁盘是按块组织的,因此您应该将数据拆分为4个KiB块。然后,您可以添加一些时间标题,以便您快速访问数据(开始索引第8,16等数据)。应该顺序扫描例如第8和第16块之间的范围,因为它比二进制搜索更简单,更快。