Redis有一个称为有序集的数据结构。
接口大致是SortedMap的接口,但按值而不是键排序。我几乎可以使用SortedSet,但它们似乎采用静态排序值。
是否存在类似概念的规范Java实现?
我的直接用例是在每个元素上构建一个带有TTL的集合。映射的值将是到期时间,并且我会定期修剪过期的元素。我也可以定期查看到期时间。
答案 0 :(得分:1)
所以......好几件事。
首先,确定您将更多地访问哪种访问权限。如果您要执行更多的HashMap操作(获取,放置)而不是访问已排序的列表,那么您最好只使用HashMap并在想要修剪集合时对值进行排序。
至于修剪集合,听起来你只想删除时间少于某个时间戳的值,而不是删除最早的n项。如果是这种情况那么你最好只根据值是否符合条件来过滤HashMap。这可能比先尝试对列表排序然后删除旧条目要快得多。
答案 1 :(得分:1)
由于您需要两个单独的条件,一个在键上,另一个在值上,因此非常大量数据的最佳性能可能需要两个数据结构。您可以依赖常规Set,并分别在TTL排序的PriorityQueue中插入相同的对象。可以通过在包含附加TTL的对象的字段中写入来完成对TTL的碰撞;然后,当你删除下一个对象时,你检查是否有一个额外的TTL,如果有,你用这个新的TTL和其他TTL = 0把它放回去[我建议这是因为从PriorityQueue中删除的成本是O( N)]。这将产生O(log n)时间以移除下一个对象(+由于碰撞TTL导致的成本,这将取决于它发生的频率)和插入,以及O(1)或O(log n)时间用于碰撞一个TTL,取决于你选择的Set的实现。
当然,最干净的方法是设计一个封装所有这些的新类。
此外,如果您的数据集不是很大,那么所有这些都是过度的。
答案 2 :(得分:0)
看看ExpiringMap。 Guava的cache也可能适用于您的用例。
答案 3 :(得分:0)
您可以使用两个数据结构的组合来实现它。 键到分数的排序映射。以及分数到琴键的排序反向映射。
在Java中,通常这些将通过TreeMap实现(如果我们坚持标准的Collections Framework)。
Redis使用“跳过列表”来保持顺序,但是“跳过列表”和“平衡二进制搜索树”(例如TreeMap)都可以在此处提供平均O(log(N))访问的目的。
对于给定的排序集, 我们可以将其实现为一个独立的类,如下所示:
class SortedSet {
TreeMap<String, Integer>> keyToScore;
TreeMap<Integer, Set<String>>> scoreToKey
public SortedSet() {
keyToScore= new TreeMap<>();
scoreToKey= new TreeMap<>();
}
void addItem(String key, int score) {
if (keyToScore.contains(key)) {
// Remove old key and old score
}
// Add key and score to both maps
}
List<String> getKeysInRange(int startScore, int endScore) {
// traverse scoreToKey and retrieve all values
}
....
}