APP下载

气象服务系统数据统计功能二次开发的设计和实现*

2019-07-03胡波周必高俞燎霓李嘉鹏

浙江气象 2019年2期
关键词:前台后台极值

胡波 周必高 俞燎霓 李嘉鹏

(1.浙江省气象台,浙江 杭州 310017;2.温州市气象局,浙江 温州 325027)

0 引 言

气象服务是所有气象业务产品向社会提供服务的出口,是气象工作的出发点和归宿[1],因此如何提高气象服务能力就成为了气象事业发展的一项重大任务[2]。多年以来,从国家到地方气象部门均投入大量人力物力不断发展气象服务系统[3-7],以满足新形势下的业务需要,如国家气象中心于2007年就开展了全国气象服务信息系统(MESIS)1期、2期、3期、4期等一系列项目建设[8],实现气象信息检索及可视化产品制作平台的开发[9]。马渝勇等采用消息型中间件技术设计省级气象信息共享系统,实现了开放式的气象信息服务[10]。雷升锴等采用先进网络服务技术,以向基层辐射和共享为主要手段,提出了省级公共气象服务系统的整体架构设计[11]。陈亮等应用本地缓存机制和智能文本生成等技术设计开发了省级气象服务产品分发系统[12]。杨忠恩等通过对用户定位信息与天气现象、能见度、温度、降水、风力等精细化格点数据进行融合,提供了一系列基于位置的创新性交通气象服务[13]。李超等通过气象服务产品管理标准化和业务规范化,开发了市县级公共气象服务集约化业务平台,使基层台站软件操作简单化[14]。这些服务系统完成后满足了当时的服务需求,但从后期维护、未来发展和推广应用等方面来看,存在许多问题。首先,数据库使用存在不足,这些系统的数据库应用分为两种情况:一种是直接连接业务数据库;另一种是建立专门的业务数据库。前一种情况随着业务发展,数据库在更改和升级后会导致系统许多功能无法继续使用,且新增数据库应用也存在困难;后一种情况需要专人去维护此业务数据库,极大增加了推广应用的难度。其次,系统集成的数据统计分析的黑箱特性导致其二次开发能力严重不足,跨区域推广应用更是水土不服,而重新开发一套新系统又意味着许多功能的重复建设,造成资源浪费。最后,服务材料文字输出功能偏弱,不能满足业务需求。为了尝试解决这些问题,采用c#和MS-SQL技术,本文提出使用内部函数和外部函数相结合的方法设计服务数据分析统计系统,最大可能提高系统的二次开发应用能力,便于在全省气象部门的推广使用。

1 系统流程框架

系统功能总体分为3部分,分别为前台界面配置模块、后台函数配置模块和前台界面显示模块(见图1)。前台界面配置模块实现自定义的插入、修改和删除业务上各种的统计项目及其条目,统计条目与内部数据库具有双向反馈能力;后台函数配置模块包括内部函数和外部函数的配置,内部函数通过暴露参数接口,灵活连接外部数据库,实现数据各种分析功能,并将数据分析结果返回到内部数据库。内部函数的接口参数与内部数据库具有双向反馈能力。外部函数采用基于sql语句的形式,在内部函数计算结果的基础上再次对数据进行统计分析,并将结果输出到自定义的文字模板之中,外部函数与内部数据库有双向反馈能力。前台界面显示模块可以在用户自定义前台界面配置模块、后台函数配置模块后,从更新的内部数据库中读取相关数据信息,将统计条目、数据结果、文本等用户需要的信息显示到前台界面,并可以将输出的数据进一步转化为图像服务产品。

图1 系统的功能框架

2 基于动态链接库形式的内部函数

为了实现灵活、强大的二次开发功能,系统的内部函数使用动态链接库形式开发,采用统一的struct接口规范,其参数在后台配置平台中完全暴露,内部函数可以灵活与外部数据库进行连接,并将分析统计的数据保存在内部数据库,最后利用基于sql语句的输出参数将计算结果显示到前台界面供业务人员使用。

表1为气候监测内部函数的接口参数样例,这个函数实现固定时段内的要素与历史同期的对比分析,结果输出包括今年值、气候平均、距平或百分率、历史极值、排序等信息。接口参数分为前台和后台两类,前台参数由用户在前台操作时使用,后台参数由管理员在后台配置内部函数时使用,前台参数只有s_time(开始时间)、e_time(结束时间)、yuzhi1(阈值≥)和yuzhi2(阈值≤),后台参数众多,主要包括二个数据源连接(con和con1)和一个用于保存计算结果的内部数据库连接(Local)、外部数据库所使用的数据表(SeTable1、SeTable1)及数据表对应的站年月日时字段(station、year、month、day、station1、year1、month1、day1、hour1)和需统计分析的数据表字段(chSet、chSet1)等,还有数据的计算方法(method)、结果在前台界面显示时所使用二个数据表连接(out、out1)等。这里二个外部数据库(con1和con2)分别为历史气候库和自动站数据库,历史气候库为日值资料,自动站数据库为小时资料,当历史气候库中数据有缺时由自动站数据库进行补充,实现统计时段内数据的无缝衔接。OutSql和OutSql1为基于sql语句的数据输出后台参数,具体赋值后面有详细讨论。

表1 气候监测内部函数的部分接口参数

表2为2017年1月1日至2月2日的平均气温与历史同期气候对比分析时的气候监测内部函数接口部分参数的赋值情况,选取的计算方法为avg,气候库的表为Temperature,自动站表为tabRealTimeData_YYYYMM,由于自动站表中的观测时间字段内容格式为yyMMddHH,因此需要将参数year1赋值为’20’+substring(ObservTimes,1,2),month1赋值为substring(ObservTimes,3,2),day1赋值为substring(ObservTimes,5,2),hour1赋值为substring(ObservTimes,7,2),气候平均值开始年份CstartY为1981年,结束年份CendY为2010,pianyi值为3代表自动站小时值加3,便于计算20—20时的平均气温。

表2 气候监测内部函数接口部分参数的赋值样本

通过灵活的参数配置实现气候监测内部函数的二次自定义开发,选取不同的数据源和计算方法(参数为method)实现不同要素的气候监测,如计算字段chSet为雨量,方法选择sum,结果为累计雨量的气候对比分析,方法选择count,SqWhere参数限制日雨量大于0,结果为雨日的气候对比分析;计算字段chSet选择最低气温,SqWhere参数限制日最低气温小于0 ℃,方法选择count,结果为低温日数的气候对比分析;计算字段chSet选择日照时数,方法选择sum,结果为总日照时数的气候对比分析。另外,由于内部函数是基于动态链接库形式进行开发,因此可以根据业务需要开发新的内部函数,并通过后台配置方式添加到系统中,这样就完全将数据统计分析的功能与数据显示、数据绘图等模块脱离开来,实现数据统计灵活的二次开发。

内部函数通过后台参数配置实现了计算后,需要进一步考虑如何实现计算结果的灵活输出。由于统计分析结果均是以表格形式保存在内部数据库的表中,故采用基于sql语句查询形式将返回的数据在系统前台界面进行显示,为了尽可能显示多种数据,sql数据列表分为主sql和从属sql数据列表,表3为气候监测内部函数输出结果存放表history的结构,temperature为相关要素统计值(如平均值、最大值、最小值、个数等),基于此表的前台界面数据显示所需主sql语句为:

Select [address] as 站号,[staname] as 站名,[county] as 县,[s_MMDD] as 开始时间,[e_MMDD] as 结束时间,[temperature] as 平均气温,basis as 距平,[LtoS_order] as 大到小排序,[StoL_order] as 小到大排序,[lon] as 经度,[lat] as 纬度,factor as 内部识别码 from [dbo].[history] where [s_MMDD]=SUBSTRING(’{s_time}’,5,4) and [e_MMDD]=SUBSTRING(’{e_time}’,5,4) and factor=’{factor}’ and the_year=SUBSTRING(’{e_time}’,1,4) order by [address] desc

语句中{s_time}、{e_time}、{factor}等为内部函数接口的参数值(见表2),为了在前台显示单站的历史统计信息,从属sql语句指定为:

select [the_year] as 年,[temperature] as 平均气温,[LtoS_order] as 大到小排序,[StoL_order] as 小到大排序 from [dbo].[history] where [address]=rtrim(’{站号}’) and [s_MMDD]=rtrim(’{开始时间}’) and [e_MMDD]=rtrim(’{结束时间}’) and factor=rtrim(’{内部识别码}’) order by [the_year] desc

语句中{站号}、{开始时间}、{结束时间}和{内部识别码}为主sql语句中输出列表中由用户选中的字段值,实现了在用户选择数据列表某一行时,对应站点的信息由从属sql语句进行指定输出。

为了进一步增强数据输出功能,主sql语句与从属sql语句均可以多选一,如日观测值破纪录查询内部函数的计算结果存放表historyHiRecord的结构见表4,为了实现从属sql语句可以查询某个站的年、月、旬的历史极值情况,其参数的赋值样式为“名称|sql语句|名称|sql语句|名称|sql语句”,具体如下:

旬极值|select sta as 站号,yyyyMMdd as 极值日期,paixu as 排序,type as 类型 from historyHiRecord where sta=’{站号}’ and factor=’{识别码}’ and type=’xun’ and time=’{日期}’|月极值|select sta as 站号,[yyyyMMdd] as 极值日期,paixu as 排序,type as 类型from historyHiRecord where sta=’{站号}’ and factor=’{识别码}’ and type=’month’ and time=’{日期}’|年极值|select sta as 站号,[yyyyMMdd] as 极值日期,paixu as 排序,type as 类型from historyHiRecord where sta=’{站号}’ and factor=’{识别码}’ and type=’year’ and time=’{日期}’|

语句中{站号}、{日期}和{识别码}为主sql语句中输出列表中选中的字段值,type为3种极值类型。

表3 气候监测内部函数输出结果存放表[dbo].[history]的结构

表4 日观测值破纪录查询内部函数输出结果存放表[dbo].[historyHiRecord]的结构

基于动态库的内部函数开发要引用FunMethod.dll和GistarUtilityLite.dll这两个动态库,GistarUtilityLite.dll作为一个辅助工具库,实现日志消息的交互、访问数据库类的封装、各种配置文件的解码等;FunMethod.dll主要基于GistarUtilityLite.dll动态库,实现系统后台跟外部实例动态库间的消息交互,及各类外部实例库的方法和参数的传递等。FunMethod.dll中包含动态库交互类,主要方法为MethodMgr,输入参数为需调用的实例动态库(DLL库)集合,返回解码反射动态库(dll库)中的函数,自动录入BaseFunction、BaseClassStruct等数据表中。GistarUtilityLite.dll包含文件管理类GPSys,方法包括GetSysConfig、AddSysInfo、AddSysInfoFormat等,实现各类配置文件的读取解码,及日志文件的写入生成等,还有数据库访问类DBUtility,方法包括Execute、GetDataList、GetDataListDir等,实现关联数据库的查询,支持返回数值结果、表格结果等功能。

具体使用时先在工程中添加FunMethod.dll和GistarUtilityLite.dll引用,并增加命名空间,语句为using GistarLite,然后在内部函数方法前面增加调用链接,具体为FunMethod(″内部函数方法名″,″方法说明″)]。譬如:

[FunMethod(″ClimateWatch″,″气候监测″)]

public void ClimateWatch(WactchCalInfo wacth_infor)

{

// 具体代码

}

其中,WactchCalInfo为气候监测模块使用的struct结构类型输入数据(见表1和表2),ClimateWatch为气候监测主程序,将程序编译成动态链接库,生成的内部函数即可在后台界面导入后使用(导入方式见第4节)。

3 基于sql语句的外部函数

服务数据的文字描述一般具有固定的格式,实现数据文字描述的自动输出将会提高工作效率,尤其基层气象台站人员紧张的情况下具有更大的实际意义。由于数据统计的结果一般存放在数据库的表中,而基于表数据的查询结果也是以表格的形式返回,故设计了用于获取数据的基于sql语句的外部函数,其调用接口格式为:

{name,row1:row2,Col,mark,unit,condition}

其中,Name外部函数名称,row1为sql语句输出数据表的开始行,row2为结束行,Col为列号或字段名,condition为数据输出时需满足的条件,可以输出列为Col、行从row1到row2的多个数据,输出的数据以unit为单位,以mark为分隔符。假设下面为一段时间内雨量统计数据需输出的文本。

全省平均降雨量*mm,其中*市*mm、*市*mm;有*个县(市、区)平均雨量超过25 mm,其中*个超过50 mm,*个超过100 mm,*个超过200 mm,最大为*县*mm;有*个乡镇(街道)超过50 mm,其中*个超过100 mm,*个超过200 mm,*个超过300 mm,*个超过500 mm,单站最大为*站*mm、*站*mm。

其中的“*”均为需要输出的数据,插入外部函数的参数接口后,需处理的文本变为:

全省平均降雨量{A1,1:1,1,’’,’’,‘’}mm[,其中{A2,1:11,1,’mm’,’、’ ,’>0’}][;有{B1,1:1,1,’’,’’,’>0’}个县(市、区)平均雨量超过25 mm][,其中{B2,1:1,1,’’,’’,’>0’}个超过50 mm][,{B3,1:1,1,’’,’’,’>0’}个超过100 mm][,{B4,1:1,1,’’,’’,’>0’}个超过200 mm][,最大为{B5,1:5,1,’mm’,’、’ ,’>=25’}]。[有{C1,1:1,1,’’,’’,’>0’}个乡镇(街道)超过50 mm][,其中{C2,1:1,1,’’,’’,’>0’}个超过100 mm][,{C3,1:1,1,’’,’’,’>0’}个超过200 mm,][,{C4,1:1,1,’’,’’,’>0’}个超过300 mm][,{C5,1:1,1,’’,’’,’>0’}个超过500 mm][,单站最大为{C6,1:5,2,’mm’,’、’,’>=50’}]。

“[ ]”中内容用于没有查询到数据(外部函数无数据返回)时不需要输出的文字描述语句,假设内部函数计算的雨量数据已经存放在StatTotalHour表中,表的结构见表5,那么基于sql语句的部分外部函数如下:

A1:select avg(rain) as 全省平均雨量 from [StatTotalHour] where s_time={s_time} and e_time={e_time} and factor={factor}

A2:select RTrim(city),avg(rain) as rain from [StatTotalHour] where s_time={s_time} and e_time={e_time} group by city order by rain desc

B1:select count(counrty) from (select RTrim(country) as counrty,avg(rain) as rain from [StatTotalHour] where s_time={s_time} and e_time={e_time} and factor={factor} group by country) a where a.rain>=25

颜晓晨用的是一款诺基亚的旧手机,连微信功能都没有,沈侯用的是iPhone手机最新款。颜晓晨还记得第一次拿到沈侯的手机时,连怎么接电话都不知道,还是沈侯手把手教会她如何用这种触摸屏手机。现在她虽然会用了,可毕竟用得少,很多功能不熟,只能笨拙地一条条慢慢回复。沈侯抬头瞅了她一眼,看她微皱着眉头,一丝不苟地和手机搏斗,忍不住唇角微翘,含着一丝笑继续看财经新闻。

C1:select count(distinct(town)) from (select StationNum,town,sum(rain) as rr from [StatTotalHour] where s_time={s_time} and e_time={e_time} and factor={factor} group by StationNum,town)a where a.rr>=50

C6:select StationNum,RTrim([country])+RTrim([stationName])+cast(sum(rain) as nchar) from [StatTotalHour] where s_time={s_time} and e_time={e_time} and factor={factor} group by StationNum,[country],[stationName] order by rain desc

表5 StatTotalHour表中的字段说明

外部函数Sql语句中的{factor}、{e_time}和{s_time}为内部函数的接口参数(见表2),可见每个外部函数均依托于特定内部函数,通过后台配置一系列的外部函数可以实现任意数据文字描述的输出,达到灵活二次开发的目的。

4 系统后台参数配置

由于系统的用户操作界面、内部函数、外部函数均通过后台参数配置模块完成,因此后台配置的设计十分重要,图2为自定义的后台参数配置界面,左边为可以增加和删除的数据检索项及具体分类,与分类对应的内部函数和外部函数均可根据需要自由指定。上半部分为内部函数参数赋值,其参数分为前台参数和后台参数,后台参数配置由管理员完成,前台参数由用户完成输入,下半部分为基于sql语句的外部函数及对应的文字描述,一系列的外部函数绑定在一个内部函数上。为了增强计算功能,每一个检索项的分类均可指定多个内部函数,可以对不同气象要素进行一系列的计算,从而在sql交叉数据查询的基础上,实现复杂的文字描述输出。

由于内部函数基于动态链接库形式,因此导入内部函数后需对参数进行说明,以及参数初始化绑定,图3为气候监测内部函数导入时的参数说明赋值界面,其中参数代码和字段类型为内部函数在系统中的实际接口,不能修改,后面的参数描述、参数类型、显示格式、初值绑定、默认初值、排序等均可由管理员自定义,参数类型分为前台和后台参数,显示格式分为TextBox、ComoBox、CheckBox,初值绑定用于指定赋值的可选项,如绑定为DBBind则可选择已有的数据库连接,绑定为EndTimeBind则可以选择已经设定各种预设时间(如今日、昨日、上周等),排序用于确定参数在后台界面的显示顺序(见图2)。通过内部函数参数说明的赋值和初始化,可以将新的内部函数不断添加到现有系统中,便于升级推广。

图2 基于自定义的后台配置界面

图3 内部函数参数说明及初始化

5 系统前台界面

系统前台界面可以显示统计数据的列表、文字描述,及多元化的图像产品。图4为2018年2月4日最低气温破纪录查询前台界面显示。破纪录查询需要获取旬、月和年等固定时段的历史极值信息,因此显示时需要3个从属sql语句,在后台对OuttSql1参数(见表1)进行赋值的时候,3个sql语句约定以“旬极值|sql语句1|月极值|sql语句2|年极值|sql语句3|”格式进行赋值,显示效果见图中右上角“▼”处快捷菜单显示的“旬极值”、“月极值”和“年极值”,分别对应了这3种从属sql的输出列表,由用户自由切换。当然根据业务需要,主sql语句也可以有多个,譬如可以区别显示区域监测情况和单站监测情况等。

由于不同主sql语句和从属sql语句返回的数据类型不同,长短也有差异,因此系统需要配置这两个sql数据列表的宽度比例,并且各自列表内的字段显示宽度也可以单独指定,以便达到最佳显示效果,默认情况下气候监测内部函数的outputSql数据输出列表的宽度占60%,其输出的各个字段占宽度80像素,有些字段不必显示在前台界面的话还可以隐藏(如factor),还可以对字段显示先后顺序进行指定(设置界面图略)。

6 结 语

各地气象服务数据的类型多样,存储方式不一,服务需求也有较大差异,基于本地业务所开发的数据统计分析系统往往由于二次开发功能设计不足,给后期升级拓展和异地推广使用带来困难,而重新开发一套新系统又意味着大量已有功能的重复建设,因此做好顶层设计,开发具有灵活二次拓展功能的服务系统有重要意义。本文基于此思想,设计和讨论了可在省市县3级使用的气象服务数据分析系统的设计和开发,得出以下主要结论。

图4 2018年2月4日最低气温破纪录查询前台界面显示

1)系统的统计项目及其详细条目均可通过后台由用户自主定义配置,通过对不同项目和条目设置不同的内部函数和外部函数,实现各种要素的数据分析、显示和文本输出等功能。

2)通过使用基于动态链接库形式的内部函数,可以实现与业务数据库中任意字段的连接和自定义的数据分析统计。函数提供的接口参数分为后台参数和前台参数二种类型,后台参数指定数据源、计算方法、输出数据类型、绘图字段等信息,前台参数供用户与系统进行交互时使用。此种参数接口暴露的设计方案不仅实现了自定义参数赋值,达到灵活应用目的,而且完全可以根据本地化需求自主开发内部函数,实现系统的完美升级。

3)在内部函数结果输出数据的基础上,利用主sql语句和从属sql语句输出数据列表可以灵活定制各种需要展示的分析数据,主sql语句和从属sql语句均可设置多条,满足不同内部函数的数据输出需要,输出列表的总宽度及各字段宽度均可自定义设置,使系统界面协调美观。

4)在内部函数的计算结果基础上,采用统一的函数接口,定义基于sql语句的外部函数,将外部函数与自定义文字模板融合在一起,实现复杂文本的输出,提高气象服务产品制作效率。

猜你喜欢

前台后台极值
极值(最值)中的分类讨论
极值点带你去“漂移”
极值(最值)中的分类讨论
极值点偏移问题的解法
中式琴房设计方案
Wu Fenghua:Yueju Opera Artist
庞鲜、卢栩枫室内设计作品
庞鲜、周衍耀室内设计作品
孟晚舟:从前台打杂到华为副总裁
后台暗恋