我正在尝试实现一个简化的内存缓存“表”,其中有两种类型的索引:主要和次要。
主索引将单个键(主键)映射到唯一值(地图界面)
辅助索引将单个关键字映射到值集合(Multimap符合要求)
非常类似于RDBMS世界中的一个表,其中一个表有几个查找列。有时您希望通过PK进行搜索,有时会根据公共属性返回行列表。现在,除了equals(=)之外的其他操作没有必要(即没有范围查询或模式匹配)。
将缓存语义添加到上述数据结构(逐出,数据填充/缓存加载,刷新等),这几乎是所需要的。
我想问一下你如何最好地解决问题的建议。应该是每个索引缓存还是缓存(对于PK)+(同步)二次索引的Multimap?
非常感谢任何帮助。
问候。
答案 0 :(得分:2)
您可以使用Guava com.google.common.cache.Cache替换地图。它不支持Multimap类型语义,因此您必须使用
Cache<K, ? extends List<V>>
在那种情况下。
为了简单起见,我将'primary index'作为二级索引的子集 - 即您有一个索引返回给定键的值列表,而主键只返回一个具有单个值的列表。
答案 1 :(得分:1)
这里的挑战是保持两个索引的完整性,无论你是否为PK + multimap使用两个缓存甚至一个缓存。
可能你应该创建一个新的缓存类(比如TableCache),它扩展了com.google.common.cache.Cache,在内部这个类可以维护二级索引的多图实例变量(可以是ConcurrentHashMap)。
然后,您可以覆盖缓存方法(put,get,invalidate等)以保持二级索引同步。
当然,您必须提供一个get函数来根据二级索引检索值。
此方法使您能够维护主索引和辅助索引的完整性。
public class TableCache<K, V> extends Cache<K, V> {
Map<K, List<V>> secondaryIndex = new ConcurrentHashMap<K, List<V>>();
public void put(K key, V value) {
super.put(key, value);
// Update secondaryIndex
}
}
答案 2 :(得分:0)
我自己多次遇到这个问题。
如果Java有更好的STM support,那么解决这个问题的方法是什么。制作非阻塞原子数据结构非常困难。我见过的最好的是multiverse。
因此@vladimir的答案可能是最好的,但我会说存储的集合应该是不可变的,你必须在刷新/缓存未命中等时检索整个集合....如果你改变其中一个成员multiset你将很难知道如何更新其父级并使缓存无效。
否则我会考虑像Redis那样的大型数据集,它支持地图和列表组合上的原子操作。