及时查找添加到 Guava 的第一个和最后一个元素 LinkedHashMultimap/HashMultiMap

Finding first and last elements in time added to Guava LinkedHashMultimap/HashMultiMap

我每分钟都有一个带时间戳的统计数据流(每分钟任意数量的统计数据)。这只是一个持续的统计数据流,不允许更改以前的数据。这里也没有并发问题。所以合适的数据结构是map<timestamp,list<stats>>。然而这张地图只需要保留最后 30 分钟的数据,所以它也应该踢出第一个元素并写入新的元素(循环缓冲区)。有人告诉我 Guava HashMultimap 是一个很好的选择。但我不知道如何使用它找到地图的第一个和最后一个元素以及如何删除最后一个元素。当我查看 LinkedHashMultiMap 时,我没有看到任何查找第一个或最后一个元素的方法。感谢您的帮助。

您可以采用多种方法。我将解释并展示两者的例子。我不会解决同步问题,如果有必要请告诉我,我可以添加详细信息以确保 Multimap 代码是线程安全的。这涉及在访问其视图并将其包装在同步包装器中时正确同步多图。还可以找到更多详细信息 here.

  1. 使用多图
  2. 使用 Guava 的 Cache

对于 Multimap 方法,我建议您使用 LinkedListMultimap。它将确保您的键是有序的并且您的值是有序的(因为您最初声明 Map<Timestamp, List<Stat>>。LinkedHashMultimap 将保留顺序但它会删除重复的统计信息。如果这不是问题,那么您可以使用 LinkedHashMultimap。

要获取第一个键值,您可以使用迭代器或使用 Guava 的 Iterables getFirst(Iteratable, defaultValue) 实用方法。要获取最后一个键值,可以使用 Iterables 的 getLast(Iteratable, defaultValue) 方法。 如果您的目标只是删除超过 30 分钟的值,您可以忽略 Iterables 并只使用它们的迭代器 Multimap 的键。

LinkedHashMultimap<Date, Stat> stats = LinkedHashMultimap.create();

//Every minute
stats.putAll(new Date(), newStats);

//To get the first key inserted into the map
Date first = Iterables.getFirst(stats.keys(), null);
//Remove the first entry
stats.remove(first);

//To get the last key inserted into the map
Date last = Iterables.getLast(stats.keys(), null);
//Remove the last entry
stats.remove(last);

//Without using Iterables.
Set<Date> keys = stats.keys();
if (!keys.isEmpty()) {
    keys.iterator().next().remove();
}

Multimap 方法要求您手动管理删除旧统计信息。在这方面稍微简单一点的方法是使用 Guava 的缓存。但是请注意,这不会维护任何类型的顺序,并且会更难获得一段时间的值,因为您没有插入统计信息的确切时间戳。您需要使用满足您需要的 .hashCode().equals(Object) 方法创建自己的自定义日期 class。这可能超出了它的价值。

Cache<CustomDate, List<Stat>> cache = CacheBuilder.newBuilder()
        .expireAfterWrite(30, TimeUnit.MINUTES)
        .build();

cache.put(new CustomDate(), stats);
List<Stat> statsForTime = cache.get(new CustomDate(/*appropriate initialization*/));