开发原型需要的维度数据:
开发先做关键原型,我们先准备各种原型需要的数据。
先准备维度数据:年度、版本、收费项目、区划

(维度的管理类)
一个具体维度,数据库上有三张表反映:

(维度及mondrian相关表)
维度相关的表:
- commObject,所有原始的祖先表;
- 前缀为 “c_” 的表,用于管理各类维度。
- 前缀为““c_dim_”的表,是mondrain引擎用到维度表。
配置mondrian的schemal相关的维度表用"c_dim_"前缀开头。
维度数据准备,以后应该用kettle抽取?
由于我先搞了一个项目维度表,感觉内容多了,相关数据重新迁移到commobject表。
select p.projectkey + 500000,
p.projectname,
1,
-100, --上级id 下面再处理
case --代数
when p.projectcode = p.level1projectcode then
1
when p.projectcode = p.level2projectcode then
2
when p.projectcode = p.level3projectcode then
3
when p.projectcode = p.level4projectcode then
4
when p.projectcode = p.level5projectcode then
5
when p.projectcode = p.level6projectcode then
6
when p.projectcode = p.level7projectcode then
7
when p.projectcode = p.level8projectcode then
8
end,
case p.isleaf --是否有子节点
when '0' then
1
when '1' then
0
end,
rank,
0,
to_timestamp(to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'), --时间戳
'yyyy-mm-dd hh24:mi:ss')
from dim_chargeproject p,
(select p.projectkey projectkey,
p.projectcode,
p.projectname
,
rank() over(order by p.projectcode) rank --排序号 可能有问题
from dim_chargeproject p) pr
where pr.projectkey = p.projectkey
ps:timestamp 是oracle对date的扩展,其度量精度比date类型更高。
case when 在这条语句中有2个形态,注意语法上些许差别。
上面没有更新commobject表中parent,后面用一条语句更新一下,即根据一张表的数据更新另外一张表相关字段。
--temp22 是一张临时表
update commobject t
set t.parent = (select s.pk2 from temp22 s where s.pk0 = t.id)
where t.id in (select s.pk0 from temp22 s)
mondrian用到的维度表是偏平化结构,所以要去掉非末级节点:
delete from c1_dim_account c1 where c1.id in (
select p.projectkey+500000 pk0 from dim_chargeproject p where p.isleaf=0);
用于管理目的的维度表和mondrian引擎用到的维度表有什么区别呢?
mondrian用到的维度表是偏平化的,管理用的维度需要方便反映上下级层级结构。
为方便后期开发,我们把维度数据存放在2个表中,2个表其实反映的是同一类维度信息。
到此,模拟维度数据准备完毕。
分析表单布局的概念:
第一小节,我们已经介绍过布局的概念,这里以图再说明如下:

(假如对维度不进行分组)

(上图中,分组的情况有7个布局 (不含页面、视点相关布局))
页面、视点可以看成另外隐藏在表单背后的维度的行、列(不是准确描述)。
其余参考我前面写的:非税olap分析平台的设计与实现(一)--数据仓库模型中,相关内容。
整体而言,查询分为三个层次,1)布局类型上的查询、2)特定布局类型、特定组上的查询 3)特定布局查询
获取特定表单 特别布局类型上的List<List<List<DimMember>>> getFormMbrsAsLayoutGroup(formId,layoutType...);
获取特定表单 特别布局类型 特定组 List<List<DimMember>> tempResult = getFormMbrsAsLayout(formId,layoutType,groupId......);
特定布局上的成员的查询:
这样分2种情况:
List<DimMember> layoutMbrs =getMemberWithQueryType(...) 这种情况不展开查询函数;
List<DimMember> layoutMbrs =getMembersByQueryType(...) 这种情况展开查询函数;
实现(由顶层到细节):
1、取得行/列上的集合:
List<List<List<DimMember>>> dimMembers_col = getFormMbrsAsLayoutGroup(form, MConstants.LAYOUT_COL, true);
2、取得一个布局类型的组上的集合,这里布局类型指的是行、列、页面、视点,关键参数为 form、维度类型、组号:
List<List<DimMember>> tempResult = getFormMbrsAsLayout(form,
layoutType, groupPosition, isOpenQueryType);
3、取得一个具体布局类型上 特定组的的布局,由具体布局,获得dimession,.另外一个方法是:考虑到所有组的维度dimesssion 是否也可以根据行列类型,获取所有组的dimession,关键参数为 form、维度类型、组号
List<CFormLayout> getAxisFormLayoutList(int formId,
int groupPosition, int layoutType)
4、上一步获取到的是 :一个特定表单、特定布局类型、特定组上布局信息,考虑到在一个表单 的特定布局上,所有组的类 布局信息是一样的,应该也有其他办法获取相关数据。现在遍历上一步获取到的布局信息,获取一个组内的所有维度成员信息。
List<List<DimMember>> mbrs = new ArrayList<List<DimMember>>();
......
List<DimMember> layoutMbrs = new ArrayList<DimMember>();
for (int i = 0; i < layouts.size(); i++) {
//取得一个特定布局(特定组、特定组内特定的布局)的成员集合List<DimMember>
layoutMbrs = getLayoutMbrs(form.getCubeId(), layouts.get(i),
isOpenQueryType);
mbrs.add(layoutMbrs);
}
5、获取一个布局上,具体维度成员集合:
layoutMbrs = getLayoutMbrs(form.getCubeId(), layouts.get(i),
isOpenQueryType);
这一步,逻辑略复杂。
首先是要获取特定布局上一个维度成员的集合,然后对这个结果进行相关处理::
List<CFormMbr> formMbrs = getFormLayoutMembersByLayoutId(layout.getId());
6、getFormLayoutMembersByLayoutId方法中,通过调用getFormLayoutMembersByLayoutId获取维度成员集合,getFormLayoutMembersByLayoutId方法的实现:
/**
* 通过布局ID获取布局成员列表
*
* @param layoutId
* @return
*/
@Override
public List<CFormMbr> getFormLayoutMembersByLayoutId(int layoutId) {
List<CFormMbr> cFormMbrs=new ArrayList<CFormMbr>();
//方法一 :从数据库当中获取数据
//CFormMbr fomMmeber = new CFormMbr();
// fomMmeber.setLayoutId(layoutId);
// Example<CFormMbr> example = Example.of(fomMmeber);
// List<CFormMbr> formMembers=formMbrMapper.findAll(example);
// return formMembers;
//方法二:从缓存当中获取这个数据
try {
//cFormMbrs=(List<CFormMbr>)cacheHelp.getObjectInCache(Constants.C_FORMMbr,new C_FormMbr_layoutId_PK(false),layoutId);
cFormMbrs=(List<CFormMbr>)cacheHelp.getObjectInCache(CFormMbr.class,new C_FormMbr_layoutId_PK(false),layoutId);
} catch (CacheException e) {
e.printStackTrace();
}
return cFormMbrs;
}
7.getFormLayoutMembersByLayoutId方法中,对特定布局的成员信息(CFormMbr),进行遍历处理:
for (int i = 0; i < formMbrs.size(); i++) {
boolean isCompare = false; //?
DimMember member = null;
memberId = formMbrs.get(i).getMemberId();
queryType = formMbrs.get(i).getQueryType();
if (isOpenQueryType) { //展开的情况
if (formMbrs.get(i).getType() == MConstants.FORM_MBR_TYPE_VAR) {
//todo
.....
} else {
tempMembers = memberEval.getMembersByQueryType(queryType, memberId, cubeId, layout.getDimId());
if (tempMembers != null && tempMembers.size() > 0) {
Iterator<DimMember> memberIterator = tempMembers.iterator();
while (memberIterator.hasNext()) {
DimMember beAddM = memberIterator.next();
boolean isHas = false;
for (DimMember temp : members) {
if (temp.getMemberId() == beAddM.getMemberId()) {
isHas = true;
break;
}
}
if (isHas) {
memberIterator.remove();
}
}
}
members.addAll(tempMembers);
}
} else { //closed node
.....
}
......
}
8.下面,我们只讨论节点是全展开,且是普通节点的情况,关键是下面的的方法,根据memberId 和 query Type,返回相应节点集合,如这个节点quey type是“子代包含”则把相应节点全部返回。
tempMembers = memberEval.getMembersByQueryType(queryType, memberId, cubeId, layout.getDimId());
9.memberEval.getMembersByQueryType方法中,首先要把CFormMbr转为DimMember对象:
DimMember curMember=getMemberInDimByMemberId(memberId, dimId);
具体实现(方法一:从数据库中查的方式):
/**
* 获取维度成员
* @param memberId
* 维度成员ID
* @param dimId
* 维度ID
* @return
*/
@Override
public DimMember getMemberInDimByMemberId(int memberId, int dimId) {
DimMember object=null;
CDimension dimension = getDimInstanceById(dimId);
int obj_type=dimension.getObjType();
switch (obj_type) {
case MConstants.DIM_ACCOUNT:
object =accountMapper.getOne(memberId);
break;
case MConstants.DIM_ENTITY:
object =entityMapper.getOne(memberId);
break;
case MConstants.DIM_YEAR:
object =yearMapper.getOne(memberId);
break;
case MConstants.DIM_PERIOD:
object =periodMapper.getOne(memberId);
break;
case MConstants.DIM_VERSION:
object =versionMapper.getOne(memberId);
break;
case MConstants.DIM_SCENARIO:
object=scenarioMapper.getOne(memberId);
break;
case MConstants.DIM_CURRENCY:
object =curencyMapper.getOne(memberId);
break;
}
return object;
}
从缓存中查的方式:略
定义一张分析表单,需要用到的数据:
1、定义一个表单,当然需要表单本身信息(如名称、说明等);
2、关联的布局信息。

准备事实数据:
insert into c_fact
(project, year, org, version, v)
select CHARGEPROJECT_KEY + 500000 account,
case year_key
when 16 then
60201
when 17 then
60202
when 18 then
60203
when 19 then
60204
end,
421087,
60253,
amt
from FACT_COL_TRADE_DETAIL f
where f.year_key in (16, 17, 18, 19)
本文详细介绍了OLAP分析平台的设计与实现过程,包括维度数据准备、表单布局概念解析及数据仓库模型构建。涵盖维度数据抽取、管理与mondrian引擎应用,以及分析表单的多层次查询实现。
40

被折叠的 条评论
为什么被折叠?



