在之前的一些帖子中,我提出了一些关于java中自定义哈希映射/表编码的问题。现在因为我无法解决它而且可能忘记正确提及我真正想要的东西,我总结所有这些以使其清晰和准确。
我要做的是:
我正在尝试为我们的服务器编写代码,我必须通过URL找到用户访问类型。
现在,我有1110万个网址(约)。
那么,我们做了什么,
1)将数据库划分为1.1亿个Url的10个部分。 2)使用并行数组构建HashMap,其键是URL的一部分(表示为LONG),值是URL的其他部分(表示为INT) - 键可以有多个值。
3)然后在系统启动时,每天在HashMap中搜索一些其他URL(一天内保存的数百万个URL)。
你有什么尝试:
1)我尝试了很多NoSQL数据库,但是我们发现它们不太适合我们的目的。
2)我为此目的构建了custom hashmap(使用两个并行数组)。
那么,问题是什么:
当系统启动时,我们必须加载每个数据库的哈希表,并搜索数百万个网址:
现在,问题是,
1)虽然HashTable性能非常好,但是在加载HashTable时代码需要更多时间(我们使用文件通道和内存映射缓冲区加载它需要20秒来加载HashTable --220万条入口 - 作为加载因子是0.5,we found it most faster)
所以,我们花时间:( HashTable Load + HashTable Search)* DB =(5 + 20)* 10 = 250秒。对我们来说这是非常昂贵的,并且大部分时间(250秒中的200秒)都用于加载哈希表。
你有没有想过其他方式:
一种方法可以是:
不用担心加载和存储,并使用内存映射缓冲区将缓存留给操作系统。但是,由于我必须搜索数百万个密钥,因此它的性能会比上述情况更差。
由于我们发现HashTable性能不错但加载时间很长,我们认为会以另一种方式切断它:
1)创建一个大小为Integer_MAX(my own custom linked list)的链接列表数组。
2)将值(int)插入到编号为密钥编号的链接列表中(我们将密钥大小减小为INT)。
3)因此,我们只需要将链接列表存储到磁盘中。
现在,问题是,创建如此数量的链接列表需要花费大量时间,如果数据分布不均,则创建如此大量的链接列表没有任何意义。
那么,您的要求是什么:
仅仅是我的要求:
1)具有多个值插入和搜索的键。寻找不错的搜索性能。 2)快速加载(特别)到内存中。
(键是64位INT,值是32位INT,一个键最多可以有2-3个值。我们也可以使我们的键32位但会产生更多的冲突,但如果我们可以制造,我们可以接受它更好。)
任何人都可以帮助我,如何解决这个或任何评论如何解决这个问题?
感谢。
注意:
1)根据之前的Stack Overflow建议,无法预读磁盘缓存数据,因为系统启动时我们的应用程序将开始工作,并在系统启动的第二天开始工作。
2)我们还没有发现NoSQL db的扩展性很好,因为我们的要求很简单(意味着只插入散列表键值,加载和搜索(检索值))。
3)由于我们的应用程序是小型项目的一部分,并且应用于小型校园,我认为没有人会为我购买SSD磁盘。这是我的局限。
4)我们也使用Guava / Trove,但他们也无法在16 GB中存储如此大量的数据(我们使用的是32 GB的ubuntu服务器。)
答案 0 :(得分:0)
如果您需要快速访问1110万个数据项,那么散列是最佳选择。但是不要重新发明轮子,使用类似的东西:
答案 1 :(得分:0)
在我看来(如果我理解你的问题正确),你试图以一种错综复杂的方式解决问题。
我的意思是你试图预加载的数据开始时很大(比方说2.2亿* 64~14GB)。你正试图为此记忆地图等。
我认为这是通过在不同机器中分配负载来解决的典型问题。即您应该尝试找出已加载地图特定部分的相应计算机的索引,而不是尝试找到链接列表索引,并从那里获取该计算机的值(每台计算机都加载了此数据库的一部分)地图,你从地图的适当部分获得数据,即每次机器。)
也许我离开这里,但我也怀疑你使用的是32位机器
因此,如果您必须继续使用单机架构,并且在经济上不可能改进您的硬件(64位机器以及更多RAM或SSD,正如您所指出的那样),我认为您无法做出任何显着的改进。
答案 2 :(得分:0)
我真的不明白您将数据存储在磁盘上的形式。如果您存储的内容由网址和一些数字组成,您可以通过压缩数据来加速从磁盘加载(除非您已经这样做了)。
创建一个在加载时解压缩的多线程加载器可能会给你带来很大的提升。