我每分钟都有一组带时间戳的统计数据(每分钟任意数量的统计数据)。它只是一个持续不断的统计数据流,并且之前不允许进行任何更改。此处也没有并发问题。所以适当的数据结构是map<timestamp,list<stats>>
。但是这个映射只需要保留最后30分钟的数据,所以它也应该踢出第一个元素并写入新元素(循环缓冲区)。我被告知Guava HashMultimap是一个很好的候选者。但我无法弄清楚如何使用它并找到地图的第一个和最后一个元素以及如何删除最后一个元素。当我查看LinkedHashMultiMap时,我看不到找到第一个或最后一个元素的方法。我感谢任何帮助。
答案 0 :(得分:1)
您可以采取几种方法。我将解释并展示两者的例子。我不会解决同步问题,如果有必要请告诉我,我可以添加详细信息以确保Multimap代码是线程安全的。这涉及在访问其视图并将其包装在同步包装器中时在多图上正确同步。更多细节也可以找到here。
对于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的Cache。但请注意,这不会保持任何类型的顺序,并且更难以获得一段时间的值,因为您没有插入统计数据的确切时间戳。您需要使用.hashCode()
和.equals(Object)
方法创建自己的自定义Date类,以满足您的需求。这可能比它的价值更多。
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*/));