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

Java 使用guava缓存维护多个索引(内存表中),java,caching,indexing,guava,Java,Caching,Indexing,Guava,我试图实现一个简化的内存缓存“表”,其中有两种类型的索引:主索引和辅助索引 主索引将单个键(主键)映射到唯一值(映射界面) 二级索引将一个键映射到一组值(Multimap适用) 非常类似于RDBMS世界中的一个表,其中有多个查找列。有时需要按主键搜索,有时需要返回基于公共属性的行列表。现在,除了equals(=)(即无范围查询或模式匹配)之外,不需要其他操作 将缓存语义添加到上述数据结构(逐出、数据填充/缓存加载程序、刷新等),这正是所需要的 我想请教你们关于如何最好地解决这个问题的建议。它

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

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

  • 二级索引将一个键映射到一组值(Multimap适用)

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

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

我想请教你们关于如何最好地解决这个问题的建议。它应该是每个索引的缓存还是二级索引的缓存(对于PK)+(同步)多重映射

非常感谢您的帮助


问候。

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

Cache<K, ? extends List<V>> 
缓存
那样的话


为了简单起见,我将把“主索引”作为二级索引的子集,也就是说,您有一个索引,它返回给定键的值列表,而主键只返回一个带有单个值的列表

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

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

然后可以重写缓存方法(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
    }

}
公共类TableCache扩展了缓存{
Map secondaryIndex=新的ConcurrentHashMap();
公开作废认沽权(K键,V值){
super.put(键、值);
//更新第二索引
}
}

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

解决这个问题的方法是,如果Java更好。制作非阻塞的原子数据结构非常困难。我见过的最好的是

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


另外,我会考虑一些更大的数据集,这些数据集支持在地图和列表组合上的原子操作。

安德列,给出的答案有多大帮助?抱歉,但是我看不出你是如何假装缓存数据结构的。正如我所看到的,如果你通过PK搜索,它将访问你的地图并在O(1)中找到正确的元素(如果一切正常),对吗?你想缓存什么?嗨,普林尼奥。假设我尝试缓存用户。它们可能具有
userId
以及
group
属性。当我通过
userId
搜索时,只会返回1个元素,因为它是PK。通过
组进行查找
将返回一个
集合
(例如,admin组中的所有用户)。添加一个用户{userId:123,group:'admin}将同时更新这两个用户indexes@kevin-布里利翁还没有一个明确的答案。嗨,弗拉基米尔,问题更多的是如何保持这些结构的同步。一个缓存中的更改应该意味着另一个缓存中的修改。按主键添加元素应该会更新二级索引等。因为我不需要ACID属性,所以我希望能够实现比内存RDBMS更快的性能。@Andrei但您需要什么样的一致性和同步性?如果通过二级索引查询缓存,是否需要所有对应的行?可能是的。如果一行由主键加载,它是否应该以某种方式放入匹配的辅助索引中?如果使用一个索引访问一行,是否应阻止其从所有其他索引过期?@maaartinus可能应该仅在PK+RemovalListener上设置过期,后者为二级索引设置过期。现在我在想,让secondaryIndex包含集合作为值,并基于PK执行第二次查找以更新逐出统计信息是否更有意义。你的意见是什么?我的意见是“也许”。这意味着两次访问,可能丢失两倍的缓存。如果您有一个包含100个PK的二级索引,并且其中一半缺失,那么您可能最终会向DB发出50个单独的查询(有点像.oth,存储整行可能需要更多内存,我不知道如何处理逐出。或者我会这样做……我稍后会检查。如果您足够小心,可以保持所有索引同步(带RemovalListener)ie no cache misses from secondary key look Upsperumal,这更接近我需要的,但仍有一些问题需要解决。当我只想在内存中保留元素子集时该怎么办?可能使用CacheLoader。问题是CacheLoader仅通过PK加载。对于elemen上的
group=admin
等搜索,会发生什么情况ts哪些不在LocalCache中?这是否意味着每个索引(包括辅助索引)必须有一个CacheLoader?在此数据结构中,我们尝试模拟一个数据库算法。基于搜索键,无论是基于主键还是次键,算法都应将数据加载到内存中,以完成请求的查询。注释继续…因此我们需要两个加载程序,一个加载基于主键的数据,另一个加载基于主键的数据