【问题标题】:compress java strings (urls)压缩java字符串(url)
【发布时间】:2012-04-13 13:12:46
【问题描述】:

我有很多网址要处理。我将其中大约 20'000'000 个存储在哈希集中。这会导致一些内存问题。

我尝试创建一个压缩字符串类:

import java.io.*;//file writer
import java.util.*;
import java.util.zip.*;

class CompressedString2 implements Serializable{
    private int originalSize;
    private byte[] cstring;



    public CompressedString2 (){
        compress("");
    }


    public CompressedString2 (String string){
        compress(string);
    }


    public void compress(String str){
        try {
            byte[] bytes = str.getBytes("UTF-8");
            originalSize = bytes.length;

            ByteArrayOutputStream deflatedBytes = new ByteArrayOutputStream();
            DeflaterOutputStream dos = new DeflaterOutputStream(deflatedBytes,new Deflater(Deflater.DEFAULT_COMPRESSION));
            dos.write(bytes);
            dos.finish();
            cstring=deflatedBytes.toByteArray();
        }catch(Exception e){e.printStackTrace();}

    }


    public String decompress() throws Exception{
        String result="";
        try{
            ByteArrayOutputStream deflatedBytes=new ByteArrayOutputStream();
            deflatedBytes.write(cstring);
            deflatedBytes.close();


            InflaterInputStream iis = new InflaterInputStream(new ByteArrayInputStream(deflatedBytes.toByteArray()));
            byte[] inflatedBytes = new byte[originalSize];
            iis.read(inflatedBytes);
            result= new String(inflatedBytes, "UTF-8");
        }catch(Exception e){e.printStackTrace();}
        return result;
    }
}

但事实上,当我用这样的东西存储它们时:

HashSet<String> urlStr=new HashSet<String>();
HashSet<CompressedString> urlComp=new HashSet<CompressedString>();


        String filePath=new String();

            filePath=args[0];

        int num=0;

        try{
            BufferedReader br = new BufferedReader(new FileReader(filePath));

            String line = br.readLine();
            while (line != null) {

                num++;
                urlStr.add(line);
                urlComp.add(new CompressedString(line));

            line = br.readLine();
            }
        } catch(Exception e){
        System.out.println("fehler..:");
            e.printStackTrace();
        }

ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream("testDeflator_rawurls.obj"));
oos1.writeObject(urlStr);
ObjectOutputStream oos4 = new ObjectOutputStream(new FileOutputStream("testDeflator_compressed2.obj"));
oos4.writeObject(urlComp);

“压缩”的网址更大...

有人知道如何成功压缩网址吗?

【问题讨论】:

  • 之前您将 url 存储为字符串,现在您将它们存储为 CompressedString 对象。当然它们会更大,当 url 本身被压缩时,你的对象会比字符串占用更多的内存。
  • @jzworkman -- 我不同意; CompressedString 包含一个数组和一个 int,这实际上比 String 的成员

标签: java string url compression web-crawler


【解决方案1】:

好吧,如果它们在一个集合中,那么您所能做的就是添加/删除/查找。您也可以在“字符森林”上执行这些操作,它可能是更紧凑的表示。我在想一棵节点树,每个节点都有一个角色,彼此链接。森林的根将包含“h”、“f”等。在“h”节点下将是一个“t”节点,在该节点下是另一个“t”,在该节点下是一个“p”,等等。“f”节点将有“t”和“i”子节点。最终树会分叉,但在根部附近可能会有很多共享。然后你就在森林里走走看看是否有 URL。

我想一个节点需要一个布尔成员来指示集合中的一个 URL 在那里终止,一个成员来保存字符,以及一个指向其他节点的链接数组。

【讨论】:

  • 这可能很快,具体取决于实现,(预期 O(n) 来遍历 URL,其中 n 是 url 的长度)
  • 我可能会尝试实现这样的东西,只是为了好玩!
  • +1。根据 URL,“字符串森林”可能效果更好(就查找时间和存储开销而言)。像“http://”和“ftp://”这样的词根,后面跟着孩子在每个“/”处分裂。
【解决方案2】:

您是否考虑过不同的方法?哈希集中的 2000 万个字符串非常多。您可以将它们存储在数据库中并从那里进行处理吗?

【讨论】:

    【解决方案3】:

    不过,一般来说,为了使压缩工作良好,字符串必须更长,因为它基于所述字符串中的模式工作。

    【讨论】:

      【解决方案4】:

      短字符串可能不会压缩到小于未压缩的字符串。您是否尝试过-XX:+UseCompressedString,它在某些 Java 6 版本中默认开启。

      【讨论】:

        【解决方案5】:

        您可以一次压缩 n 个 URL,其中 n 可能是 10 到 100 个。这将使压缩器以重复字符串和倾斜字符概率分布的方式工作。缺点是每次访问都必须解压缩 10 到 100 个 URL。因此,在实现之后,改变 n 以在内存使用和速度之间进行权衡,然后选择你喜欢的折衷方案。

        【讨论】:

          【解决方案6】:

          如果您的许多网址都有一个共同的基础,例如http://www.mysite.com/,那么您应该考虑使用Ropes (project page),以便每个字符串的第一部分表示一次。

          另见this wikipedia page

          【讨论】:

            【解决方案7】:

            你可以使用 tinyurl 来减少长度然后存储它。
            你可以找到java实用程序类到微小的URL here

            【讨论】:

              【解决方案8】:

              例如,将 100 个链接连接在一起(由特殊字符分隔)并尝试将它们压缩成一个 CompressedString 怎么样? 压缩可能需要最小长度才能有效。 CompressedString 类可以恢复 Collection 中的 100 个字符串。

              【讨论】:

                【解决方案9】:

                由于包装类的额外开销,压缩 URL 不一定会为您节省任何内存。另一种方法是使用前缀映射来缩短 URL。但是,如果使用包装类,则必须实现 hashCodeequals 方法。没有它们,哈希集将无法按预期工作(允许重复)。对于CompressedString2,这些可以实现为:

                @Override
                public int hashCode() {
                    return Arrays.hashCode(cstring);
                }
                
                public boolean equals(Object other){
                    if(other instanceof CompressedString){
                        return Arrays.equals(cstring, ((CompressedString) other).cstring);
                    }
                    return false;
                }
                

                另一个可以显着减少内存占用的方法是使用 Trove 的 THashSet。由于您知道 URL 的大致数量,您还可以增加负载因子并设置哈希集的初始大小,这将为您节省大量重新哈希并让您更有效地使用分配的空间。

                【讨论】:

                  猜你喜欢
                  • 2012-05-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-10-15
                  • 2021-04-13
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-01-06
                  相关资源
                  最近更新 更多