Java 我应该使用哪种数据结构来表示此数据集?

Java 我应该使用哪种数据结构来表示此数据集?,java,hashmap,pyspark,Java,Hashmap,Pyspark,假设我有一个如下的数据集: Screen ID User ID 1 24 2 50 2 80 3 23 5 50 3 60 6 64 . . . . . . 400,000 200,000 我想跟踪每个用户访问的屏幕。我的第一种方法是创建一个哈希映射,其中键是用户ID,值是屏幕

假设我有一个如下的数据集:

Screen ID  User ID
 1          24     
 2          50
 2          80
 3          23
 5          50
 3          60
 6          64
 .          .
 .          .
 .          .
 400,000    200,000

我想跟踪每个用户访问的屏幕。我的第一种方法是创建一个哈希映射,其中键是用户ID,值是屏幕ID。但是,在使用Java时,我会遇到一个OutofMemory错误。是否有高效的数据结构可以处理这些数据量?大约有3000000个键,每个键大约有1000个值。Spark(Python)是实现这一点的方法吗?原始数据集大约有300000000行和2列。

为什么要在内存中存储这么大的数据?最好将其存储在数据库中,只使用所需的数据。因为在任何语言中使用任何数据结构都会消耗几乎相同的内存。

HashMap无法处理您所描述的内容,因为键必须是唯一的。您的场景是复制密钥

如果你想提高内存效率,并且无法访问关系数据库或外部文件,可以考虑使用数组来设计一些东西。 数组的优点是能够存储比对象使用更少数据的原语。集合在存储时总是隐式地将原语转换为其包装类型


您可以让数组索引表示屏幕id,索引中存储的值可以是存储关联用户id的另一个数组或集合。

您使用的是什么数据类型?让我们假设您正在使用

Map<Integer,Integer>
Map
。然后每个条目占用8字节(32位)或16字节(64位)。。让我们计算您的内存消耗:

8*400000=3200000字节/1024=3125千字节/1024=3.05MB

如果是64位数据类型(如Long),则为6.1MB

简言之。。3.05 MB或6 MB对于您的硬件来说不算什么

即使我们计算了300万个条目,最终的内存使用量也是22MB(对于整数条目集)。我不认为OutofMemory异常是由数据大小引起的。检查您的数据类型或 切换到MapDB以获得快速原型(支持堆外内存,请参见下文)

是的,处理300万份申请越来越严重。我们最终的内存使用率为22.8Gig。在这种情况下,你应该考虑。 一种能有效处理这一数量数据的数据存储器。我不认为Java映射(或另一种语言中的向量)是这样一个数据量的好用例 (正如Brain所写,有了这些数据量,您必须增加JVM堆空间或使用MapDB)。还要考虑你的部署;您的产品将需要22 GB的内存 意味着硬件成本高。然后,成本与内存性能之间的问题必须得到平衡。。。我会选择以下其中一种选择:

  • Riak(键值存储,适合您的数据结构)
  • Neo4J(您的数据结构可以作为网络图处理;在这种情况下,屏幕可以与用户有多个关系,反之亦然)
  • 或为快速原型考虑MapDB()
  • 要获得专业且高性能的解决方案,您可以查看SAP Hana(但并非免费)
  • H2()也是一个不错的选择。这是一个SQL内存数据库
使用上述解决方案之一,您还可以持久化和查询数据(无需编码索引、B树等)。我想这就是你想做的, 处理和操作您的数据。最后,只有测试才能显示哪种技术的性能最适合您的需要


OutofMemory异常与java或python无关。您的用例可以在java中毫无问题地实现。

只需查看数据结构即可。您有一个按用户id和屏幕id索引的二维矩阵,其中包含一个布尔值,无论该用户是否访问过它:
visted[screen id,user id]

在每个用户访问几乎每个屏幕的情况下,最佳表示将是一组位。这意味着您需要
400k x 200k
位,大约为10G字节。在Java中,我会使用位集并线性化访问,例如
BitSet.get(屏幕id+400000*用户id)

如果每个用户只访问几个屏幕,那么位集中会有大量重复的假值。这就是所谓的a。事实上,这是计算机科学中一个研究得很好的问题,你会发现很多不同的解决方案

这回答了您最初的问题,但可能无法解决您的问题。在评论中,您表示希望查找访问特定屏幕的用户。现在,这是一个不同的问题领域,我们正在从高效的数据表示和存储转向高效的数据访问

查找访问了一组屏幕的用户,本质上与查找包含一组单词的文档是相同的问题。这是一个基本的信息检索问题。对于这个问题,您需要一个所谓的反向索引数据结构。一个流行的库是ApacheLucene


您可以阅读访问并自行构建数据结构。本质上,它是一个映射,由屏幕id寻址,返回一组受影响的用户,即:
map
。对于整数集,第一个选择是哈希集,这不是非常高效的内存。我建议使用针对整数值的高性能集合库,例如。尽管如此,这可能不适合内存,但是,如果您使用Spark,您可以将处理分片,稍后加入处理结果。

map
是有效的,我想知道您的硬件是怎么回事。在采用新结构之前,您是否尝试过通过-Xmx简单地增加JVM的可用内存?乍一看,您上面的原始数据结构似乎并不不合理。否则,您可以脱机存储数据吗?如果不需要内存驻留数据结构,那么您可能会发现