繁体   English   中英

是否有等效于 Redis 排序集 (zset) 的 Java 数据结构

[英]Is there a Java data structure equivalent to Redis sorted sets (zset)

Redis 有一种数据结构,称为有序集。

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

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

我的直接用例是在每个元素上构建一个带有 TTL 的集合。 地图的值将是过期时间,我会定期修剪过期元素。 我还可以定期调整到期时间。

所以……有几件事。

首先,确定您将更多地使用哪种访问。 如果您将执行更多 HashMap 操作(获取、放置)而不是访问排序列表,那么您最好只使用 HashMap 并在您想要修剪集合时对值进行排序。

至于修剪集合,听起来您只想删除时间小于某个时间戳的值,而不是删除最早的 n 个项目。 如果是这种情况,那么您最好仅根据值是否满足条件来过滤 HashMap。 这可能比尝试先对列表进行排序然后删除旧条目要快。

由于您需要两个独立的条件,一个在键上,另一个在值上,因此在大量数据上的最佳性能可能需要两种数据结构。 您可以依赖常规 Set 并分别在 PriorityQueue 中按 TTL 排序插入相同的对象。 可以通过写入包含附加 TTL 的对象字段来实现 TTL; 然后,当你移除下一个对象时,你检查是否有额外的 TTL,如果有,你用这个新的 TTL 和额外的 TTL = 0 把它放回去 [我建议这样做,因为从 PriorityQueue 中移除的成本是 O( n)]。 这将产生 O(log n) 时间来移除下一个对象(+ 由于碰撞的 TTL 产生的成本,这将取决于它发生的频率)和插入,以及 O(1) 或 O(log n) 的碰撞时间一个 TTL,取决于您选择的 Set 的实现。

当然,最简洁的方法是设计一个封装所有这些的新类。

此外,如果您的数据集不是很大,那么所有这些都是多余的。

看看ExpiringMap Guava 的缓存也可能适用于您的用例。

您可以使用两种数据结构的组合来实现它。 键到分数的排序映射。 以及分数到键的排序反向映射。

在 Java 中,通常这些将使用 TreeMap 实现(如果我们坚持标准的集合框架)。

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
  }

  ....

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM