16

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

  • 主索引将单个键(主键)映射到唯一值(Map 接口)

  • 二级索引将单个键映射到值集合(Multimap 符合要求)

非常类似于 RDBMS 世界中的表,其中一个表有多个查找列。有时您想按 PK 搜索,有时返回基于公共属性的行列表。现在,除了等于 (=) 之外,不需要其他操作(即没有范围查询或模式匹配)。

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

我想就如何最好地解决给定问题征求您的意见。应该是 Cache per index 还是 Cache (for PK) + (synchronized) Multimap for secondary index?

任何帮助深表感谢。

问候。

4

3 回答 3

2

You can replace a Map with a Guava com.google.common.cache.Cache. It doesn't support Multimap type semantics , so you'd have to use

Cache<K, ? extends List<V>> 

in that case.

For the sake of simplicity I would make the 'primary index' a subset of the secondary index - i.e. you have a single index that returns a list of values for a given key and primary keys just return a list with a single value.

于 2012-06-07T14:53:38.607 回答
1

这里的挑战是保持两个索引的完整性,无论您是使用两个缓存还是一个缓存来进行 PK + multimap。

可能你应该创建一个扩展 com.google.common.cache.Cache 的新缓存类(比如 TableCache),在内部这个类可以维护二级索引的多映射实例变量(可以是 ConcurrentHashMap)。

然后您可以覆盖缓存方法(放置、获取、无效等)以保持二级索引同步。

当然,您必须提供一个 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
    }

}
于 2012-06-13T20:11:30.067 回答
0

我自己也遇到过很多次这个问题。

如果 Java 有更好的STM 支持,可以解决这个问题。制作非阻塞原子数据结构非常困难。我见过的最好的是多元宇宙

因此@vladimir 的答案可能是最好的,但我会说存储的集合应该是不可变的,并且您必须在刷新/缓存未命中等时检索整个集合......另外,如果您更改 multiset 的成员之一,您将继续很难知道如何更新其父级并使缓存无效。

否则我会考虑像Redis这样的大型数据集,它支持地图和列表组合上的原子操作。

于 2012-10-17T12:26:05.557 回答