用友NC语义模型红皮书07.docx
《用友NC语义模型红皮书07.docx》由会员分享,可在线阅读,更多相关《用友NC语义模型红皮书07.docx(57页珍藏版)》请在冰豆网上搜索。
用友NC语义模型红皮书07
高级分析平台
语义模型红皮书
版本:
V6.0.0.20100924
一、前言
1.概念
SMART,即Semantic Modeling for Analysis Report Toolkit, 分析报表语义建模工具。
2.定位
二、结构
3.应用模型
上图为语义模型应用结构图。
语义模型通过语义提供者,可以将多个数据源的数据进行整合。
4.语义模型
a)定义形态
下图展示了语义模型的内部结构,
语义模型主要由以下几部分构成:
a)元数据
元数据是指描述数据的数据,是为了外界使用数据而对数据本身含义的阐述。
拿我们最常见的二维数据(行列结构)举例来说,如果只有这些行列结构的数据,对我们来说这将毫无意义。
因为我们无法知道哪一列的数据代表什么含义,无法知道如何操作这些数据,更别提由这些数据分析出有用的信息。
反过来,如果针对这些数据指定了元数据,我们就可以了解哪一列代表的业务含义,并且知道该列的数据类型、长度、精度等。
这样,我们就能对这些数据进行加工处理,分析提取出有价值的信息。
同理,语义模型的元数据是对执行语义模型后获取的二维数据的描述。
元数据针对结果数据的每一列都提供了下列信息:
数据类型、字段显示名、字段名、备注、长度、精度等。
有了这些信息,我们就能知道在业务应用中该如何使用语义模型。
b)语义提供者
语义提供者,表述了一类取数方式,或者说如何提供数据的方式。
在语义模型中,语义提供者负责把一类业务取数过程以语义脚本的形式描述出来。
为了能更好的理解这个概念,我们可以打这样一个比方:
NC元数据、数据仓库、报表数据、总账数据等这些可提供数据的对象好比“数据水源”,而语义提供者好比“水泵”,语义模型好比“抽水机”。
每种“数据水源”只支持特定的“水泵”来抽取数据。
我们有了一种语义提供者“水泵”,就能抽取其对应的“数据水源”里的数据。
语义模型中能指定多个语义提供者,就相当于“抽水机”挂接了多个“水泵”,我们就能从多个不同类型的“数据水源”来抽取数据。
语义提供者负责抽取数据,同时对外提供元数据来描述这些数据。
语义提供者的元数据一般是在语义模型内部使用。
更多细节以及语义提供者的扩展说明参见章节《语义提供者》。
c)描述器
描述器是指对数据操作的描述,例如:
过滤、排序、分页、汇总等。
在语义模型中,描述器表述了对语义提供者抽取的数据的加工处理过程。
更多细节参见章节《描述器》。
d)首选项
语义模型中的首选项包括三类数据:
参数、宏变量、配置项。
下面将分别介绍:
i.参数
参数是模型中代表动态信息的元素,用于响应用户的输入。
参数给用户提供了控制模型执行过程的机会。
更多细节参见章节《参数》。
ii.宏变量
宏变量与参数类似,区别是,参数在模型执行时需要用户输入值;而宏变量不需要与用户交互,系统后台会根据上下文计算该值。
更多细节参见章节《宏变量》。
iii.配置项
配置项用于控制语义模型的执行方式。
b)执行流程
语义模型的执行流程如下图所示:
语义模型执行过程可分为以下步骤:
第一步:
语义模型脚本化
语义模型中的对象结构将转变为字符串形式的语义脚本。
第二步:
脚本对象化
通过脚本引擎把语义脚本解析为脚本模型,即把字符串形式的脚本对象化。
第三步:
脚本模型翻译为SQL
基于脚本模型,处理其中的语义函数,把脚本模型翻译为标准SQL语句。
运行态描述器会在这一步被处理。
第四步:
执行sql,把结果集封装为DataSet,返回DataSet。
由于运行态描述器的存在,每次执行语义模型时获取的最终sql都是不同的,但是,语义模型本身对应的脚本模型是相同的。
基于性能考虑,我们可以把语义模型对应的脚本模型缓存起来。
这样一来,只有第一次执行语义模型时,我们需要完整执行上述四个步骤,接下来的每次执行,我们只需取得该缓存的脚本模型,再做第三、四步的处理即可。
c)数据形态
语义模型提供的数据可以以两种形态存在:
数据集DataSet、数据表DbTable。
从数据流转的角度来说,语义模型代表了一种取数管道,数据可以从管道中抽取出来。
数据集DataSet代表了内存中的数据,或者说,数据在内存中以数据集DataSet为载体。
数据表DbTable代表了数据库中的数据,或者说,数据在数据库中以数据表DbTable为载体。
语义模型、数据集、数据表这三者之间还存在互相转换的关系,下图形象的展示了这点:
数据从语义模型这种数据管道中加载到内存,就以数据集的形式存在;如果把数据集中的当前数据持久化到数据库中,数据就以数据表的形式存在;把数据从数据库中加载到内存中,就完成了数据表到数据集的转换;数据表可以以语义提供者的形式构成语义模型,完成数据从数据表到语义模型的流转;并且,语义模型经由视图化执行,最终的结果集将以数据表的形式呈现。
数据在不同形态间流转时,改变的是数据载体,不变的数据本身的结构,即元数据。
5.语义提供者
语义提供者,表述了一类取数方式,或者说如何提供数据的方式。
在语义模型中,语义提供者负责把一类业务取数过程以语义脚本的形式描述出来。
a)接口
语义提供者包括NC元数据、DW元数据、以及语义脚本和业务代码扩展提供者。
提供总帐、HR、供应链、报表等业务数据扩展。
其整个体系结构可由下图表示:
其中,Provider是语义提供者的接口;
SemanticProvider是基础扩展抽象类,对能把取数过程以脚本形式描述的语义提供者可继承此类;
SemanticDataProvider是语义数据扩展抽象类,对不能以脚本形式描述取数过程,只能提供二维数据的提供者,可继承此类。
SemanticSqlProvider适用于提供者在运行时根据执行环境context返回不同取数sql
与SqlProvider的区别在于:
SqlProvider的sql结构在定义态已经确定;
SemanticSqlProvider是在运行时,经过一系列业务处理,返回最终取数sql.
上述图中,蓝色代表具体实现类。
通过以上的介绍我们可以得知,Provider定义了语义提供者的接口规范,SemanticProvider、SemanticDataProvider、SemanticSqlProvider则是我们具体实现提供者时要继承的抽象类。
现对这四个类的主要接口做重点介绍。
●Provider
接口方法
方法说明
StringgetCode()
获取编码。
该编码用于标示语义提供者
MetaDatagetMetaData()
获取元数据。
元数据中包含了该提供者提供的数据的描述信息,例如:
字段名、字段数据类型、字段精度等
StringgetTitle()
获取标题,即该提供者的显示名称
MetaData
provideMetaData(SmartContextcontext)
构造元数据。
入参参数context是提供者构造元数据时的执行环境。
此方法通常在设计态使用,用于重新构造元数据。
StringprovideScript(SmartContextcontext)
构造语义脚本。
入参参数context是提供者构造脚本时的执行环境。
此方法通常在运行态使用,用于把业务取数过程转换为语义脚本。
voidsetCode(Stringcode)
设置编码
voidsetMetaData(MetaDatametaData)
设置元数据。
此方法通常在设计态使用,一般是先调用provideMetaData(context)构造元数据,然后调用此方法来把元数据保存在语义提供者。
voidsetTitle(Stringtitle)
设置标题,即显示名
●SemanticProvider
接口方法
方法说明
MetaData
provideMetaData(SmartContextcontext)
同Provider
对于继承此类的提供者,必须实现此方法。
StringprovideScript(SmartContextcontext)
同Provider
对于继承此类的提供者,必须实现此方法。
●SemanticDataProvider
接口方法
方法说明
DataSetprovideData(SmartContextcontext)
提供二维数据。
入参context提供执行环境;
返回结果数据以DataSet形式展现。
DataSet主要包含两部分:
二维数据数组、元数据。
对于继承此类的提供者,必须实现此方法。
●SemanticSqlProvider
接口方法
方法说明
StringprovideSql(SmartContextcontext)
提供sql。
入参context提供执行环境;
返回结果数据以sql形式展现。
对于继承此类的提供者,必须实现此方法。
b)扩展
前面介绍了语义提供者的整个体系结构,现在我们拿一个具体例子来讲解如何实现一个语义提供者。
我们以比较简单的“数据表”这类取数方式来做示例。
扩展语义提供者可分为以下三步:
i.实现语义提供者类
由前文介绍,我们知道实现一个提供者有三种方式:
1.继承SemanticProvider:
能把取数过程以脚本形式描述的语义提供者可继承此类
我们现以数据表提供者为例来讲解如何以此种方式实现语义提供者。
数据表提供者对应的实现类为:
DbTableProvider,该类继承于SemanticProvider,实现了接口provideMetaData(SmartContextcontext),provideScript(SmartContextcontext)。
数据表提供者,是把NC元数据底层数据模型中的一张表作为操作对象,从中抽取数据。
其在语义模型中的操作是这样的:
在上级“模块”目录上选中模块“平台”,展开后在子节点上选中“sm_user”这张表。
在数据表提供者DbTableProvider中,我们只需要存储一条信息:
表名。
这些信息可以看做取数过程的业务描述,接下来我们做的就是把这些业务描述转换为以语义模型中的概念来进行描述。
实现provideMetaData(SmartContextcontext)接口:
有了表名信息,我们就可以把其列信息拿到,列Column解析为字段Field,每列对应一个字段,多个列对应的多个字段就组合为元数据MetaData。
实现provideScript(SmartContextcontext)接口:
数据表提供者比较简单,直接返回表名即可。
到此,我们的数据表语义提供者类就实现完毕。
2.继承SemanticDataProvider:
不能以脚本形式描述取数过程,只能提供二维数据的提供者,可继承此类
例如,供应链中有些查询并不能直接通过一条sql就能查出,中间可能经过一系列复杂的代码运算逻辑来构造这个结果数据,这时我们就可以继承SemanticDataProvider来实现语义提供者。
继承此类只需要实现provideData(SmartContextcontext)接口:
在该方法中,我们编写运算逻辑,构造最终的结果数据DataSet,返回之即可。
在此我们有必要介绍下DataSet的结构。
DataSet主要包含两部分:
元数据MetaData,数据容器Object[][](即二维数组)。
Object[][]即是最终的结果数据,MetaData是对数据的描述信息,包含对应字段信息:
字段名、数据类型、数据精度等。
3.继承SemanticSqlProvider:
应用方式与SemanticDataProvider类似,不同在于,SemanticDataProvider最终返回二维数据,而SemanticSqlProvider返回sql语句。
ii.实现语义提供者设计向导类
有了语义提供者类,我们还需要一个设计器来设计语义提供者。
每个设计器都需要实现接口IProviderDesignWizard。
该接口只有一个方法:
/**
*@paramparent父窗口。
为ProviderStepPanel,藉此可获得SmartModelWizardShareObject(向导模型,包含向导共享数据)
*@paramprovider待修改的语义提供者
*@paramcontext上下文
*@return设计完成后的语义提供者
*/
publicProviderdesign(Containerparent,Providerprovider,SmartContextcontext);
当设计语义提供者时,会调用此方法,调用完成返回提供者实例。
数据表提供者设计向导类为DbTableProviderDesigner。
其界面效果如下图所示:
其具体处理流程为:
调用design()方法,打开一如上图所示对话框,用户选中表后,点“确定”按钮,构造一个DbTableProvider实例,返回之。
iii.配置文件注册
编写完语义提供者类、设计向导类,我们还需在配置文件中注册该种语义提供者,以便在语义模型能加载到。
所谓注册,即在配置文件中增加相应配置项。
为方便各模块扩展语义提供者,在开发环境下,配置文件存放位置为各模块resources下的smart目录:
${NC_Project}/resources/smart/smart_${模块号}.xml
如总帐项目扩展配置文件路径为:
gl/resources/smart/smart_gl.xml
这样在安装盘中,各模块扩的扩展配置文件将都在NC_HOME/resources/smart/目录中。
具体配置信息如下:
每个语义提供者注册项包含五种属性:
名称、图标路径、类型、语义提供者类名、设计向导类名。
其格式为:
其中,type类型是用于区分预置的语义提供者和用户自定义的语义提供者,其有效值有:
preset、custom。
分别对应系统预置、用户自定义两种类别。
一般用户在自己扩展实现自定义的语义提供者时,可以直接去掉type项,或者把该项设置为custom。
以数据表提供者举例,其配置项为:
数据表../dbtableprovider.gif
preset
nc.pub.smart.provider.impl.DbTableProvider
nc.ui.pub.smart.designer.provider.DbTableProviderDesigner
至此,我们的语义提供者就全部实现了,在语义模型的设计向导中就会支持该类型的语义提供者。
6.函数
a)函数解析
语义脚本支持sql语法和自定义函数的混合编写。
系统默认函数有smart(),nc_metadata(),qdi_metadata(),parameter(),macro(),后续会扩展字符串函数、时间函数等。
NC公式统一走宏变量定义。
b)函数扩展
语义模型支持对其函数进行扩展,用户可以根绝业务需求添加自定义函数。
具体步骤如下:
1、根据函数接口(ISemanticCommand)实现自定义函数。
类图示意如下:
接口中API如下:
publicinterfaceISemanticCommand{
/**
*执行计算
*@paramcontext上下文环境
*@paramparams参数值
*@return执行结果
*/
Objectrun(SmartContextcontext,Object[]params);
/**
*函数名称
*@return
*/
StringgetFunctionName();
/**
*函数描述
*/
StringgetFunctionDesc();
/**
*函数参数类型
*为null表示不作约束
*/
Class[]getParameterTypes();
/**
*函数设置向导类
*为null标识无设置向导
*@return@seeIFunctionDesignWizard
*/
StringgetFunctionDesignWizardClz();
}
2、在函数扩展配置文件进行配置。
默认配置文件路径为${NC_Home}/resources/smart/function_default.xml。
为方便各模块扩展函数,在开发环境下,配置文件存放位置为各模块resources下的smart目录:
${NC_Project}/resources/smart/function_${模块号}.xml
如总帐项目扩展配置文件路径为:
gl/resources/smart/function_gl.xml
这样在安装盘中,各模块的扩展配置文件将都在NC_HOME/resources/smart/目录中。
配置文件示例如下:
配置文件中是根据驱动名称进行组织的,驱动总共分为两类SmartFunctionDriver和DBFunctionDriver。
之所以对驱动进行区分是因为在不同的功能点,加载的函数驱动可能不同。
在实际配置过程中,用户可以根据自己的需要把自定义的函数类全路径名放在已有的驱动定义或新增加自定的驱动定义中,即可完成函数的扩展。
7.参数
参数是模型中代表动态信息的元素,用于响应用户的输入。
在模型的执行过程中,可以根据参数值的不同来影响结果数据。
参数常用于对筛选条件的设置上。
示意图如下:
d)参数定义
参数是与具体的模型绑定的,在每个模型的设计过程中都可以对参数进行定义。
参数的类型分为:
字符,数值,枚举和参照。
当类型为枚举时,枚举项为用“@”分隔的枚举值,或者是一个单字段的查询SQL;当类型为参照时,枚举项为基础参照名,或者是用尖括号括起的自定义参照的类名。
在定义的时候需要注意,参数的编码要保证互不相同。
e)参数引用
参数引用主要在模型设计中的筛选描述器部分,在筛选描述器的条目中,值类型选择
为参数时候,则会在值字段的下拉列表中列出相应的参数。
另外在模型设计的“Smart脚本”中,我们提供了“parameter”函数,在函数列表中双击,则会弹出参数选择框。
f)参数设置
运行态要求用户首先对参数进行设置,当报表引用了多个语义模型时,参数将通过多页签设置,每个页签代表一个模型。
另外需要注意的是,模型在运行态时会对参数是否被引用进行检查,最终的设置界面上只会显示被引用的参数。
g)参照依赖
Ø设计态增加“参照依赖”列,参照型的参数可以使用参照依赖,其他类型即使设置也不会起作用
Ø“参照依赖”中支持parameter,macro函数;例如:
sm_user.cuid=parameter('param1')andpk_org=macro('m1')
Ø如果参照是树表形式的,并且需要分别对树和表进行设置,则输入框中输入的条件用“;”分割。
Ø定义态的默认值设置支持参照依赖,即参照显示的值会根据依赖的条件过滤。
具体设置:
h)自定义参照
参照类型参数支持对参照编辑的自定义设置。
实现方法:
在设计态,属性列编辑框中通过注册自定义编辑器的方式实现,方式为“<类路径>”。
相关的具体规则如下:
Ø编辑界面基类:
nc.ui.pub.smart.designer.preference.CustomParamDlg,自定义编辑器必须实现以下方法:
/**
* 利用参数信息构建UI
* @param info 参数信息
* @throws Exception
*/
public abstract void buildUI(CustomParamInfo info) throws Exception;
/**
* 获取参数编辑的返回值
* @return
* @throws Exception
*/
public abstract String getParamValue() throws Exception;
其中buildUI方法传递的参数CustomParamInfo相关说明:
/**
* 参照当前值
*/
private String currentValue;
/**
* 当前数据源
*/
private String dsName;
/**
* 当前参数的哈希表
*/
private HashMap paramMap;
3、使用说明:
见下图
8.宏变量
宏变量引申自程序设计中的宏,其表达式会被替换为字符串,并在最终的查询语句中可以被完全替换。
宏变量根据作用域分为全局宏变量和模型宏变量。
故名思意,全局宏变量用于全局共享,在任何语义模型中都可以直接引用。
模型宏变量与具体的语义模型相关,其只在当前模型中其作用。
全局宏变量中包含多个预置宏变量,如LoginDate,LoginUser等,方便共享。
宏变量其定义与参数类似,不同之处在于其类型有两种选择“公式”和“SQL语句”。
公式只是其表达式支持NC公式的编辑;SQL语句是指一般的SQL语句,但默认情况下取值只能取第一行第一列的值。
宏变量示意图如下:
宏变量的引用与参数相同,分别在筛选描述器和Smart脚本的公式(macro)中可以对其引用。
另外与参数区别的是,由于宏变量都是固定的值,因此不需要与用户进行交互,所有在浏览态没有相应的设置界面。
9.描述器
Descriptor是指对数据操作的描述,例如:
过滤、排序、分页、汇总等。
现支持以下几种描述器:
名称
对应类
用途
结构
对应界面设计类
汇总描述器
AggrDescriptor
对数据做汇总处理,相当于sql中的groupby
包含汇总条件、汇总字段两部分
无
数据唯一描述符
DistinctDescriptor
清除数据中的重复行,相当于sql中的distinct
不持有属性,以其存在与否来判断是否做distinct处理
无
过滤描述器
FilterDescriptor
对数据做过滤处理,相当于sql中的where
包含树形结构的过滤条件
FilterDescPanel
表连接描述器
JoinDescriptor
表示表之间的连接关系,相当于sql中的join。
只用于设计态
包含连接条件