使用番石榴缓存维护多个索引(内存中表)

2022-09-03 08:06:54

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

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

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

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

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

我想问问你关于如何最好地解决给定问题的建议。它应该是“按索引缓存”还是“缓存”(对于 PK)+(已同步)二级索引的多映射?

任何帮助都非常感谢。

问候。


答案 1

您可以将地图替换为Guava com.google.common.cache.Cache。它不支持 多映射类型语义 ,因此您必须使用

Cache<K, ? extends List<V>> 

在这种情况下。

为了简单起见,我会将“主索引”设置为二级索引的子集 - 即,您有一个索引,该索引返回给定键的值列表,而主键仅返回具有单个值的列表。


答案 2

这里的挑战是保持两个索引的完整性,而不管您是将两个缓存还是对 PK + 多映射使用一个缓存。

也许你应该创建一个新的缓存类(比如TableCache),它扩展了com.google.common.cache.Cache,在内部,这个类可以为二级索引维护一个多映射实例变量(可以是 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
    }

}