使用 WebSphere ILOG JRules 开发保险应用系统
使用 WebSphere ILOG JRules 开发保险应用系统
概述
保险行业在国内是一个充分竞争的行业,竞争的加剧导致保险公司的业务管理等各项费用在增长。而保险公司业务支撑系统的先进性与灵活支撑能力能够在很大程度上降低企业运营成本。目前越来越多的国内外保险公司已经采用 IBM 公司的业务规则管理产品 WebSphere ILOG JRules提升了自己的业务支撑系统,通过降低运营成本与提升业务灵活性来大大增强了企业竞争能力。业务规则管理系统能够给 IT 系统带来两个比较大的变化:
- 简单、灵活、快速地支撑业务变化;
- 让业务管理人员参与管理业务变化;
保险行业同时也是一个快速变化的行业,变化主要来自于政策法规变化、市场竞争、内部组织结构变化、以及各种突发事件等。而对这些变化的支持与响应对保险业务支撑系统提出了很大的挑战。通过使用业务规则管理系统可以轻松应对这些挑战。业务规则管理系统通过把原来硬编码在程序中的业务规则外置出来,集中存放在规则库中,然后通过图形化的、自然语言的形式来书写和管理这些业务规则。保险应用程序则通过规则执行服务器的调用接口来执行这些规则并得到返回结果。这样规则库就变成了保险公司的业务资产,而不是应用开发商的程序代码。在最近新的 IT 体系结构中,如面向服务的架构(SOA)允许应用程序或流程的松耦合。 业务逻辑可在一个业务规则管理系统中封装成决策服务,而这个基于规则的决策服务可被应用程序和流程触发。通过这种分离,业务策略和应用程序体系结构可以异步管理,对业务策略进行更改不需要更改应用程序或流程代码,这样允许业务用户和开发人员管理协作完成业务的变化需求,缩短了系统变更的实现周期。
在保险应用系统中适合使用业务规则管理系统来开发的应用主要包括:
- 自动核保;
- 自动理赔;
- 承保计费;
- 电话销售;
- CRM 营销(包括网店);
- 佣金管理;
图 1. 整个保险业务过程中的业务规则应用点
本文将通过寿险自动核保应用的一个虚拟的业务需求来介绍如何使用 WebSphere ILOG JRules 规则管理系统进行开发。
IBM ILOG JRules 业务规则管理系统简介
ILOG JRules 是一组模块,它们虽然在不同的环境中进行操作,但却共同致力于提供一个复杂的业务规则管理系统。 下图显示了使用这几个不同的模块的环境以及他们是如何通过同步和部署进行协作的。
图 2. ILOG JRules 模块体系结构
基于业务规则的应用程序开发
开发人员利用 Eclipse 内的 Rule Studio 来进行设计、Java 开发和规则项目开发。 使用 Decision Validation Services,他们还可以用真实或虚拟的场景测试规则集,以支持和解决业务用户使用 Rule Team Server 时发现的任何问题。
业务用户的业务规则管理和编写
业务用户使用 Rule Team Server 以在应用程序开发过程中和应用程序被部署到产品之后编写和维护业务规则。业务用户还可以在 Rule Team Server 中执行终端用户测试和模拟。 业务分析人员能够模拟业务结果,对自己的历史数据运行更新的规则,以分析业务变化带来的影响。
政策管理人员和其他业务用户能够使用 Rule Solutions for Office 在一个他们熟悉的环境中编写规则。 RuleDocs 是包含业务规则的 Office 文档。 业务用户可以从 Rule Team Server 发布 RuleDocs,以 Word 或 Excel 格式编辑 RuleDocs,然后再在 Rule Team Server 中更新其变更。
在企业应用程序中集成、监控和审计
规则执行部件可以被集成到企业应用程序中。管理员可访问 Rule Execution Server 控制台以监视已部署的规则集和管理决策服务。 另外他们还可使用决策仓库来执行精细的审计。
在下面的需求开发中我们将会使用到其中的 3 个部件,Rules Studio、Rule Team Server、和 RuleExecution Server。假如你想在你自己的环境中尝试以下开发过程,则需要你已经安装了 ILOG JRules 7.01 或以上版本。
人寿保单自动核保系统
我们采用寿险公司的保单自动核保系统作为原型来开发基于规则的自动核保功能。保单核保在整个保单处理过程中起着关键的质量保障作用。通过建设自动核保系统能够提高保单处理效率,提高保单自动通过率,降低保单处理环节的成本。在保单核保过程中要解决保险条款适应、合规、风险控制等多方面的问题。由于经常有新产品的推出与老产品的升级,核保系统要经常变化以便满足新的核保要求。而核保逻辑又是由大量的业务规则组成,使用硬编码的方式对这些规则的进行管理与运行带来很大的维护成本,而专业的规则管理系统可以避免这个问题,并实现安全、简单、灵活地规则管理与执行。
图 3. 核保系统同其它系统之间的关系
保单可以通过联机(Online)或批处理(Batch)两种方式来执行核保处理。
人寿保单核保需求
在本文我们假设 A 保险公司有一个人寿保险产品 P,使用到这个产品的保单在自动核保时执行下面这些规则:
- R1:投保人必须有工作单位。
- R2:投保人的年收入必须大于 5 万元。
- R3:被保险人的年龄小于 18 或者大于 60 岁则必须通过人工核保。
- R4:保费标准:18-35 岁 1000 元;36-50 岁 1100 元。
这个需求的实现是由前台应用(在线应用或批处理)实例化保单数据,然后把这些数据交给规则执行服务器运行这些规则,然后返回处理结果。结果为:通过、未通过、需要走人工3 种情况。
业务对象设计
我们简化设计核保的业务对象为:
- 个人 (Individual):年龄 (age)、收入 (income)、工作单位 (employer)。
- 保险产品 (Product):编码 (id)、名称 (name)。
- 保单 (Policy):投保人 (applicant)、被保人 (insurant)、保险产品 (product)、处理结果状态 (processStatus)、处理结果消息 (processMsg)、保费(rate)。
图 4. 业务对象类图
业务对象 Java 项目开发
在这里我们根据上面的业务对象开发一个 Java 项目,创建这些业务对象对应的 Java 类,我们让这些类实现 Java 序列化接口,以便可以通过 EJB 来远程调用。假如这些对象在应用系统中已经开发好了,我们也可以直接引用它的 Jar 包。
运行安装好的 ILOG JRules Rule Studio (ZH),然后创建一个 Java 项目,命名为 underwriting-xom。然后在 model 包下创建以下类。
清单 1. Individual.java
package model; public class Individual implements java.io.Serializable { private static final long serialVersionUID = 1L; private int age; private int income; private String employer; public Individual(int age, int income, String employer) { this.age = age; this.income = income; this.employer = employer; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getIncome() { return income; } public void setIncome(int income) { this.income = income; } public String getEmployer() { return employer; } public void setEmployer(String employer) { this.employer = employer; } }
清单 2. Product.java
package model; public class Product implements java.io.Serializable { private static final long serialVersionUID = 1L; private String id; private String name; public Product(String id, String name) { this.id = id; this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
清单 3. Policy.java
package model; public class Policy implements java.io.Serializable { private static final long serialVersionUID = 1L; private Individual applicant; private Individual insurant; private Product product; private int rate; private String processStatus; private String processMsg; public Policy(Individual applicant, Individual insurant, Product product) { this.applicant = applicant; this.insurant = insurant; this.product = product; } public Individual getApplicant() { return applicant; } public void setApplicant(Individual applicant) { this.applicant = applicant; } public Individual getInsurant() { return insurant; } public void setInsurant(Individual insurant) { this.insurant = insurant; } public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } public String getProcessStatus() { return processStatus; } public void setProcessStatus(String processStatus) { this.processStatus = processStatus; } public String getProcessMsg() { return processMsg; } public void setProcessMsg(String processMsg) { this.processMsg = processMsg; } public int getRate() { return rate; } public void setRate(int rate) { this.rate = rate; } }
创建规则项目
在 Rule Studio(zh) 已经创建的 Java 项目对应的工作空间下,创建一个命名为 underwriting-rule 规则项目。在这个工作空间中可以同时开发 Java 代码与业务规则相关内容,并且 Java 项目和规则项目可以在一块进行 Debug。
下图为我们新建了一个规则项目后的 Rule Studio 工作空间。
图 5. 规则开发环境
红色框区 1:有两个项目,一个为 java 项目 underwriting-xom,包含上面所开发的 3 个 java 类。
红色框区 2:规则项目工作导图。可以按照链接逐步完成规则项目的开发。接下来我们就创建 BOM。
创建 BOM(业务对象模型)
BOM(业务对象模型,Business Object Model)是 WebSphere ILOG JRules 的一个核心概念。BOM 是业务规则(自然语言)与应用代码(Java、XML Schema)的连接的桥梁,同时也使得业务规则能够独立于应用代码来编写。前面开发的业务对象 Java 叫做执行对象模型 (XOM: eXecution Object Model )。业务规则、业务对象模型、执行对象模型之间的关系见下图。
图 6. Rule-BOM-XOM 的关系
假如使用 Java 类来作为执行对象的话,执行对象与业务对象之间的映射可以使用默认的类、属性、方法来一一对应。也可以在规则开发环境的 BOM 设计器中通过 Java 代码来进行扩展一些虚拟的属性与方法。例如根据被保人的年龄来在 BOM 中增加一个是否为成年人的虚拟方法 publid boolean isAdult(){return this.age>18;},这个可以在 BOM 设计器中完成,不需要更改 Java 代码。
现在我们基于前面开发的 Java 对象来创建一个 BOM。然后给每个属性一个中文描述。开发界面见下图。
图 7. BOM 开发与词汇编写
红色框区 1:当前操作为 Policy 类(保单)。
红色框区 2:当前操作为 processStatus 属性(处理结果)。
红色框区 3:变更 processStatus 属性的词汇描述。
红色框区 4:使用 processStatus 属性的词汇描述。
注:{this} 为关键字,表示当前处理的保单对象而 {***} 为属性占位符。
通过这种方式把 3 个类的相关属性与方法进行中文词汇描述。只需要对业务规则使用到的属性与方法提供中文词汇描述。
确定规则项目的输入输出参数
规则项目的输入输出参数确定了这个规则项目同外部应用的接口,外部应用通过 Map 键值对的方式来同规则执行服务器来交换数据。对于本例子我们采用 Policy(保单)来作为该规则项目的输入输出参数。见下图。
图 8. 规则项目参数定义
确定规则结构与执行流程
我们首先把核保规则分为通用核保规则、P 保单核保规则、其它保单核保规则多个规则包。在 P 保单核保规则包下再创建保费计算与资格检查两个包。接着在 P 保单规则包下创建一个子规则流,对保单先进行资格检查,然后再计算费率。
图 9. 保单 P 的规则运算流程
然后在根规则包下创建一个主规则流来确定不同类型的保单的规则运算路径。
图 10. 所有保单的运算流程
在这里,需要核保处理的保单进来之后,规则的执行会按照这个主流程来运行:首先执行通用核保规则包下的所有规则,然后再根据保单的类型运行相关保单的核保规则,而对于 P 保单分支对应的条件定义见红色连线,最后退出返回结果到应用程序。规则流中可以嵌套子流程,规则包中可以嵌套子规则包。
业务规则开发
接着我可以在 P 保单规则包中创建前面所定义的业务规则。
R1
新建一个业务规则 投保人必须有工作单位,在规则的辅助编辑器中按下图的步骤完成规则。
图 11. R1:投保人必须有工作单位,业务规则书写步骤
- 打开一个“业务规则辅助编辑器”。创建一个空的“业务规则”,这种规则叫做操作规则。另外还可以创建 决策表、和 决策树。
- 通过点击“选择一个条件”,从下拉框中选择我们前面定义的参数 核保保单。
- 点击 是 再选择保单的属性“投保人”。这些是我们在定义 BOM 时确定的。
- 点击“是” 再选择投保人的属性“工作单位”
- 点击“是” 再选择操作符“为空”。系统会自动根据属性的数据类型来确定可以使用的操作符集合。操作符还可以被定制。
- 在那么操作块中点击“选择一个操作”,选择“设置保单的处理结果为一个字符串” 并设置返回消息。
- 把占位符填上,就完成了一个规则的书写。
R2
参考上面的操作步骤,我们创建这个规则如下。
图 12. R2:投保人的年收入必须大于 5 万元
R3
图 13. R3:被保险人的年龄小于 18 或者大于 60 岁则必须通过人工核保
R4
对于这个规则比较适合使用决策表来处理,操作步骤见下图。
图 14. R4:费率表,决策表开发步骤
- 创建一个 决策表,并输入名称“保费费率”
- 产生了一张空表。其中 A、B、C 为条件列,而 D 为动作列。条件列与动作列可以增加或减少。
- 本规则只有一个条件列与动作列,所以我们删除两个条件列。
- 双击条件列 A 的表头,在条件定义弹出框中定义列条件。可以通过“ctrl+alt+ 空格”热键来选择条件。同时定义动作列的动作为设置保单费率。
- 完成格式的决策表。
- 输入数据的决策表。选中一行,则该行所表达的规则在下面的空白处自动显示出来。(需要配置决策表的属性为显示规则)
这样我们就完成了规则项目的开发。见下图。
图 15. 开发好的规则项目
同步规则项目到 Rule Team Server(RTS)
为集中安全地保存规则并提供给保单政策管理人员方便地管理与变更规则,我把在 Rule Studio 中开发的规则项目同步到基于 ILOG Rule Team Server(RTS) 的规则库中。该工作可以通过在 Rule Studio 中的规则项目上点击右键,然后选择“Rule Team Server”并输入 RTS 的服务器地址 http://server:port/teamserver 与 rtsAdmin/rtsAdmin
用户名与密码来上传项目。上传完毕后登录 Rule Team Server 的 Web 页面后可以看到该规则项目。
RTS 是部署在应用服务器(APP Server)上的一个企业应用(EAR),它通过 JDBC 数据源来访问存放在关系数据库中的规则库。在该环境中可以实现有权限控制的规则管理,包括查询、新建、变更、版本、基线、测试、部署、权限管理等各种功能。
业务管理人员在该环境下完成了规则变更后,可以直接把规则部署到生产环境。技术人员还可以在 Rule Studio 中同步管理人员的变更。或重新创建一个来自于 RTS 规则库中的规则项目。
图 16. RTS 操作界面与规则书写界面
规则执行服务器(RES)集成
ILOG JRules 规则执行服务器(Rule Execution Server)与应用的集成有多种方式。可以采用 J2SE 与 J2EE 或 Web Service 的集成方式。J2SE 的集成方式是通过一组 Java API Jar 包来引用,对应的规则部署方式则一般是通过规则文件,也支持 JDBC 数据库。默认没有提供热部署支持,需要应用程序定制来实现。而 J2EE 或 Web Service 的方式是依赖 Java 应用服务器的(例如 WebSphere Application Server),RES 表现为部署在 APP Server 上的 Resource Adapter 与控制台 Web 应用,规则通过控制台程序可以实现热部署,即应用应用无需中断就可以切换到新部署的规则上。已经部署的规则一般是通过 JDBC Datasource 保存在关系数据库中,也可以保存在文件中。应用程序可以通过 Local/Remote EJB、JMS、Web Service、POJO(应用与 RES 部署在同一个容器中)来与规则执行服务器建立会话然后调用执行。
对于批量处理(Batch)的应用我们建议采用 J2SE 的应用架构,数据与应用在一块,降低协议开销,最大化地提高系统吞吐量。而对于联机处理(OLTP)应用,我们建议采用 J2EE 模式或 Web Service。
针对本应用我们采用使用的比较广泛的 Remote EJB 集成方式,在性能满足的条件下,通过 EJB 接口可以提供给多个前端应用程序来访问(例如联机保单、批处理保单)。在能够运行该例子之前还需要你在你的应用服务器上部署 ILOG JRules 的 EJB Jar 包(对应文件为 jrules-res-session-XXX.jar
,其中 XXX
是对应的应用服务器名)。
创建规则应用项目(RuleApp)
我们在 Rule Studio 中创建一个规则应用程序(Rule APP)的项目并把刚才创建的规则项目加入进来。规则应用程序是用来封装规则项目的,只与规则相关,不包含任何客户段代码。规则应用可以放入多个规则项目,每个规则项目对应一个规则集(RuleSet),规则集是最小的发布单元,也是客户端程序调用的入口。
在这里我们创建了一个 underwriting-app 项目并加入 underwriting-rule 规则项目,其对应的规则应用名称 underwritingapp 规则集名称为underwritingrule。那么客户端调用核保规则的入口参数就是 underwritingapp/ underwritingrule。标准的规则集字串格式为:“规则应用程序名 /[ 版本 ]/ 规则集名称 /[ 版本 ]”。不写版本信息则执行最新版本。
同样名称的 RuleApp 也可以在 Rule Team Server 上来创建。这样规则可以同时在 Rule Studio 和 Rule Team Server 上来进行部署。
把规则应用(RuleApp)部署到 RES 上
然后我们把这个规则应用程序部署到 RES 规则执行服务器 上。通过在 underwriting-app 项目上点击右键,然后选择 RuleApp,选择部署,下一步输入 RES 服务器的 http://server:port/res 和 resAdmin/resAdmin 用户名与密码部署。这样规则项目被部署到执行服务器上去,规则执行服务器就可以被外部应用来调用了。
接着我们登录 RES 的控制台查看部署过来的规则。通过控制台我们发现,在执行服务器中可以同时部署多个规则应用,每个规则应用又可包含多个规则项目(规则集),每个规则应用与规则集有可以有不同的执行版本。
图 17. RES 控制台 - 已部署的核保规则应用
开发 EJB 集成客户端代码
我们使用 ILOG JRules 提供的 API 来开发 EJB 客户端,本代码调用部署在 WebSphere Application Server 上的 RES 服务。代码如下:
清单 4. ILOGRuleRemoteRunner.java
package client; import ilog.rules.bres.session.IlrRuleSessionProvider; import ilog.rules.bres.session.IlrRuleSessionProviderFactory; import ilog.rules.bres.session.IlrSessionDescriptor; import ilog.rules.bres.session.IlrSessionExecutionSettings; import ilog.rules.bres.session.IlrSessionParameters; import ilog.rules.bres.session.IlrSessionRequest; import ilog.rules.bres.session.IlrSessionResponse; import ilog.rules.bres.session.IlrStatelessRuleSession; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import javax.naming.Context; import model.Individual; import model.Policy; import model.Product; public class ILOGRuleRemoteRunner { private Map inputParams = new HashMap(); private IlrSessionResponse response = null; private IlrSessionRequest sessionRequest = null; private IlrStatelessRuleSession statelessRuleSession = null; public void init(String rulesetPath) throws Exception{ sessionRequest = new IlrSessionRequest(rulesetPath); Properties jndiProperties = new Properties(); jndiProperties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"); jndiProperties.setProperty(Context.PROVIDER_URL, "corbaloc:iiop:localhost:2809"); IlrRuleSessionProvider provider = new IlrRuleSessionProviderFactory.Builder(jndiProperties).build(); statelessRuleSession = provider.createStatelessRuleSession(); } public void setInputParam(String paramName, Object paramValue){ inputParams.put(paramName, paramValue); } public Object getOutputParam(String paramName){ if(response == null) { return null; } return response.getExecutionResult() .getOutputParameters().getObjectValue(paramName); } public void executeRuleset()throws Exception { IlrSessionExecutionSettings execSettings = sessionRequest.getExecutionSettings(); IlrSessionParameters parameters = execSettings.getInputParameters(); Iterator it = inputParams.keySet().iterator(); while(it.hasNext()){ String paramName = (String)it.next(); parameters.setParameter(paramName, inputParams.get(paramName)); } response = statelessRuleSession.executeRules(sessionRequest); } public static void main(String[] args) throws Exception { //sample ILOGRuleRemoteRunner theRunner = new ILOGRuleRemoteRunner(); try{ theRunner.init("/underwritingapp/underwritingrule"); //Prepare your java object here Individual aIndividual = new Individual(30, 100000, null); Product aProduct = new Product("P", "P 保险产品"); Policy aPolicy = new Policy(aIndividual, aIndividual, aProduct); //set the rule set exeuction parameter theRunner.setInputParam("policy", aPolicy); //execute the rule set theRunner.executeRuleset(); //get the result aPolicy = (Policy)theRunner.getOutputParam("policy"); //print the result System.out.println("return code: " + aPolicy.getProcessStatus()); System.out.println("return message is: " + aPolicy.getProcessMsg()); }catch(Exception e) { e.printStackTrace(); } } }
我们在 Eclipse 中运行这个类的 main 方法,得到的结果截图如下:
图 18. 投保人没有单位的执行结果
我们修改 main 方法的代码,给投保人加上单位,计算费率结果截图如下:
图 19. 核保通过,30 岁的费率标准为 1000
后续的工作
这样保险应用系统的两个主要的开发内容规则开发与应用集成就完成了。以后该自动核保应用可以通过维护业务规则来满足业务发展的需要,而不需要再变更代码。规则所有的变更轨迹都在 RTS 的规则库中详细保存,增强了业务的可审计性、可跟踪性,并有利于业务优化。
总结
基于业务规则管理系统(BRMS)的保险应用系统的开发能够简化系统的架构,使得应用程序处理逻辑与业务规则分离,业务规则可以独立于应用程序来使用简单易用的工具与方法进行管理,大大提高了保险公司业务支撑能力。