有没有更好的方法在Java集合对象上实现有价值的压缩量?

时间:2015-09-09 12:33:12

标签: java performance collections compression gzip

我目前正在寻找不同的替代方案来改善现有Web应用程序的搜索操作的性能。我试图找出现有系统压缩可能的最大改进,然后再考虑不同的替代方案。

在现有系统中,使用内部和外部数据资源来制定响应于用户搜索而返回的结果集。结果集由嵌套的Java集合对象组成。我想压缩和传输对象并在需要时解压缩它们。我们想要压缩的数据是多种多样的,从浮动向量到字符串到日期。

我已经尝试过Java实用程序来压缩和扩展集合对象。我尝试了下面的代码块,试图检查Java压缩如何帮助减少结果集大小,以及它是否会改善网络上的数据传输。我使用了基于Gzip的压缩。

package com.soft.java.Objectcompress;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 
 * The Class ObjectCompressionUtil.
 * 
 * @param <T> the generic type of the serializable object to be compressed
 */
public class ObjectCompressionUtil<T extends Serializable> {

    /**
     * The compressObject(final T objectToCompress) takes the object 
     * to compress and returns the compressed object as byte array.
     * 
     * @param objectToCompress the object to compress
     * @return the compressed object as byte array
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public byte[] compressObject(final T objectToCompress) throws IOException {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        /*Create a new GZIPOutputStream with a default buffer size.*/
        final GZIPOutputStream gz = new GZIPOutputStream(baos);
        /*Create an ObjectOutputStream that writes to the specified GZIPOutputStream.*/ 
        final ObjectOutputStream oos = new ObjectOutputStream(gz);

        try {
          /*Writes the specified object to be compressed to the ObjectOutputStream and flush it, using writeObject(Object obj)*/
            oos.writeObject(objectToCompress);
          /*flush() API methods of ObjectOutputStream*/
            oos.flush();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        /*Closes both the GZIPOutputStream and the ObjectOutputStream, using their close() API methods.*/
        finally {
            oos.close();
        }

        byte[] bytes = baos.toByteArray();

        return bytes;
    }

    /**
     * The expandObject(final T objectToExpand, final InputStream instream) method takes 
     * the object to expand and an InputStream and returns the expanded object.
     * 
     * @param objectToExpand the object to expand
     * @param instream the input stream
     * @return the expanded object
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws ClassNotFoundException the class not found exception
     */
    public T expandObject(byte[] objectToExpand) throws IOException,ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(objectToExpand);
      /*Creates a new GZIPInputStream with a default buffer size.*/
        final GZIPInputStream gs = new GZIPInputStream(bais);
      /*Creates an ObjectInputStream that reads from the specified GZIPInputStream.*/
        final ObjectInputStream ois = new ObjectInputStream(gs);

        /*Reads the object to expand from the ObjectInputStream, with readObject() API method of ObjectInputStream.*/
        try {
            @SuppressWarnings("unchecked")
            T expandedObject = (T) ois.readObject();
            //MyObject myObj1 = (MyObject) objectIn.readObject();

            /*Returns the expanded object*/
            return expandedObject;
        } finally {
            /*Closes both the GZIPInputStream and the ObjectInputStream, using their close() API methods.*/
            gs.close();
            ois.close();
            bais.close();
        }
    }
}

我也在这个论坛上检查了类似的问题,但有一些但没有明确回答我的问题。所以我想发布这个问题。

是否有更好的方法可以实现结果集的有效压缩量?我认为压缩的容易程度和减压速度是最重要的因素和最佳压缩比作为第二选择。

使用的流类型/组合是否会影响预期结果?

是否有其他自定义/第三方压缩算法可以提供更好的性能改进?

更新 - 一些可能的潜在客户相关问题

  • Java中的searilized对象压缩通常不是很好。一个 Java对象有很多不需要的附加信息。如果你 有数以百万计的对象,你有这个开销数百万次。

  • 如果可能,将对象写入数据库,数据存储区或文件 使用缓存将常用对象保存在内存中。

  • 如果大小很重要,您可能希望进行简单的序列化 你自己。使用ObjectOutputStream可能不是答案。 这是因为ObjectOutputStream有很大的开销 小物件要大得多。流格式包括很多 与类型相关的元数据。如果你正在序列化小对象,那么 强制元数据将使压缩算法难以实现 “收支平衡”,即使您实现自定义序列化方法。

  • 使用DataOutputStream添加最少(或没有)类型信息 会给出更好的结果。为了更好的压缩,您可能需要 查看正在压缩的数据的属性。混合 数据通常不是使用通用目的可压缩的 压缩算法。

  • 使用DeflatorOutputStream和InflatorInputStream 比替代品更简单/更快/更小。原因是这样的 较小的是它只是压缩,而替代品增加 文件格式扩展名,如CRC校验和标题。

  • 压缩所有数据可能不是一件好事。比如一个 序列化的空数组可能是几十个字节长的名称 底层类是在序列化数据流中。也是最多的 压缩算法旨在消除大型冗余 数据块。在您可能拥有的中小型Java对象上 很少或根本没有收获。

  • Java ZIP还提供了另一种选择。 Java支持ZipStream。所有你 需要是将对象序列化为字节数组,然后压缩它。

  • 使用ByteArrayOutputStream,DataStream,ZipOutputStream。但一些 认为zip DEFLATE算法相当陈旧并使用了算法 在gzip,bzip2或7zip / lzma中可能更有效率。你会得到 使用bzip或tar.gz进行更好的压缩。 Apache Compress是 如果您愿意接受,最简单的方法是使用这些格式 额外的JAR依赖。

1 个答案:

答案 0 :(得分:1)

您可以查看LZ4的压缩效果不佳,但解压缩速度比gzip快得多。