当前位置:首页 期刊杂志

基于语法树的批价优惠研究与设计

时间:2024-07-28

王爱平,国玮玮,李仿华,徐晓艳

(安徽大学 计算机科学与技术学院,安徽 合肥 230039)

计费系统[1]是电信运营商业务支撑系统中最为核心的部分,其灵活性、响应速度、支撑能力的高低也在很大程度上决定了前端业务模式的多样性和客户体验的满意程度。随着电信行业的发展,电信运营商需要构建一个能够支持3G网络多业务发展的融合计费系统,以满足复杂的资费套餐以及多业务融合的需求[2]。

面对更加复杂的全业务运营模式,运营商想要推出适应全业务运营环境下的计费系统,必然需要对原有的计费系统进行整合和改造。为了提高计费系统性能、支持多业务组合、个性化资费套餐灵活配置的能力,本文提出了基于语法树的批价优惠方法。

1业务介绍

计费系统框架图如图1所示,计费系统的核心是批价优惠处理,批价优惠分为三种类型:前向优惠、优惠和后向优惠。传统上的套餐是指优惠,前向优惠和后向优惠是优惠的补充,主要是针对所有用户的计费策略,可以把其视为标准资费的补充。批价优惠处理的过程是,首先与局数据 (公共数据中心)建立连接进行全局零件库加载操作 (这里的局数据存储在内存数据库MDB[3]中),然后创建业务处理线程(如网络服务线程、读文件处理线程、业务处理线程、写文件处理线程等),根据业务导航将CDR话单类 (如语音话单、数据业务话单、GPRS话单、VPMN话单等)分配给不同业务处理线程处理,即对用户话单中的费用进行优惠。

图1 计费系统框架图

用户订购的每一个套餐资费即记账资费包括多个子项,这些子项称之为子记账资费,每一个子记账资费对应的有一个费率方案和一种场景,每一个费率方案由不同的零件组合而成,场景是用户打电话产生的信息,包括用户品牌、日期、地区、呼叫类型、用户类型、费用类型等。优惠过程实质上是用记帐计费,子记帐资费再到优惠零件一级一级分解任务并执行任务的过程,因此,优惠过程是一个子记帐资费作用效果的描述串。这里记帐资费与子记帐资费的关系通过语法树实现,每一个子记帐资费唯一地使用一个优惠零件,即优惠规则,且唯一地匹配一套参数,理论上,由于采用纵表结构的优惠零件具有扩展性,因此所有的优惠计费策略都可以通过优惠零件来实现。所以在最关键的优惠处理过程中,用户订购的每一种记帐资费都可以通过优惠语法树进行描述、解析、计算。

2语法树与零件设计

2.1优惠语法树

2.1.1语法树定义

语法树是一棵二叉树,其中非叶子节点的值为子节点或子树之间的关系,叶子节点为记账资费或者子记账资费。定义了以下五种业务关系:

(1)互斥关系(mut):两节点之间只能取一个节点执行(子记帐资费)。先执行左节点,如果符合优惠条件则执行优惠,否则执行右节点。

(2)叠加关系(add):在左节点优惠的基础上,再执行右节点。

(3)最优关系(max):取两个节点最大优惠值。分别执行两个子节点,然后进行比较,取优惠值最大节点。

(4)最劣关系(min):取两个子节点最小优惠值,max的逆操作。

(5)特殊叠加关系(mad):针对分段的费用对象取最优后进行组合,颗粒度更细,其他关系针对整段费用对象做总费用判断。一般针对打折跟忙闲时类优惠做mad的分时段最优处理。即在add的基础上,针对费用对象分段考虑。

2.1.2构建语法树

假如用户定购了 A、B、C三个记帐资费,A和 B两个资费为互斥关系,A的子资费表达式为add(F01,F02),B的子资费表达式为 add(F03,F04),C的子资费表达式为 add(F05,F06)。记账资费的优先顺序为:A、B、C,所以资费表达式为:add(mut(add(a,b),add(c,b)),add(e,f)),优惠语法树构造如图2所示。

图2 语法树

用户订购的所有套餐需要先按照优先级进行排序,以保证语法树的唯一性,然后按照套餐间的关系以及业务类型来生成记帐资费表达式。其实就是将所有的套餐构造一颗二叉树的过程。

2.2优惠零件

(1)优惠零件定义

基本零件:也称简单零件,打折、置费率、减值优惠零件,实现最基础的操作。

派生零件:也称复杂零件,是在简单零件的基础上增加条件功能或者辅助逻辑功能,组合成功能更健壮的优惠零件,如图3所示。

图3 优惠零件

(2)优惠零件模板定义

在计费系统里,具体的计费优惠规则是体现在优惠零件里,根据优惠的业务特点把相近的一批优惠规则提炼出来,用一段简单的代码来实现这些规则,每一个优惠零件都代表了一种优惠规则。先使用C++模板[4]定义优惠零件,再用零件的有限组合构成各种优惠类型。

模板定义如下:

cFavBase:每个具体的优惠零件都需要继承优惠零件基类;

cFav000:对费用对象赋值的最基本的优惠零件,所有优惠零件最后都是归结为对次优惠零件的调用;

cFav001:基本打折类优惠零件;

cFav002:简单分段优惠零件;

cFav003:忙闲时类优惠零件;

cFav004:节假日简单无阶梯话单优惠类零件;

cFav005:亲情号码优惠零件;

cFav006:小区优惠零件。

因此可以组成多种优惠类型,举例如下:

基本打折类优惠零件:cFav001<cFav000>;

忙 闲 时 类 优 惠 零 件 :cFav001<cFav003<cFav000,cFav000>>;

节假日简单无阶梯话单优惠类:cFav001<cFav004<cFav000>>;

亲情号码优惠:cFav001<cFav009<cFav000>>;

所以节假日,亲情号码与忙闲时:

cFav001 <cFav004 <cFav009 <cFav003 <cFav000,cFav000>>>>

3语法树处理的C++实现

图4是批价优惠处理的实现类图,为了简明只给出基本的属性和方法,图中 cDataBase是 CDR、cFeeObj、cUserInfoNode、cStatisObj、cFavProc 的基类。 话单基类 CDR存放话单的基本信息和中间变量结构体等信息,费用对象类cFeeObj创建费用对象,cUserInfoNode用于生成用户资料节点地址对象,引用用户信息类cUserInfo类来创建用户资料节点上的记帐资费语法树,cStatisObj类负责创建累计对象,cFavProc类负责创建优惠过程对象。

图4 业务处理类

3.1记账资费表达式的解析和调用

首先按照优先级对cUserInfo中的所有套餐进行排序,然后按照套餐间的关系以及业务类型生成记账资费表达式,其实就是将所有的套餐构造成一颗二叉树的过程。下面以语音业务的记账资费表达式为例说明表达式的解析和调用的过程。语音业务的优惠语法树如图5所示, 生成的记账资费表达式为 2:add(2:add(1:nam1e:index:effdate:expdate:type:id,1:name:index:effdate:expdate:type:id),0:subname:index)。

图5 语音业务的优惠语法树

从图5可以看出记账资费表达式的结构实际上是一颗二叉树,解析记账资费表达式的过程是先将表达式中信息放到一个结构体p,属性有节点类型type、函数名称 name、左子树 pl、右子树 pr、生效日期 effDate、失效日期expDate、索引index等。下面对记账资费表达式构成的树中的节点进行说明:

(1)以“2:”开头,称之为函数节点,表明此节点有子节点(记账资费或子记账资费);“2:add”中的 2代表节点类型,add代表函数,表示子节点之间的关系,其中“add”表示子节点之间为叠加关系,执行左节点后又执行右节点,经过解析之后,p.type=2、p.name=函数名、p.pl=左子树、p.pr=右子树。

(2)以“1:”开头,称之为记账资费节点,此节点为叶子节点 , 比如 :1:name:index:effdate:expdate:type:id 分别代表的含义为节点类型、记账资费名称、索引、开始时间、失效时间、业务类型、产品id;表达式经过解析后p.type=1、p.name=记账资费名称、p.index=索引、p.effData=开始时间、p.expData=失效时间。

(3)以“0:”开头,称之为子记账资费节点,此节点为叶子节点,比如:0:c1:18258分别代表的含义为节点类型、子记账资费名称、索引,表达式经过解析后,p.type=0、p.name=子记账资费名称、p.index=索引。

根据记账资费表达式进行批价处理函数为favProcess(…char*expression,int sFlag..),先声明一个结构体变量p,对表达式expression进行解析并将相关的信息存放到变量p中,然后根据p.type和p.name做不同的递归调用。

(1)当 p.type=2、p.name=mut:若 favProcess(…p.pl,int sFlag..)的返回值不等于0时,整个函数返回整个返回值;否则 返 回 favProcess(..p.pr,intsFlag..);当 p.name=add、min、max或者mad时进行不同方式的递归调用。

(2)当p.type=1时,根据 p.index从局数据中获取名为p.name记账资费的子记账资费的组合表达式billpalnexp, 然后 递归执行 favProcess(…billpalnexp,int sFlag..)。

(3)当p.type=0时,根据 p.index从局数据中获取名为p.name的子记账资费的详细信息,生成子记账资费费率计划对象T_PP_SubPrcPLAN*pSubBillPlan并调用函数 execSubBillPlan(…expnod.name… ,pSubBillPlan,…),再将其返回值作为favProcess的返回值;执行execSubBillPlan的过程实际上就是调用优惠零件的过程。

3.2优惠零件调用

因为优惠模板种类太多,挑出其中最基本的cFavBase、cFav000、cFav001和 cFav002作为示例,类关系如图6所示,图中,类cFavBase是所有优惠零件的基类,每个具体的优惠零件都由它派生出来,并实现其中参数初始化和优惠过程的接口;cFav000是cFavBase的子类,它是对费用对象赋值的最基本的优惠零件,所有优惠零件最后都归结为对此优惠零件的调用;cFav001是基本打折类优惠零件;cFav002是简单优惠分段优惠零件。

图6 优惠零件类图

调 用 exeSubBillPlan(cFeeObj*pFeeObj…T_PP_SubPrcPLAN*pSubBillPlan…)函数时,实际上是根据子记账资费调用优惠零件进行批价处理。不同的子记账资费的优惠零件模板可能不一样,但是它们的核心处理过程process最终都会调用最简单的优惠零件(cFav000)的处理函数。下面以简单分段优惠零件组合为例,阐述优惠零件的调用过程,图7为一个简单分段优惠的子记账资费的参数列表。

图7 简单分段优惠的子记账资费的参数

(1)创建优惠零件cFavBase*p=new cFav001<cFav002<cFav000,cFav000>>:创建零件时,cFav002<cFav000,cFav000>将被实例化作为 cFav001的成员 T*pFavBase;同时 cFav000和 cFav000分别实例化为T1*pltFavBase(小于等于阈值ThresholdVal用到的具体的优惠零件)和 T2*pgtFavBase(大于阈值 ThresholdVal用到的具体的优惠零件)。

(2)参数初始化 p->initPara():从子记账资费参数中读出 conditionCode和 bill_rebill_flag,然后调用 cFav002<cFav000,cFav000>(pFavBase)的初始化操作,读出其中的ThresholdVal、Thresholdtype、feetype 和 unit,同时调用两 个cFav000(pltFavBase和 pgtFavBase)的初始化操作,将前缀lt和gt的参数项分别赋值给pltFavBase和pgtFavBase。

(3)优惠过程p->process():首先获取话单的相关条件信息(如通话类型,漫游类型,对端类型,费用类型等)和标批二批标识,然后与子记账中conditionCode限制的相关条件信息进行匹配,若匹配失败则返回0;若成功,继续调用 cFav002<cFav000,cFav000>(pPavBase)的优惠过程,根据话单中的计费量与阈值的关系,最终调用cFav000 的优惠过程,即将 feetype、value、unit、favortype 等值传递给费用对象feeObj,让其负责最后费用的计算。

本文通过对移动计费系统批价优惠业务的分析,提出了一种基于语法树的优惠方法并使用面向对象语言C++的模板类设计了语法树的解析和调用过程,构建优惠语法树实现多套餐的叠加优惠,调用配置好的优惠零件使得程序具有更高的灵活性。该方法实现了各种复杂的优惠逻辑组合,可以支撑灵活的市场营销策略,提高了计费系统的支撑能力,在理论和实践上给出了一个电信行业计费系统应用中的解决方案。

[1]陈龙,张春红,云亮,等.电信运营支撑系统[M].北京:人民邮电出版社,2007.

[2]倪然.融合计费:全业务运营的必由之路[J].通讯世界,2008(11):88.

[3]刘全.内存数据库在帐务后台中的应用[D].南京:南京理工大学,2004.

[4]LAFORE R.C++面向对象程序设计 [M].邓子梁译.北京:中国电力出版社,2004.

免责声明

我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!