最近公司有一个需求发现用neptune实现起来非常清新爽洁不紧绷。
需求是这样:
需要从某公司下载大量的数据文件。
一共有十八种不同的文件,比如Customer,Company, StockIndex等等。
从2003年4月一直到现在,每个工作日都有数据文件下载。周末没有。
对某一天,比如2005/1/3的Customer文件,url的格式是:http://river.com/repos/2005/01/03/Customer.zip
。
开始需要把所有历史文件下载下来。
然后天天都持续下载新文件。
在给定的某一天,不一定每个文件都有。有时候Customer没有,或者Company没有。理论上,可以每个文件都没有。
下载下来的文件需要unzip。unzip出来的会是一个csv文件。
这个csv文件需要被输入到数据库中的对应表中。这一天的日期也要存在这个表里,作为一个列。也就是说Customer, Company这些表除了有这些数据文件里面的每一个field之外,还有一个date列,来表示这个纪录是哪一天的。
下面是一些思考:
因为一个文件可能也可能不存在,所以这个文件不存在不能让整个流程停下来。文件不存在我们需要停止接下来的对这个文件的解压和导入数据库。但是不能中断其他文件的下载。
因为从别的公司下载,也无法保证敌人给我们的文件永远格式正确。假如万一解压失败,或者导入数据库失败,也能终端整个任务。
文件需要下载到本地目录里面,因为不同日期的文件名字一样,所以我们本地也可以构建一个yyyy/mm/dd格式的目录树。
一个一个文件下载,解压,导入,非常没有效率。也许敌人的网络很慢,这样整个任务就会持续太长时间。最好的办法是能够并行同时处理多个文件。
持续更新的时候,不能简单地只使用当前日期。因为也许因为某些原因前一天的某个文件没有及时更新或者下载失败了之类的。为了保证程序的健壮性,我们最好是从数据库读取最新日期,那一天的下一天就是我们要开始处理的日期。
下载,解压,调用数据库这些基本动作都可以用ant的任务来实现。
导入数据库我们用一个存储过程实现。
好,下面让我们从头构建这个任务。
下载:
download srcfile zipfile = ant.get{src=srcfile,dest=zipfile,username="myuser",
passWord="mypwd",usetimestamp=true,verbose=false};
解压:
unzip zipfile destdir = ant.unzip{src=zipfile, dest=destdir};
导入数据库:
importFile date name = ant.sql(db_connection).with[
"exec loadDataFile '${destdir}', '${datestr}', '${name}'"
]
where
datestr = datepath date;
destdir = "$csvroot/$datestr";
end;
导入数据库这一步用到了几个辅助函数和变量。
datepath函数负责把一个java.util.Date对象转换成"yyyy/MM/dd"格式的字符串。它使用jaskell的内建函数format:
datepath date = jaskell.dates.format{pattern="yyyy/MM/dd"} date;
db_connection是一个储存着所有数据库连接相关信息的对象。
csvroot是储存所有csv文件的根目录。