是否存在与Redis有序集(zset)等效的Java数据结构

时间:2014-04-30 02:58:47

标签: java data-structures set ttl

Redis有一个称为有序集的数据结构。

接口大致是SortedMap的接口,但按值而不是键排序。我几乎可以使用SortedSet,但它们似乎采用静态排序值。

是否存在类似概念的规范Java实现?

我的直接用例是在每个元素上构建一个带有TTL的集合。映射的值将是到期时间,并且我会定期修剪过期的元素。我也可以定期查看到期时间。

4 个答案:

答案 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
  }

  ....

}