我正在对大型数据集进行一些实验,并希望优化特定部分。目前,我有5-6 Model
个,每个Topic
存储List
到String
Topic
的映射。 Model
s的集合很大,每个String
之间都相同,因此必须有更好的方法。最终,我需要执行的查询是:对于某些List
- Model
组合,Topic
的位置x中的Map<Model, Map<Topic, List<String>>>
是多少。
使用映射方法的一个问题是,如果有500k-5M主题,则每个主题都有20个字符串的列表。那么我的{{1}}将是巨大的。
答案 0 :(得分:1)
您是否尝试过SortedSet / Maps?听起来你需要优化搜索,排序的集合(如TreeMap)应该是log(n),而常规列表是O(1)。当然,这种事情是数据库优秀的东西......
答案 1 :(得分:1)
您可以使用Topic
和Model
在单个地图中构建复合键,例如
map.put(topic1_id + model1_id, list1_1);
map.put(topic1_id + model2_id, list1_2);
...
map.get(topic_id + model_id)
其中ID是字符串(或类似的方案可以与数字标识符一起使用)。
类似的方法是为每个主题分配一个唯一的编号,然后将字符串列表存储在数组中,因此查找给定组合的列表是查找两个索引,然后访问给定位置的问题。一个2D数组。 (但是,当您在构建数据结构之前知道主题和模型的数量时,这会更容易)
为了提高内存效率,还要考虑细节。通常,您希望最小化对象的数量 - 每个对象都有一个开销。 ArrayLists在动态增长时可能会浪费大量空间,当它们超出当前容量时会增加一倍。如果您可以预先调整它们的大小(或使用数组),那么您可以节省大量内存。使用大量小型HashMaps时同样适用。
答案 2 :(得分:1)
不清楚您希望在何处/如何实现“内存效率”。首先需要查看详细数据的详细信息,以查看消耗的存储量,然后检查各种组织方式,并根据%开销与“真实”数据分析其效率。
简要说一下,当您考虑关联表时,HashMap每个条目的开销大约为80字节。 ArrayList看起来平均在10-12左右。不看,我猜想TreeMap不仅仅是一个HashMap - 可能是100个。
一般来说,与使用这些聚合对象的链接相比,您自己对象中的链接在存储和访问速度方面都会“更便宜”。但是聚合对象使用起来很方便,并且在某种程度上已经“优化”。
(但是看看你的更新,你可能应该看一下数据库应用程序,而不是把所有东西都放在堆中。)
答案 3 :(得分:0)
一种可能的数据结构是地图层次结构,从而产生一个字符串数组。 E.g:
HashMap<Model, HashMap<Topic, String[]>> map;
查询功能如下:
public String query(Model model, Topic topic, int x) {
HashMap<Topic, String[]> childMap = map.get(model);
if (childMap == null) {
return null;
}
String[] list = childMap.get(topic);
if (list == null) {
return null;
}
return list[x];
}
假设您的模型和主题结构合理地实现hashCode()
和equals()
,查询性能应该非常好。
一个潜在的弱点:我假设您需要索引大量的模型/主题组合以及相关的字符串列表(如果没有,您可能不会询问优化)。我的猜测是子String []数组将占用大量内存。每个数组都是一个Java对象(大约20个字节)+每个数组位置的指针。
有2条建议:
1)如果许多模型/主题组合共享同一组字符串,则可以通过共享这些String[]
实例获得相当多的收益。
2)如果您使用的是64位虚拟机,请务必使用压缩的普通对象指针(-XX:+UseCompressedOops
)。这至少会将大多数指针保留为4个字节而不是8个。压缩OOP是1.6.0_23以来的默认值,因此相对较新的VM将为您节省一些内存。
答案 4 :(得分:0)
未提及的另一种可能性是使用String[][][]
以及List
中的模型和主题(例如ArrayList
)然后在查询时存储字符串:
public String query(Model model, Topic topic, int x) {
return strings[models.indexOf(model)][topics.indexOf(topic)][x];
}
如果对主题和模型进行排序,可以进一步提高速度,然后可以使用二进制搜索而不是indexOf
。