Gle*_*eno 33 c# sorting date-sorting
所以,由于一些奇怪的原因,我最终得到一个100GB的未分类日志文件(实际上它是部分排序的),而我试图应用的算法需要排序数据.日志文件中的一行看起来像这样
data <date> data data more data
Run Code Online (Sandbox Code Playgroud)
我可以在工作站上访问C#4.0和大约4 GB的RAM.我认为合并 - 某种类型在这里最好,但是我自己实现这些算法还不够 - 我想问一下我是否可以采取某种捷径.
顺便说一句,解析日期字符串DateTime.Parse()非常慢,占用了大量的CPU时间 - chugging -rate几乎是10 MB /秒.有比以下更快的方式吗?
public static DateTime Parse(string data)
{
int year, month, day;
int.TryParse(data.Substring(0, 4), out year);
int.TryParse(data.Substring(5, 2), out month);
int.TryParse(data.Substring(8, 2), out day);
return new DateTime(year, month, day);
}
Run Code Online (Sandbox Code Playgroud)
我写道,为了加快速度DateTime.Parse(),它确实运行良好,但仍然需要大量的循环.
请注意,对于当前的日志文件,我也对小时,分钟和秒感兴趣.我知道我可以使用格式提供DateTime.Parse(),但这似乎并没有加快它的速度.
我正在寻找正确方向的推动,提前谢谢.
编辑:有些人建议我使用字符串比较来比较日期.这适用于排序阶段,但我确实需要解析算法的日期.我仍然不知道如何在4GB的免费RAM上对100GB文件进行排序,而无需手动操作.
编辑2:嗯,多亏了我使用windows排序的一些建议,我发现Linux上有类似的工具.基本上你叫sort,它会为你修复一切.正如我们所说,它正在做一些事情,我希望它能尽快结束.我正在使用的命令是
sort -k 2b 2008.log > 2008.sorted.log
Run Code Online (Sandbox Code Playgroud)
-k指定我要对第二行进行排序,第二行是通常YYYY-MM-DD hh:mm:ss.msek格式的日期时间字符串.我必须承认,man-pages缺乏解释所有选项,但我通过运行找到了很多例子info coreutils 'sort invocation'.
我会用结果和时间报告.这部分日志大约是27GB.我正在考虑分别对2009和2010进行排序,然后使用sort -m选项将结果合并到一个文件中.
编辑3好吧,检查iotop表明它正在读取数据文件的小块,然后疯狂地做一些事情来处理它们.这个过程似乎很慢.=(
sort没有使用任何内存,只有一个核心.当它从驱动器读取数据时,它不处理任何事情.难道我做错了什么?
编辑4三个小时,它仍在做同样的事情.现在我正处于那个阶段,我想尝试使用该功能的参数,但我投入了三个小时...我将在大约4个小时内中止,并试着用更智能的内存进行夜间计算和空间参数......
编辑5在我回家之前,我使用以下命令重新启动了该过程:
sort -k 2b --buffer-size=60% -T ~/temp/ -T "/media/My Passport" 2010.log -o 2010.sorted.log
Run Code Online (Sandbox Code Playgroud)
它今天早上回来了:
sort: write failed: /media/My Passport/sortQAUKdT: File too large
Run Code Online (Sandbox Code Playgroud)
Wraawr!我想我会尽可能多地添加硬盘来加速这个过程.显然,添加USB驱动器是最糟糕的想法.目前我甚至无法判断它是关于FAT/NTFS还是其他一些,因为fdisk告诉我USB驱动器是"错误的设备"......不开玩笑.我会试着再试一次,现在让我们把这个项目放到可能失败的堆中.
最后的注意事项 这次使用与上面相同的命令,但没有有问题的外部硬盘驱动器.感谢大家的帮助!
标杆
在同一SATA控制器上使用2个工作站级(至少70mb /秒读/写IO)硬盘,我花了162分钟对30GB日志文件进行排序.今晚我需要另外排序52 GB的文件,我会发布这是怎么回事.
Han*_*ant 18
像这样的代码完全受限于从磁盘上获取数据的速度.该文件根本无法放入文件系统缓存中,因此您始终在磁盘上等待提供数据.你以10 MB /秒的速度做得相当不错,优化代码永远不会有明显的效果.
获得更快的磁盘.将你所拥有的那个碎片整理为中间步骤.
Wil*_*ung 15
如果字符串排序适合您,则只需使用Windows SORT命令.对文件进行排序并完成.它会愉快地对您的100GB文件进行排序,并且使用起来很简单.
如果你需要过滤和转换文件,特别是日期字段,那么我只需编写一个小的转换程序,将数据字段转换为0填充整数(如1970年以来的秒数,或者你喜欢的任何东西),以及重写记录.然后你可以将输出管道(|)到sort命令,然后你有一个最终的,有条件的文件,你的实用程序更容易解析.
我认为你所犯的错误只是试图一次性完成这一切.100GB的数据很多,复制需要一些时间,但这并不需要很长时间.由于您必须对其进行排序,因此您必须在某个时刻处理该文件的副本(即,您的计算机上需要尽可能多的可用空间以便在某个时间处理这两个副本),即使使用合并排序等外部排序例程也是如此.
编写一个简单的重新格式化器并将其输入以进行排序将节省您在文件中的几次浏览,并节省磁盘空间,因为您不可避免地只需要两个副本.
我还要调整格式化程序,只拉动我真正感兴趣的字段,并在那时进行所有"重"解析,这样你最终得到的本质上是一个格式化的文件,很容易由你的报告程序处理.这样,您可以在以后可能多次运行报告时节省时间.
如果可能,请使用简单的CSV或更好的固定长度文件格式进行输出.
如果您选择使用整数,请确保您的日期信息具有相同长度的所有字段.否则SORT实用程序将不会正确排序它们(最终得到1 10 2 3而不是1 2 3 10.你最好有01 02 03 10.).
编辑 -
让我们从另一个机智接近它.
最大的问题是"你需要所有这些数据吗".这与先前关于首先进行重度解析的建议有关.显然,你可以越多地减少初始设置越好.例如,简单地删除10%的数据是10GB.
作为经验法则,我喜欢考虑一些事情,特别是在处理大量数据时:"如果你有1百万的东西,那么每节省一毫秒,距离底线20分钟."
通常情况下,我们真的没有考虑工作的毫秒数,它更像是"裤子的位置","感觉更快".但1ms == 20分钟/百万是一个很好的衡量标准,可以掌握你正在处理的数据量,以及应该/可以采取多长时间.
对于你的情况,100GB的数据.每条记录有一个100字节的赃物,你需要10亿行.每毫秒20,000分钟. - 5个半小时.gulp(这是一个经验法则,如果你做数学计算,那就不太合适了.)
因此,如果可能的话,您可以欣赏减少原始数据的愿望.
这是我推迟到Windows SORT命令的一个原因.这是一个基本过程,但受细微差别影响,可以使用一些优化.写SORT的人有时间和机会在很多方面使其"最佳".无论他们做了还是做不到,我都说不出来.但这是一个公平的假设,他们会把更多的时间和精力放在这个过程中,使他们的SORT和实际一样好,而不是你在紧迫的期限内.
有大型数据集的第三方排序实用程序,可能(理想情况下)在这种情况下更好地工作.但是,那些是你无法获得的(你可以得到它们,但我认为你不想立即赶去并获得其他实用工具).所以,SORT是我们现在最好的猜测.
也就是说,减少数据集将比任何排序实用程序获得更多.
你真的需要多少细节?你真正跟踪了多少信息?例如,如果是网络统计信息,您的网站上可能有1000个网页.但即使每年的小时数,365*24*1000,这只是870万"桶"的信息 - 与1B相差甚远.
那么,您是否可以进行任何不需要排序的预处理?将信息汇总为更粗略的粒度?你可以做到这一点而无需排序,只需使用基于内存的哈希映射.即使你没有"足够的内存"来一次处理所有100GB的数据,你可能有足够的数据块(5个块,10个块),并写出中间结果.
您也可以更好地分割数据.进入每月或每周文件块.也许这不容易做到,因为数据"大部分"都是排序的.但是,在这种情况下,如果按日期进行,违规者(即排序中的数据)很可能会聚集在文件中,而"乱序"的东西只会混淆在时间段的障碍上(就像日常转换一样,也许你有像下午11:58,晚上11:59,上午00:00,上午00:01,晚上11:58,下午00:02这样的行.您也可以利用该启发式方法.
目标是,如果您可以在某种程度上确定性地确定无序的子集,并将文件分解为"按顺序数据"和"无序数据"的块,则您的排序任务可能会小得多.对无序的几行进行排序,然后出现合并问题(比排序问题简单得多).
所以,这些是你可以采取的策略来解决问题.总结显然是最好的,因为在任何可测量的情况下减少这种数据负载的任何事情都可能是值得的.当然,这一切都归结为你真正想要的数据,显然报告会推动这一点.这也是关于"预成熟优化"的一个很好的观点.如果他们没有报告,请不要处理它:).
Jam*_*ate 13
简短回答 - 将数据加载到关系数据库中,例如Sql Express,创建索引,并使用基于游标的解决方案,例如DataReader来读取每个记录并将其写入磁盘.
只是回答关于排序不适合内存的长文件的问题 - 您需要使用一些外部排序算法,例如Merge sort.这个过程大致如下:
将输入分成几个适合内存的部分,可以使用标准的内存中排序算法进行排序(例如100 MB或更大 - 你需要在内存中同时保存~4个部分).对所有部件进行排序并将其写回磁盘.
从磁盘中读取两个部分(它们都已排序)并合并它们,这可以通过同时迭代两个输入来完成.将合并的数据集写入磁盘中的另一个位置.请注意,您不需要将整个部分读入内存 - 只需随时读取/写入块即可.
重复合并部件,直到只有一个部件(将使用原始输入数据集中的所有数据对其进行排序).
您提到数据已经部分排序,因此在这种情况下选择一些内存排序算法(在第一阶段)是个好主意.你可以看到一些建议,这个问题(虽然我不知道,如果答案是一样的非常大的数据集-这取决于有多少部分排序的输入).