间隔树实现在序列化后占用大量文件空间

时间:2017-08-16 22:26:21

标签: java algorithm optimization serialization tree

我有一个文本文件,其中包含IPv6范围以及范围所属的ISP(范围不重叠)。一些样本(假)行如下:

2010:258:0:0:0:0:0:0;2010:258:ffff:ffff:ffff:ffff:ffff:ffff;ISP_1;
2010:260:0:0:0:0:0:0;2010:260:ffff:ffff:ffff:ffff:ffff:ffff;ISP_2;
2010:268:0:0:0:0:0:0;2010:268:ffff:ffff:ffff:ffff:ffff:ffff;ISP_3;

我已经使用了这个文本文件并创建了一个Interval Tree,这样我就可以快速查找特定IP所属的ISP。 Interval树中的每个节点都具有以下结构:

public class Node implements Serializable {
    Range nodeRange;

    IntervalTreeNode left;
    IntervalTreeNode right;

    UnsignedLong128 centerValue;

}

以下是Range

public abstract class Range implements Comparable<Range>, Serializable {

    UnsignedLong128 start;
    UnsignedLong128 end;
    boolean sortAccordingToStart;
}

其中UnsignedLong128是我写的自定义Long类,长度为128位:

public class UnsignedLong128 implements Comparable<UnsignedLong128>, Serializable {

    Long major;
    Long minor;
}

问题是,如果我将树序列化并将树写入文件,该文件的大小比原始文本文件大。这是一个例子:我有一个包含19860范围行的文本文件,该文本文件的大小为1.7 MB。当我基于它创建Interval Tree并将该树写入文件(通过Java的序列化)时,生成的文件的大小为15.7 MB ,即使它存储相同的信息。是的,树的节点数量是文本文件中行数的两倍(我正在生成的树是平衡的),这仍然不能证明文件大小增加太多。

那么导致这个文件大小增长的原因是什么?我怎样才能减少它?

2 个答案:

答案 0 :(得分:1)

Java序列化会产生很多开销,如果你用文本编辑器查看文件,你可能会看到它。

由于范围不重叠,您可以将数据保持在排序顺序(比较两个范围,比较它们的起点或终点),并使用二进制搜索来查找匹配项。然后你只需序列化一组结构。您可能会发现Java序列化的开销较小,您有一个大型阵列或三个大型阵列,包含起点,终点和ISP ID,或者您可以自己读取和写入数据。

您还可以调查readResolve()和writeReplace()

答案 1 :(得分:0)

您可以实现Externalizable,它允许您在保持Serializable框架的同时自定义序列化。它相当简单,你需要每场和每个方向一行。 Serializable有一些开销,因为每个字段可能包含null或其类型的子类的实例,但您通常知道它不会发生。

我不确定,但我想Serializable默认使用UTF-16,这是快速而简单的,就像Java内部所做的那样(或者像Java 9那样做)可以做得更好),但它为你的纯ASCII浪费了两倍(使用UTF-8很好)。看起来你用数字替换了字符串,所以它可能没什么帮助。

你的UnsignedLong128在记忆中也很浪费。将Long替换为long。不知道,它对序列化数据大小有多大帮助,但是你节省了大量的RAM(并获得了一些速度)。