使用guava缓存维护多个索引(内存表)

时间:2012-05-30 00:12:43

标签: java caching indexing guava

我正在尝试实现一个简化的内存缓存“表”,其中有两种类型的索引:主要和次要。

  • 主索引将单个键(主键)映射到唯一值(地图界面)

  • 辅助索引将单个关键字映射到值集合(Multimap符合要求)

非常类似于RDBMS世界中的一个表,其中一个表有几个查找列。有时您希望通过PK进行搜索,有时会根据公共属性返回行列表。现在,除了equals(=)之外的其他操作没有必要(即没有范围查询或模式匹配)。

将缓存语义添加到上述数据结构(逐出,数据填充/缓存加载,刷新等),这几乎是所需要的。

我想问一下你如何最好地解决问题的建议。应该是每个索引缓存还是缓存(对于PK)+(同步)二次索引的Multimap?

非常感谢任何帮助。

问候。

3 个答案:

答案 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那样的大型数据集,它支持地图和列表组合上的原子操作。