在 Java 中避免大量计数器
Avoiding lots of counters in Java
在我的Java项目中,我需要读取一个大约有160万行的文件。
每一行代表用户在一天内完成的一项操作。如果我没记错的话,有 83 种不同的可能操作。
我需要按如下方式分析该文件并将找到的统计信息存储在 csv
文件中:
通常:计算一个动作发生的频率(数字会高达大约 50 万)
但也应该有单独的文件:
每小时发生一个动作的频率是多少? (csv 文件中的 24 行)
每个用户执行一个操作的频率是多少? (大约 20 个不同的用户 - 每个用户一个文件)
每个用户每小时执行一次操作的频率是多少? (每个用户单独的文件,其中 24 行)
最重要的是,有 3 个不同的频道(HTML、手机、电话)可能会发生这些事情(也保存在日志文件中),所以我需要为每个频道创建一个文件夹并为每个人做上面提到的事情。
问题:
我怎样才能 store/count 如此高效? 运行-时间不是什么大问题(它不应该 运行 一天,但它需要半小时没问题)
但是我怎么算呢?
我不能只为所有内容创建那么多计数器(数量会很大),而且 int[]
在我看来在这里不是很方便,因为我必须记住哪个操作有哪个索引等.
有更好的解决方案吗?
我考虑过使用本地数据库和 SQ
L 脚本,但该程序需要在每台 PC 上 运行 并且必须可以从命令行执行(不一定在IDE)。我正在使用 Intellij 14
进行开发。
A HashMap<String, Integer>
将是您柜台的便捷工具。单个实例足以满足所有操作类型。
关于工作流程,您有以下选择:
将完整的文件加载到 RAM 中(对于当今的 RAM 大小,这种方法变得越来越流行),然后以您需要的任何方式对其进行分析;
针对每种类型的分析再次阅读文件。
如果您的目标是较旧、配备较少的计算机,则第二个选择似乎不错。
顺便说一句,如果你可以使用Java 8,我会热烈推荐使用Streams API进行分析。它将从您的代码中消除大量样板文件,您将获得有效利用 Streams 的重要技能 API.
嵌入式数据库,如H2。
任何包装都意味着您必须自己做所有事情。
为了提高速度,您可以在多个级别上设置计数字段,也许作为单独的表。带有时间戳以供检查。
优点是可以灵活做报表。轻松备份。
当一切正常时,可以稍后进行自定义重构。
我会介绍一个KeyClass
public KeyClass {
timeInterval;
user;
action;
channel;
hasCode();
equals();
}
并在地图中使用它来计数。
为每条记录创建键实例并从映射值中获取。增加值(或为缺少的键创建)。
然后使用地图汇总计数。
更新:
Map<KeyClass, Integer> map=new HashMap<>();
for (String oneLine: allLines) {
KeyClass lineKey=createSomeHowTheKeyFromLine(oneLine);
Integer value=map.get(lineKey);
if (value==null) {
value=0;
}
value++;
map.put(lineKey, value);
}
循环后,您的所有计数都在地图中。
在我的Java项目中,我需要读取一个大约有160万行的文件。
每一行代表用户在一天内完成的一项操作。如果我没记错的话,有 83 种不同的可能操作。
我需要按如下方式分析该文件并将找到的统计信息存储在 csv
文件中:
通常:计算一个动作发生的频率(数字会高达大约 50 万)
但也应该有单独的文件:
每小时发生一个动作的频率是多少? (csv 文件中的 24 行)
每个用户执行一个操作的频率是多少? (大约 20 个不同的用户 - 每个用户一个文件)
每个用户每小时执行一次操作的频率是多少? (每个用户单独的文件,其中 24 行)
最重要的是,有 3 个不同的频道(HTML、手机、电话)可能会发生这些事情(也保存在日志文件中),所以我需要为每个频道创建一个文件夹并为每个人做上面提到的事情。
问题:
我怎样才能 store/count 如此高效? 运行-时间不是什么大问题(它不应该 运行 一天,但它需要半小时没问题) 但是我怎么算呢?
我不能只为所有内容创建那么多计数器(数量会很大),而且 int[]
在我看来在这里不是很方便,因为我必须记住哪个操作有哪个索引等.
有更好的解决方案吗?
我考虑过使用本地数据库和 SQ
L 脚本,但该程序需要在每台 PC 上 运行 并且必须可以从命令行执行(不一定在IDE)。我正在使用 Intellij 14
进行开发。
A HashMap<String, Integer>
将是您柜台的便捷工具。单个实例足以满足所有操作类型。
关于工作流程,您有以下选择:
将完整的文件加载到 RAM 中(对于当今的 RAM 大小,这种方法变得越来越流行),然后以您需要的任何方式对其进行分析;
针对每种类型的分析再次阅读文件。
如果您的目标是较旧、配备较少的计算机,则第二个选择似乎不错。
顺便说一句,如果你可以使用Java 8,我会热烈推荐使用Streams API进行分析。它将从您的代码中消除大量样板文件,您将获得有效利用 Streams 的重要技能 API.
嵌入式数据库,如H2。
任何包装都意味着您必须自己做所有事情。
为了提高速度,您可以在多个级别上设置计数字段,也许作为单独的表。带有时间戳以供检查。
优点是可以灵活做报表。轻松备份。
当一切正常时,可以稍后进行自定义重构。
我会介绍一个KeyClass
public KeyClass {
timeInterval;
user;
action;
channel;
hasCode();
equals();
}
并在地图中使用它来计数。 为每条记录创建键实例并从映射值中获取。增加值(或为缺少的键创建)。
然后使用地图汇总计数。
更新:
Map<KeyClass, Integer> map=new HashMap<>();
for (String oneLine: allLines) {
KeyClass lineKey=createSomeHowTheKeyFromLine(oneLine);
Integer value=map.get(lineKey);
if (value==null) {
value=0;
}
value++;
map.put(lineKey, value);
}
循环后,您的所有计数都在地图中。