涉及多维度的业务如何落地实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linfujian1999/article/details/78989648

最近公司的产品系统要重构,但是时间又比较紧迫,所以底层的结构如mongo mq的连接操作就直接用之前的jar包了,目前系统采用的maven多module模块模式,最可耻的是webframework是用的play,而且大家也觉得替换spring在短时间内不好实现。所以只好去把paly服务作为module集成到maven中了,这块任务交到我这里那就做吧,相关资料少之又少,通过git源码及联系原作者,终于用maven play plugin的方式将play集成到maven中去了。下一步我的开发任务便是业务指标的梳理,整体上包括三部分:取数据的dateOperation层、algorithm层及指标计算层:即指标计算层调用其它两层从而计算出指标。
dataOperation层: 1)简单的mongo的crud操作,写成工具类的形式;2)策略模式实现不同的取数及计算规则,返回指标计算想要的中间值。
algor层:仅仅的指标计算的算法,其实就是公式了。没有多余的取数及逻辑
index计算层:在指标计算过程中,用不同的策略计算中间值,然后调用相关算法来计算指标。

以上三层均定义接口及抽象类,java的多态还是蛮有用的。

然后最近在梳理业务,因为有些指标计算不仅是简单的入参然后输出一个指标。譬如:
基金公司的某组合id 一段时间范围内所有的持仓数据
1)根据持仓计算个券的指标
2)将所有的持仓根据type(股票、期货、债券等等)分类,然后计算每一层的指标(sum(权重*个券) )。
3)股票层还要根据行业分类标准分成不同的行业层,每一层计算指标(sum(权重*个券))

呵呵,然后用了二天半时间,不断地推翻重建,终于形成了一套初步的方式。这里分享下,源码如下:


            clientParam.setCollection("bond_position");
            Set<String> keySet = new HashSet<>();
            keySet.add("combination_id");
            keySet.add("date");
            keySet.add("type");
            keySet.add("code");
            keySet.add("name");
            keySet.add("value");
            keySet.add("hq_close_price");
            clientParam.setKey(keySet);
            List<Map<String, Object>> totalBondList = (List<Map<String, Object>>) context.handle(params, clientParam);

            //预处理 dimension的industryNames 及 map<code, level1_name>
            clientParam.clearQueryParameters();
            clientParam.setCollection("stock_category");
            clientParam.setParam("industry_name_cd", "SW");

            params.setParam("keyName", "ticker");
            params.setParam("valName", "level1_name");
            // map<code, level1_name>
            Map<String, String> code_industry = (Map<String, String>) context.handle(params, clientParam);
            //dimension的industryNames
            clientParam.setGroup("$level1_name");
            Stragtegy stragtegy2 = strategy.get("AggregateDataHandleStra");
            context.setStrategy(stragtegy2);
            List<String> industrayList = (List<String>) context.handle(params, clientParam);

            //第一步 根据入参date及type及dimension将结构搭好

            //date结构里放入type结构
            DateModel dateModel = new DateModel();
            for(int type : new ArrayList<Integer>()) {
                TypeModel typemodel = new TypeModel(type, "typeName");
                dateModel.setTypeModel(type, typemodel);
            }
            //type为股票的放入行业结构
            TypeModel typeModel = dateModel.getTypeMap().get(1);
            for(String industryName : industrayList) {
                IndustryModel industryModel = new IndustryModel(industryName);
                typeModel.setIndustryModel(industryName, industryModel);
            }
            //组合层次放入日期结构,此时用到了之前构建好的dateModel结构。
            CombIdModel combIdModel = new CombIdModel(119);

            for(Date date :new ArrayList<Date>()) {
                combIdModel.setDateModel(date, dateModel);
            }

            //第二步 将范围内个券转换成singleBond对象,并将个体对象放到已搭建好的结构combIdModel合适位置
            for(Map<String, Object> single1 : totalBondList) {
                SingleBondModel single = new SingleBondModel();
                //type date用来分类
                int type = Integer.parseInt(single1.get("type").toString());
                Date date = DateUtil.stringToDateGL(single1.get("date").toString());
                String code = single1.get("code").toString();
                //基本信息直接copy
                single.setType(type);
                single.setCode(code);
                single.setDate(date);
                //需要计算的指标计算完毕再set进对象,指标计算走之前的设计逻辑
                Double initWeight = 0.001;
                single.setInitWeight(initWeight);
                single.setIdx(123.0);

                //开始往combIdModel结构中放入 个券放入过程中在相应的层级累加initweight
                if(1== type) {
                    combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).getIndustryModel(code_industry.get(code)).addInitWeight(initWeight).addSingle(single);
                } else {
                    combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).addSingle(single);
                }
            }

            //第三步 开始计算各维度的idx
            combIdModel.calIdx();

一头雾水对吧,其实思想层次是这样:
先根据date type industry 把存放数据的结构建好,就好比你要把一群乞丐放进收容所,你得先把收容所根据性别、年龄等建好男女宿舍、厕所等。
ok,存放数据的结构建好了,下一步就是把数据库取出来的数据封装成SingleBondModel对象并放入合适的位置,这里在循环遍历每一条数据的时候做了两件事:
1、计算个券的指标idx,计算其权重initWeight。连同重要数据一并放入对象中
2、放到它本来应该在的位置,那就根据该单个对象的date、type、industry依次查找直至合适它的位置,在寻找过程中,将包括它的相应层级的initWeight加之

//开始往combIdModel结构中放入 个券放入过程中在相应的层级累加initweight
                if(1== type) {
                    combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).getIndustryModel(code_industry.get(code)).addInitWeight(initWeight).addSingle(single);
                } else {
                    combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).addSingle(single);
                }

最后计算每一层的指标,这里看似只调用了

//第三步 开始计算各维度的idx
            combIdModel.calIdx();

但内部实现原理是这样的:

首先combIdModel不同的层级包含了对应的对象,当调用combIdModel.calIdx()时,首先是计算每一日期的指标,每一日期的指标计算方法中会触发下一级别层次的指标计算,直至找到最底层的SingleBondModel并计算之。

CombIdModel:

//触发该组合下每一个DateModel的指标计算
    @Override
    public void calIdx() {
        for(Date date : dateMap.keySet())
            dateMap.get(date).calIdx();
    }

DateModel:

//计算该DateModel的指标,由CombIdModel层触发
    @Override
    public void calIdx() {
        Double initSum = 0.0D;
        for(int type : typeMap.keySet()) {
            TypeModel typeModel = typeMap.get(type);
            initSum += typeModel.calAndGetIdx() * typeModel.getInitWeight();
        }
        idx =  initSum / initWeight;

TypeModel:


    //在DateModel层调用calAndGetIdx()触发
    @Override
    public void calIdx() {
        if(null!=industryMap)
            calIndustryMap();
        else
            calSingleList();
    }

    public void calIndustryMap() {
        Double initSum = 0.0D;
        for(String industryName : industryMap.keySet()) {
            IndustryModel industryModel = industryMap.get(industryName);
            initSum += industryModel.calAndGetIdx() * industryModel.getInitWeight();
        }
        idx = initSum / initWeight;
    }

    public void calSingleList() {
        Double initSum = 0.0D;
        for(SingleBondModel single : singleList) {
            initSum += single.getIdx() * single.getInitWeight();
        }
        idx = initSum / initWeight;
    }

IndustryModel:

//在TypeModel层调用calAndIdx方法触发
    @Override
    public void calIdx() {
        Double initSum = 0.0D;
        for(SingleBondModel single : singleList) {
            initSum += single.getIdx() * single.getInitWeight();
        }
        idx = initSum / initWeight;
    }

这些model均实现了抽象类

/**
 * model抽象层
 * @author fujian
 *
 */
public abstract class AbstrateModel  implements Model {
    Double idx;
    @Override
    public Double calAndGetIdx() {
        calIdx(); //当前层级下触发计算指标动作
        return idx; //返回指标
    }

    public abstract void calIdx();
}

ok,好久不更博,总结mark下


然后被老板嫌弃 弃用了…………….

猜你喜欢

转载自blog.csdn.net/linfujian1999/article/details/78989648