保险理赔欺诈检测的 Lambda 架构实践
1. 数据模型概述
1.1 实体与关系
在保险业务的数据环境中,存在多个关键实体,如
Claim_status
、
Claim_type
、
Policy_type
等。
Policy_owner
实体包含
PolicyOwnerDOB
(保单所有者出生日期)和
PolicyStartDate
(保单开始日期)列,
Claim
实体有
ClaimWeatherCond
(理赔申请时的天气状况)列。此外,
PO_Drv_Hist
实体存储保单所有者的驾驶历史详细信息,其属性如下:
| 属性 | 描述 |
| ---- | ---- |
| PolicyOwnerId (FK) | 保单所有者 ID(外键) |
| ViolationNum | 违规次数 |
| ViolationSeverity | 违规严重程度 |
| ViolationDate | 违规日期 |
| ViolationDetails | 违规详情 |
PolicyOwner
和
PO_Drv_Hist
实体之间存在一对多关系,即一个保单所有者可能有一个或多个违规记录,如果没有违规记录,则
PO_Drv_Hist
实体中不会有该保单所有者的记录。
1.2 事实模型考量
可以将当前的数据模型视为基于事实的模型。数据模型已处于第三范式,动态表(如
Claim
、
Claim_resubmission
、
Claim_settelement
、
Claim_status
)已有用于捕获日期/时间的列,
Policy
实体也添加了
PolicyStartDate
列。静态表(如
Claim_type
、
Claim_status_type
等)虽无时间戳列,但假设静态数据不变,可对数据进行反规范化处理,用于批量层视图。
2. 欺诈数据条件
为了设计批量层视图,需要明确用于确定欺诈可能性的数据条件:
1. 若客户在过去 12 个月内提交了超过 5 次理赔申请,则其下一次理赔申请可能存在欺诈。
2. 理赔申请时间在晚上 10 点之后,表明存在欺诈可能性。
3. 雪、雨、风暴、雪崩、龙卷风等天气状况下的理赔申请,可能存在欺诈。
4. 过去 12 个月内至少有 2 次严重程度为 1 的违规记录的青少年司机,可能提交欺诈性理赔申请。
5. 过去 12 个月内至少有 3 次严重程度为 1 的违规记录的司机,可能提交欺诈性理赔申请。
保险公司根据其预测模型确定,满足条件(1)以及另外两个条件的理赔申请,需要放入额外评估/调查队列;满足条件 2、3 以及条件 4 或 5 的理赔申请,也需要放入额外评估/调查队列;其他理赔申请则被视为真实申请,可快速处理,无需额外约束。
3. 批量层设计
3.1 数据反规范化
首先对数据进行反规范化处理:
-
理赔相关反规范化
:从
Claim
实体开始,包含
Claim_line_item
、
Claim_status
、
Claim_status_type
和
Claim_type
实体的相关列,仅包含所需列,用于与理赔相关的批量视图。
-
保单相关反规范化
:对
Policy
实体进行反规范化,包含
Policy_owner
和
Policy_type
实体的列,用于与保单相关的批量视图。同时,为两个视图添加
LastModified
属性,以处理时间变化。
反规范化后的实体如下:
| 理赔实体 | 保单实体 |
| ---- | ---- |
| ClaimId
PolicyId (FK)
ClaimSubmissionDate
ClaimSeqId
ClaimAmount
ClaimType
ClaimStatus
ClaimWeatherCond
LastModified | PolicyOwnerId
PolicyOwnerSSNFEIN
PolicyOwnerType
PolicyType
PolicyId
PolicyEndDate
LastModified
PolicyStartDate
PolicyOwnerDOB |
3.2 批量视图设计
理赔相关批量视图
-
视图 1
:统计过去 12 个月内某个保单的理赔申请数量,将数量大于 5 的记录存入临时表,然后将该临时表与反规范化后的
Policy实体连接,获取保单所有者详细信息,构成批量视图。 - 视图 2 :过滤出雪、雨、风暴、雪崩、龙卷风等天气状况下的理赔申请。
保单相关批量视图
-
视图 3
:列出过去 12 个月内至少有 2 次严重程度为 1 的违规记录的青少年司机。先使用
PO_Drv_Hist实体填充一个临时表,存储过去 12 个月内有 2 次或更多严重程度为 1 的违规记录的司机信息,然后使用反规范化后的Policy实体中的DOB过滤出年龄小于等于 19 岁的司机。 - 视图 4 :使用视图 3 创建的临时表,过滤出年龄大于 19 岁的司机。
以下是批量视图设计的 mermaid 流程图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A[数据反规范化]:::process --> B[理赔相关批量视图]:::process
A --> C[保单相关批量视图]:::process
B --> B1[视图 1: 统计理赔数量]:::process
B --> B2[视图 2: 按天气过滤]:::process
C --> C1[视图 3: 青少年违规司机]:::process
C --> C2[视图 4: 成年违规司机]:::process
4. 批量层实现
4.1 存储与分区
使用 HDFS 存储主数据和批量层视图(Hive 表),Hive 用于元数据管理,也可使用 MySQL 存储元数据。为了追加垂直或基于时间的数据,使用 Hive 分区(按日、周或月,根据应用需求而定),以
LastModified
时间戳进行表分区。以下是构成主数据的 Hive 表创建语句:
CREATE TABLE ClaimsMaster(
ClaimId INT,
ClaimSeqId INT,
PolicyId INT,
ClaimSubmissionDate TIMESTAMP,
ClaimType STRING,
ClaimAmount INT,
ClaimSTATUS STRING,
ClaimWeatherCond STRING
)
PARTITIONED BY (LastModified TIMESTAMP)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\;";
CREATE TABLE PolicyMaster(
PolicyId INT,
PolicyOwnerId INT,
PolicyOwnerDOB DATE,
PolicyOwnerSSNFEIN STRING,
PolicyOwnerType STRING,
PolicyType STRING,
PolicyStartDate TIMESTAMP,
PolicyEndDate TIMESTAMP
)
PARTITIONED BY (LastModified TIMESTAMP)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\;";
CREATE TABLE PO_Drv_Hist(
PolicyOwnerId INT,
ViolationNum SMALLINT,
ViolationSeverity TINYINT,
ViolationDate TIMESTAMP,
ViolationDetails STRING
)
PARTITIONED BY (LastModified TIMESTAMP)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\;";
4.2 数据添加
使用动态分区按日(或其他必要频率)添加新数据。以
ClaimsMaster
表为例,创建临时表并添加新分区的步骤如下:
1. 创建外部临时表
ClaimsMaster_stg
:
CREATE EXTERNAL TABLE ClaimsMaster_stg(
ClaimId INT,
ClaimSeqId INT,
PolicyId INT,
ClaimSubmissionDate TIMESTAMP,
ClaimType STRING,
ClaimAmount INT,
ClaimSTATUS STRING,
ClaimWeatherCond STRING,
LastModified TIMESTAMP
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\;"
LOCATION "/InsuranceExample/ClaimsMaster/staging";
-
将临时表数据插入
ClaimsMaster表:
FROM ClaimsMaster_stg INSERT OVERWRITE TABLE ClaimsMaster PARTITION (LastModified)
SELECT ClaimId, ClaimSeqId, PolicyId,
ClaimSubmissionDate, ClaimType, ClaimAmount, ClaimSTATUS, ClaimWeatherCond,
LastModified;
相同的原则可应用于
PolicyMaster
和
PO_Drv_Hist
表,且该过程可自动化和调度。
4.3 批量视图创建
创建
BatchProcHist
表来维护批量视图创建历史:
CREATE TABLE BatchProcHist(
ViewName STRING,
CreatedAt timestamp
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\;";
视图 1:过去 12 个月内提交超过 5 次理赔申请的保单所有者
-- 第一步:获取过去 12 个月内理赔申请超过 5 次的保单列表
Create table ClaimDeftemp1 as
Select PolicyId, count(ClaimId) as Claimcount
from ClaimsMaster
where datediff(current_date, add_months(to_date(ClaimSubmissionDate), 12)) <= 0
group by PolicyId
having count(ClaimId) > 5;
-- 第二步:连接临时表与反规范化的 Policy 实体,获取保单所有者详细信息
Create table ClaimDefView as
Select P.PolicyOwnerID, P.PolicyId, C.Claimcount
from PolicyMaster P, ClaimDeftemp1 C
where P.PolicyId = C.PolicyId;
-- 写入历史表
INSERT INTO TABLE BatchProcHist
VALUES ('ClaimDefView', from_unixtime(unix_timestamp()));
视图 2:按天气条件过滤的理赔申请
-- 创建视图
CREATE table ClaimWeatherView as
Select distinct ClaimId, ClaimWeatherCond
from ClaimsMaster
where ClaimWeatherCond in ('Snow', 'Rain', 'Storm', 'Avalanche', 'Tornado');
-- 写入历史表
INSERT INTO TABLE BatchProcHist
VALUES ('ClaimWeatherView', from_unixtime(unix_timestamp()));
视图 3:过去 12 个月内至少有 2 次严重程度为 1 的违规记录的青少年司机
-- 第一步:获取过去 12 个月内至少有 2 次严重程度为 1 的违规记录的司机列表
Create table TeenageVioltemp1 as
Select PolicyOwnerId, count(ViolationSeverity) as TotalViolations
from PO_Drv_Hist
where (datediff(current_date, add_months(to_date(ViolationDate), 12)) <= 0)
and (ViolationSeverity = 1)
group by PolicyOwnerId
having count(ViolationSeverity) > 2;
-- 第二步:过滤出年龄小于等于 19 岁的司机
Create table TeenageViolView as
Select T.PolicyOwnerId, T.TotalViolations
from TeenageVioltemp1 T, PolicyMaster P
where T.PolicyOwnerId = P.PolicyOwnerId
and (datediff(current_date, add_months(P.PolicyOwnerDOB, 228)) <= 0);
-- 写入历史表
INSERT INTO TABLE BatchProcHist
VALUES ('TeenageViolView', from_unixtime(unix_timestamp()));
视图 4:过去 12 个月内至少有 3 次严重程度为 1 的违规记录的成年司机
-- 第一步:获取过去 12 个月内至少有 3 次严重程度为 1 的违规记录的司机列表
Create table Violtemp1 as
Select PolicyOwnerId, count(ViolationSeverity) as TotalViolations
from PO_Drv_Hist
where (datediff(current_date, add_months(to_date(ViolationDate), 12)) <= 0)
and (ViolationSeverity = 1)
group by PolicyOwnerId
having count(ViolationSeverity) > 3;
-- 第二步:过滤出年龄大于 19 岁的司机
Create table AdultViolView as
Select T.PolicyOwnerId, T.TotalViolations
from Violtemp1 T, PolicyMaster P
where T.PolicyOwnerId = P.PolicyOwnerId
and (datediff(add_months(P.PolicyOwnerDOB, 228), current_date) < 0);
-- 写入历史表
INSERT INTO TABLE BatchProcHist
VALUES ('AdultViolView ', from_unixtime(unix_timestamp()));
重要提示:创建批量视图后,不要忘记删除临时表,否则脚本可能会出错。
5. 服务层实现
5.1 服务层要求
服务层的主要功能是提供批量视图的快速访问,减少延迟。因此,服务层需要是一个专门的分布式数据库,具备以下特性:
- 托管批量视图,支持随机和顺序数据访问(仅读)的良好性能。
- 当批量层重建批量视图时,能够快速替换为新版本(支持批量更新)。
- 具有容错能力,因为视图可从批量层快速重新部署。
- 具备索引功能,以便快速检索数据。
5.2 Splout SQL 应用
使用 Splout SQL 部署批量层视图。Splout SQL 可将批量层视图作为表部署在表空间中,表空间用于分组具有相同键列的表,可使用相同的分区键对多个表进行分区。
表空间设计
观察到批量视图 1、3 和 4 使用
PolicyOwnerId
作为键列,可设计一个包含这三个批量视图的表空间;另一个表空间可包含使用
ClaimId
作为键列的批量视图 2。
表空间生成
使用 “generate” 工具生成表空间,需要使用 JSON 表空间描述符。以
PolicyTblspace
为例,描述符如下:
{
"name": "PolicyTblspace",
"nPartitions": 12,
"partitionedTables": [
{
"name": "ClaimDefView",
"partitionFields": "PolicyOwnerId",
"tableInputs": [
{
"inputType": "HIVE",
"hiveTableName": "ClaimDefView",
"hiveDbName": "MyHiveDB"
}
]
},
{
"name": "TeenageViolView",
"partitionFields": "PolicyOwnerId",
"tableInputs": [
{
"inputType": "HIVE",
"hiveTableName": "TeenageViolView",
"hiveDbName": "MyHiveDB"
}
]
},
{
"name": "AdultViolView",
"partitionFields": "PolicyOwnerId",
"tableInputs": [
{
"inputType": "HIVE",
"hiveTableName": "AdultViolView",
"hiveDbName": "MyHiveDB"
}
]
}
]
}
执行以下命令生成
PolicyTblspace
表空间:
hadoop jar splout-*-hadoop.jar generate -tf file:///`pwd`/PolicyTblspace.json -o out-MyHiveDB_splout_example
索引添加
对于性能优化,可使用
simple-generate
工具添加索引。以
ClaimTblspace
为例,创建带有额外索引的表空间的命令如下:
hadoop jar splout-hadoop-*-hadoop.jar simple-generate –it HIVE –hdb MyHiveDB –htn ClaimWeatherView -o out-MyHiveDB_splout_example -pby ClaimId -p 1 -idx "ClaimWeatherCond" -t ClaimWeatherView -tb ClaimTblspace
表空间部署
生成表空间后,使用以下命令部署:
hadoop jar splout-hadoop-*-hadoop.jar deploy -q http://localhost:4412 -root out-MyHiveDB1_splout_example -ts PolicyTblspace
hadoop jar splout-hadoop-*-hadoop.jar deploy -q http://localhost:4412 -root out-MyHiveDB2_splout_example -ts ClaimTblspace
部署后,可使用 REST API 查询表空间。例如,检查特定理赔申请(
ClaimId=14124736
)是否在恶劣天气条件下提交:
http://localhost:4412/api/query/ClaimTblspace?sql=SELECT * FROM ClaimWeatherView;&key=14124736
6. 速度层实现
6.1 速度层目的
速度层的目的是使批量层视图尚未处理的数据能够无延迟地可用。与批量层视图不同,速度层对视图进行增量处理,仅处理自上次增量处理后执行的新事务。
6.2 异步更新选择
考虑到分析应用更注重复杂计算和聚合,而非交互式用户输入,且数据量较大,异步更新更有用,可更好地控制更新(如临时分配额外请求以处理不同负载)。
6.3 Spark 实现
使用 Spark 和 Spark SQL 实现速度层。以
ClaimDefView_S
视图为例,创建速度层视图的步骤如下:
1. 获取批量视图的最新创建时间:
Create table MaxTable as
select ViewName, max(CreatedAt) as MaxDate
from BatchProcHist
group by ViewName
having ViewName = 'ClaimDefView';
- 获取速度层视图的最新创建时间:
Insert into MaxTable
select ViewName, max(CreatedAt)
from BatchProcHist
group by ViewName
having ViewName = 'ClaimDefView_S';
- 确定最新的创建时间:
Create table MaxTbl1 as
select max(MaxDate) as MaxDate
from MaxTable;
- 获取未处理的记录并创建临时表:
Create table ClaimDeftemp11 as
Select PolicyId, ClaimId
from ClaimsMaster a, MaxTbl1 b
where a.LastModified > b.MaxDate;
Create table ClaimDeftemp12 as
Select PolicyId, count(ClaimId) as Claimcount
from ClaimDeftemp11
where datediff(current_date, add_months(to_date(ClaimSubmissionDate), 12)) <= 0
group by PolicyId
having count(ClaimId) > 5;
-
连接临时表与反规范化的
Policy实体,创建速度层视图并写入历史表:
Create table ClaimDefView_S as
Select P.PolicyOwnerID, P.PolicyId, C.Claimcount
from PolicyMaster P, ClaimDeftemp12 C
where P.PolicyId = C.PolicyId;
INSERT INTO TABLE BatchProcHist
VALUES ('ClaimDefView_S', from_unixtime(unix_timestamp()));
- 删除临时表:
Drop Table MaxTable;
Drop Table MaxTbl1;
Drop Table ClaimDeftemp11;
Drop Table ClaimDeftemp12;
其他速度层视图(如
ClaimWeatherView_S
、
TeenageViolView_S
、
AdultViolView_S
)的创建过程类似。
通过以上步骤,完成了保险理赔欺诈检测的 Lambda 架构实践,包括数据模型设计、批量层实现、服务层部署和速度层处理,能够有效处理保险理赔数据,检测欺诈可能性。
7. 速度层其他视图创建
7.1
ClaimWeatherView_S
视图创建
此视图用于筛选出未处理且天气状况符合欺诈条件的理赔申请。具体步骤如下:
1. 获取批量视图和速度层视图的最新创建时间:
Create table MaxTable as
select ViewName, max(CreatedAt) as MaxDate
from BatchProcHist
group by ViewName
having ViewName = 'ClaimWeatherView';
Insert into MaxTable
select ViewName, max(CreatedAt)
from BatchProcHist
group by ViewName
having ViewName = 'ClaimWeatherView_S';
- 确定最新的创建时间:
Create table MaxTbl1 as
select max(MaxDate) as MaxDate
from MaxTable;
- 创建速度层视图并写入历史表:
CREATE table ClaimWeatherView_S as
Select distinct a.ClaimId, a.ClaimWeatherCond
from ClaimsMaster a, MaxTbl1 b
where a.LastModified > b.MaxDate
and a.ClaimWeatherCond in ('Snow', 'Rain', 'Storm', 'Avalanche', 'Tornado');
INSERT INTO TABLE BatchProcHist
VALUES ('ClaimWeatherView_S', from_unixtime(unix_timestamp()));
- 删除临时表:
Drop Table MaxTable;
Drop Table MaxTbl1;
7.2
TeenageViolView_S
视图创建
该视图用于找出未处理的、过去 12 个月内至少有 2 次严重程度为 1 的违规记录的青少年司机。步骤如下:
1. 获取批量视图和速度层视图的最新创建时间:
Create table MaxTable as
select ViewName, max(CreatedAt) as MaxDate
from BatchProcHist
group by ViewName
having ViewName = 'TeenageViolView';
Insert into MaxTable
select ViewName, max(CreatedAt)
from BatchProcHist
group by ViewName
having ViewName = 'TeenageViolView_S';
- 确定最新的创建时间:
Create table MaxTbl1 as
select max(MaxDate) as MaxDate
from MaxTable;
- 获取未处理的记录并创建临时表:
Create table TeenageVioltemp11 as
Select a.PolicyOwnerId, a.ViolationSeverity
from PO_Drv_Hist a, MaxTbl1 b
where a.LastModified > b.MaxDate;
Create table TeenageVioltemp12 as
Select PolicyOwnerId, count(ViolationSeverity) as TotalViolations
from TeenageVioltemp11
where (datediff(current_date, add_months(to_date(ViolationDate), 12)) <= 0)
and (ViolationSeverity = 1)
group by PolicyOwnerId
having count(ViolationSeverity) > 2;
- 创建速度层视图并写入历史表:
Create table TeenageViolView_S as
Select T.PolicyOwnerId, T.TotalViolations
from TeenageVioltemp12 T, PolicyMaster P
where T.PolicyOwnerId = P.PolicyOwnerId
and (datediff(current_date, add_months(P.PolicyOwnerDOB, 228)) <= 0);
INSERT INTO TABLE BatchProcHist
VALUES ('TeenageViolView_S', from_unixtime(unix_timestamp()));
- 删除临时表:
Drop Table MaxTable;
Drop Table MaxTbl1;
Drop Table TeenageVioltemp11;
Drop Table TeenageVioltemp12;
7.3
AdultViolView_S
视图创建
此视图用于筛选出未处理的、过去 12 个月内至少有 3 次严重程度为 1 的违规记录的成年司机。步骤如下:
1. 获取批量视图和速度层视图的最新创建时间:
Create table MaxTable as
select ViewName, max(CreatedAt) as MaxDate
from BatchProcHist
group by ViewName
having ViewName = 'AdultViolView';
Insert into MaxTable
select ViewName, max(CreatedAt)
from BatchProcHist
group by ViewName
having ViewName = 'AdultViolView_S';
- 确定最新的创建时间:
Create table MaxTbl1 as
select max(MaxDate) as MaxDate
from MaxTable;
- 获取未处理的记录并创建临时表:
Create table Violtemp11 as
Select a.PolicyOwnerId, a.ViolationSeverity
from PO_Drv_Hist a, MaxTbl1 b
where a.LastModified > b.MaxDate;
Create table Violtemp12 as
Select PolicyOwnerId, count(ViolationSeverity) as TotalViolations
from Violtemp11
where (datediff(current_date, add_months(to_date(ViolationDate), 12)) <= 0)
and (ViolationSeverity = 1)
group by PolicyOwnerId
having count(ViolationSeverity) > 3;
- 创建速度层视图并写入历史表:
Create table AdultViolView_S as
Select T.PolicyOwnerId, T.TotalViolations
from Violtemp12 T, PolicyMaster P
where T.PolicyOwnerId = P.PolicyOwnerId
and (datediff(add_months(P.PolicyOwnerDOB, 228), current_date) < 0);
INSERT INTO TABLE BatchProcHist
VALUES ('AdultViolView_S', from_unixtime(unix_timestamp()));
- 删除临时表:
Drop Table MaxTable;
Drop Table MaxTbl1;
Drop Table Violtemp11;
Drop Table Violtemp12;
以下是速度层视图创建的 mermaid 流程图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A[获取批量视图最新时间]:::process --> B[获取速度层视图最新时间]:::process
B --> C[确定最新时间]:::process
C --> D[获取未处理记录]:::process
D --> E[创建临时表]:::process
E --> F[创建速度层视图]:::process
F --> G[写入历史表]:::process
G --> H[删除临时表]:::process
8. 总结
8.1 架构优势
通过 Lambda 架构实现保险理赔欺诈检测,结合了批量层、服务层和速度层的优势。批量层对数据进行全面处理和分析,生成稳定的视图;服务层提供快速的数据访问,减少查询延迟;速度层则能及时处理未被批量层处理的数据,保证数据的实时性。
8.2 操作要点
- 数据处理 :在数据处理过程中,要注意数据的反规范化、分区和增量处理,以提高数据处理效率。
- 视图创建 :创建批量视图和速度层视图时,要合理使用临时表,并及时删除,避免脚本出错。
- 表空间管理 :使用 Splout SQL 管理表空间时,要根据键列合理设计表空间,并可通过添加索引提高查询性能。
8.3 整体流程回顾
| 层次 | 操作内容 |
|---|---|
| 批量层 | 数据反规范化 -> 创建批量视图 -> 存储在 HDFS 和 Hive 中 |
| 服务层 | 使用 Splout SQL 部署表空间 -> 添加索引 -> 部署表空间到分布式数据库 |
| 速度层 | 确定未处理数据 -> 增量处理 -> 创建速度层视图 |
通过以上架构和操作流程,能够有效地对保险理赔数据进行管理和分析,及时发现可能的欺诈行为,为保险公司的风险控制提供有力支持。
超级会员免费看
1446

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



