QualityStage 使用通过知识专家服务编写的大量巧妙的规则处理要清理的数据。这些规则常常针对特定的领域和特定的数据集构建,并针对特定服务活动进行调解。从一个客户到另一个客户或从一个数据集到另一个数据集的规则的定制涉及到规则的配置,以便协调特定数据源中的不同方面的干扰。
在 RDR 方法中,领域专家会处理各种案例,给出相关建议,并在必要时提供一些功能来证明其建议的合理性。仅在系统不正确地分类某个案例或未能对案例进行分类时,才能添加规则。在系统中创建额外的规则有助于更正错误分类的案例。
使用基于规则的系统对新数据源进行数据清理,需要通过手动干预将规则从一个数据集调整到另一个数据集。因此,以服务的形式提供数据清理需要进行很大的调整,因为需要为不同的数据集定制该工具 (QualityStage Standardization RuleSet)。这是因为 QualityStage 缺乏整合不同数据源的独特异常的能力。这使得将底层数据清理算法 (RuleSet) 从一个数据集迁移到另一个数据集变得很困难。
RDR 框架允许您以递增方式修补现有的规则或添加例外,且无需破坏其他规则。随着规则数量增加,管理它们变得非常困难,很难决定在何处添加新规则。但是如果您使用 RDR 框架编写规则,就会准确知道在何处添加规则,从而可以更轻松地对破坏逻辑的规则进行调试。RDR 还可帮助您识别最常使用的规则,帮助您将它们放在开头部分。所以,如果您要在给定时间范围内清理数百万个地址,可通过支持您对数据进行分段的方式来应用规则。
要执行这里描述的场景,需要安装 InfoSphere QualityStage V8.5 和 Information Services Director。您需要基本了解如何使用模式操作文件 (PAT) 编写标准化规则。关于 PAT 的更多信息,请参阅 参考资料。
在以前,规则集由专家(PAT 代码开发人员)开发,并基于此 PAT 代码对数据进行标准化。但是,此访问无法解决知识的两个重要方面:知识的上下文和不断演化的性质。RDR 背后的基本哲学基于这样的观察结果,专家不会解释他们编写规则的方式,但他们会证明规则是正确的,并在上下文内提供证据。
如图 1 所示,在 RDR 方法中,领域专家会处理案例,给出相关建议(新规则),并提供一些功能来证明其建议的合理性。RDR 框架使用了一种失败驱动的方法。仅在系统错误地分类案例或无法对案例进行分类时才能添加规则。可以在系统中创建额外的规则来解决错误分类的案例。RDR 方法允许对知识库 (RuleSet) 进行增量更改,不会导致对现有知识库或现有规则集的不想要的副作用。在将一条规则添加到专家系统时,提示规则的案例也会与该规则一起存储。
图 1. RDR 中的知识获取过程
在特定规则集上实现 RDR 的第一步是将类似规则聚合到一起,这有助于将规则分组到单个集群中,删除彼此的依赖关系。
第二步是计算每个集群的集群频率,这是该集群中所有规则依赖关系的总和。图 2 显示了从 R1 到 Rn 的规则,它们已分解到集群 C1 到 Cp 中,它们的集群频率显示在每个集群的外部。
第三步是按集群依赖关系的降序对集群进行排序。
图 2. 实现 RDR 的集群规则
这可帮助您识别来自原始规则集的依赖性规则集群,识别没有落入任何上述集群中的规则。如果用不到这些规则,可以删除它们。RDR 实现支持在恰当地放置和集群规则时,不断演化规则集。经常触发的规则可放在开头部分,在大型数据集中实现更高性能。
本文使用一个标准化部件名称的示例,使用一家制造公司的部件名称子程序。该公司拥有数千个部件类型,它们常常改变。该公司需要标准化这些部件类型。每个部件的名称没有固定的格式,但每个部件可能包含以下特性:
- 部件制造商名称 — 由分类符号 R 指定
- 制造部件的地点 — 由分类符号 P 指定
- 部件编号
- 部件类型 — 由分类符号 B 指定
- 制造的部件的目标机器名称 — 由分类符号 M 表示
清单 1 显示了部件名称 QualityStage 规则集的分类文件。
清单 1. 部件名称规则集的样例分类文件
;;QualityStage v8.0 \FORMAT\ SORT=Y ;---------------------------------------------- ; PART NAME CLASSIFICATION TABLE ;---------------------------------------------- ; CLASSIFICATION LEGEND ;---------------------------------------------- ; B - PART TYPE ; D - DIRECTION ; I - INITIALS ; M - MACHINE NAME ; P - PLACE OF MANUFACTURING ; R - MANUFACTURER NAME ;-------------------------------------------- BLOT BLOT B BLOT BLOT B BLOTS BLOT B NORTH NORTH D GRINDER GRINDER M GINDER GRINDER M JAPAN JAPAN P |
表转化过程的输出列如下所示:
- PartName
- PartNumber
- PartManufacturerPlace
- PartManufacturer
- PartMachineName
- PartType
清单 2 显示了部件名称 QualityStage 规则集的字典文件。
清单 2. 部件名称 QualityStage 规则集的样例字典文件
;;QualityStage v8.0 \FORMAT\ SORT=N ;---------------------------------------------- ; PART Dictionary File ;---------------------------------------------- ; Business Intelligence Fields ;---------------------------------------------- PartName C 100 S PartName PartNumber C 20 S PartNumber PartManufacturerPlace C 100 S PartManufacturerPlace PartManufacturer C 100 S PartManufacturer PartMachineName C 100 S PartMachineName PartType C 100 S PartType ;---------------------------------------------- ; Reporting Fields ;---------------------------------------------- UnhandledPattern C 30 S UnhandledPattern UnhandledData C 100 S UnhandledData InputPattern C 30 S InputPattern ExceptionData C 50 S ExceptionData UserOverrideFlag C 6 S UserOverrideFlag |
规则集开发人员构建了一个名为 PartName 的子例程。本文旨在演示 RDR 如何简化此规则集的构建、维护和扩展。
通常,规则按顺序编写。引擎从第一条规则开始,查找与输入模式匹配的规则。以下代码显示了在 QualityStage 中编写的示例规则集,用于标准化没有 RDR 的部件名称。可下载完整的代码(参见 下载)。
清单 3. 没有 RDR 的部件名称的示例规则集
;------------------------------------------------
; PART NAMES COMMON PATTERNS HERE
;------------------------------------------------
\SUB Process_Part
;Clear a temporary variable
**
COPY "" temp
COPY "" temp1
+|+|B|^|&="/"|^|[ {PartType}="" ]
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
CONCAT [4] temp1
CONCAT " " temp
CONCAT [5] temp1
CONCAT " " temp1
CONCAT [6] temp1
COPY temp {PartName}
COPY temp1 {PartNumber}
COPY_A [3] {PartType}
COPY "" temp
COPY "" temp1
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
RETYPE [4] 0
RETYPE [5] 0
RETYPE [6] 0
+|+|M|+|B|[ {PartType}="" ]
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
CONCAT " " temp
CONCAT_A [3] temp
COPY temp {PartMachineName}
COPY [4] {PartName}
COPY_A [5] {PartType}
COPY "" temp
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
RETYPE [4] 0
RETYPE [5] 0
+|+|P|+|B|[ {PartType}="" ]
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
CONCAT " " temp
CONCAT_A [3] temp
COPY temp {PartManufacturerPlace}
COPY [4] {PartName}
COPY_A [5] {PartType}
COPY "" temp
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
RETYPE [4] 0
RETYPE [5] 0
|
一个接一个地编写规则并按相同顺序执行它们,无需考虑为特定数据集触发一条规则的频率。有时规则的编写顺序与规则的执行顺序相同,该顺序取决于与其他规则相关的规则的位置。清单 4 显示了来自同一个标准化部件名称的子例程的两条规则。应该始终在编写第一条规则之后编写第二条规则,因为如果先编写第二条规则,它将错误地处理第一条规则的模式,所以标准化将不准确。因此,规则集开发人员在实现 RDR 时需要了解这些情况。
清单 4. 冲突的规则
+|+|+|B|[ {PT}="" ]
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
CONCAT " " temp
CONCAT [3] temp
COPY temp {PartName}
COPY_A [4] {PartType}
COPY "" temp
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
RETYPE [4] 0
+|+|B|[ {PT}="" ]
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
COPY temp {PartName}
COPY_A [3] {PartType}
COPY "" temp
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
|
实现 RDR 的第一步是标注预先编写的规则,以便标记它们,我们也可以计算为特定数据集触发每条规则的频率。要标注 QualityStage 规则集,规则集开发人员需要在 Dictionary 文件中添加一列。
清单 5. 添加一列来标注 QualityStage 规则集
;;QualityStage v8.0 \FORMAT\ SORT=N ;------------------------------------------------------------------------------- ; PART Dictionary File ;------------------------------------------------------------------------------- ; Annotation Fields ;------------------------------------------------------------------------------- RuleAnnotate C 1500 S RuleAnnotateOutputColumn |
规则集开发人员在开发时应该使用合适的注释标注规则,如果没有,则可以使用一个简单的 Java™ 程序标注 PAT 文件。清单 6 显示了可用于标注 PAT 文件的示例 Java 程序。
清单 6. 标注 PAT 文件的示例 Java 程序
String comment="";
String concat="";
String legend="\\G";
public void annotateRules(String input, String output)
throws FileNotFoundException, IOException
{
BufferedReader br1= new BufferedReader(new FileReader(input));
String line="";
int ruleNumber=1;
PrintWriter p=new PrintWriter(output);
int firstSub=0,flag=0;
while((line=br1.readLine())!=null)
{
line=line.trim();
if(line.startsWith("\\SUB"))
{
System.out.println(legend+" "+(ruleNumber-1));
changeLegend(line);
ruleNumber=1;
p.println(line);
p.flush();
}
else if(line.startsWith(";-----------------RULE"))
{
comment=";-----------------RULE "+ruleNumber+" ------------";
p.println(comment);
p.println();
ruleNumber++;
flag=1;
}
else if(line.startsWith("#") ||line.startsWith("*")
||line.startsWith("0")||line.startsWith("%")
||line.startsWith("[")||line.startsWith("&")
||line.startsWith("!")||line.startsWith("+")
||line.startsWith("^")||line.startsWith("L"))
{
if(flag==0)
{
p.println();
comment=";-----------------RULE "+ruleNumber+" ------------";
p.println(comment);
p.println();
p.println(line);
concat=" CONCAT \""+legend+ruleNumber+"\" RuleOutput";
p.println(concat);
ruleNumber++;
}
else{
p.println(line);
concat=" CONCAT \""+legend+ruleNumber+"\" RuleOutput";
p.println(concat);
flag=0;
}
}
else
{
p.println(line);
}
}
System.out.println(legend+" "+(ruleNumber-1));
p.close();
br1.close();
}
|
清单 7 显示了标注后的 PAT 文件。完整的已标注文件可通过下载获得(参见 下载)。
清单 7. 标注的 PAT 文件
;------------------------------------------------
; PART NAMES COMMON PATTERNS HERE
;------------------------------------------------
\SUB Process_Part
;Clear a temporary variable
;------------RULE 1 -------------
**
COPY "" temp
COPY "" temp1
;------------RULE 2 -------------
+|+|B|^|&="/"|^|[ {PT}="" ]
CONCAT "\P2" {RuleAnnotate}
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
CONCAT [4] temp1
CONCAT " " temp
CONCAT [5] temp1
CONCAT " " temp1
CONCAT [6] temp1
COPY temp {PartName}
COPY temp1 {PartNumber}
COPY_A [3] {PartType}
COPY "" temp
COPY "" temp1
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
RETYPE [4] 0
RETYPE [5] 0
RETYPE [6] 0
;------------RULE 3 --------------
+|+|M|+|B|[ {PartType}="" ]
CONCAT "\P3" {RuleAnnotate}
COPY [1] temp
CONCAT " " temp
CONCAT [2] temp
CONCAT " " temp
CONCAT_A [3] temp
COPY temp {PartMachineName}
COPY [4] {PartName}
COPY_A [5] {PartType}
COPY "" temp
RETYPE [1] 0
RETYPE [2] 0
RETYPE [3] 0
RETYPE [4] 0
RETYPE [5] 0
|
完成标注后,规则集开发人员需要获得为特定数据集(规则是为这些数据集开发或编辑的)触发规则的频率。通过 QualityStage RuleSet 运行数据集。然后,您需要从 RuleAnnotate 列将所生成注释的输出提取到一个独立的 CSV 文件中,然后通过频率生成器程序运行此 CSV 文件。清单 8 显示了示例频率生成器 Java 程序。
清单 8. 频率生成器
Hashtable<String, Integer= areaRules=new Hashtable<String, Integer=();
Hashtable<String, Integer= addrRules=new Hashtable<String, Integer=();
void computeFrequency(String fileName,String outputfile)
throws FileNotFoundException, IOException
{
BufferedReader br1= new BufferedReader(new FileReader(fileName));
String line="";
int totalAreaRules=0;
int totaladdressRules=0;
int totalrows=0;
int maxareaRules=0;
int maxaddrRules=0;
int maxareaRuleorderLength=0;
int maxaddrRuleorderLength=0;
line=br1.readLine();
while((line=br1.readLine())!=null)
{
totalrows++;
line.replaceAll("\"","");
String tokens[]=line.split(",");
if(line.length()>maxareaRuleorderLength)
{
maxareaRuleorderLength=line.length();
}
if(tokens.length=1 && tokens[1].length()=maxaddrRuleorderLength)
{
maxaddrRuleorderLength=tokens[1].length();
}
StringTokenizer st=new StringTokenizer(line,"\\");
int numrules=0;
while(st.hasMoreElements())
{
numrules++;
totalAreaRules++;
Integer count;
String token=st.nextElement().toString();
if((count=areaRules.get(token))!=null)
{
count=count+1;
areaRules.put(token, count);
}
else
{
count=1;
areaRules.put(token, count);
}
}
if(maxareaRules<numrules)
{
maxareaRules=numrules;
}
numrules=0;
if(tokens.length<2)
{
continue;
}
StringTokenizer st1=new StringTokenizer(tokens[1],"\\");
while(st1.hasMoreElements())
{
numrules++;
totaladdressRules++;
Integer count;
String token=st1.nextElement().toString();
if((count=addrRules.get(token))!=null)
{
count=count+1;
addrRules.put(token, count);
}
else
{
count=1;
addrRules.put(token, count);
}
}
if(maxaddrRules<numrules)
{
maxaddrRules=numrules;
}
}
PrintStream p= new PrintStream(outputfile);
Enumeration<String= keys=areaRules.keys();
Enumeration<Integer= values=areaRules.elements();
while(keys.hasMoreElements())
{
p.println(keys.nextElement()+" , "+values.nextElement());
}
p.close();
p=new PrintStream(addrFileName);
keys=addrRules.keys();
values=addrRules.elements();
while(keys.hasMoreElements())
{
p.println(keys.nextElement()+" , "+values.nextElement());
}
p.close();
br1.close();
}
|
清单 9 显示了部件名称子例程的频率输出。第一列是已标注的规则编号,第二列是为示例数据集触发规则的次数。
清单 9. 部件名称子例程的频率输出
P3 2290 P4 2057 P13 1360 P11 1023 P16 1010 P2 908 P12 806 P7 600 P5 254 P14 175 P6 125 P3 117 P15 102 P10 97 P21 82 P20 79 P18 53 P19 32 P8 2 P9 1 P17 0 P22 0 |
下一步是将类似的例程分组到一个独立的子例程中,使它充当着 RDR 中的一个决策分支,以便在特定的输入进入该分支并触发一条规则时,阻止它进入其他分支,模块化规则并提升性能。要集群化类似的规则,则需要在子例程中扫描规则。在我们的示例中,第一个规则 (+|+|B|^|&="/"|^|[ {PartType}=""
]) 将进入 Plus Followed By
Part 的集群中,因为除了 +(未分类令牌的 PAT 表示),在 Part Type (B) 之前没有其他分类。而且类似地,第二个规则 (+|+|M|+|B|[ {PartType}="" ]) 将进入 MachineName Followed By Part 集群,因为 M 是机器名称的分类,MachineName 后面是 Part Type (B)。部件名称子例程可分解为以下集群:
MachineName Followed By PartManufacturerPlaceName Followed By PartMultplePartTypeManufacturerName Followed By PartInitial Followed By PartPlus Followed By PartPartType Followed By PlusPartType Followed By ComplexPartContatainingDirectionalName
相同的标注逻辑和已生成的频率可用于确定信息子例程中的每个规则的位置,如果子例程太大,则可使用相同方法将其进一步分解为其他子例程。创建所有子例程之后,需要从主要流程构建子例程调用它们。根据频率输出(计算集群中所有模式的频率总和之后),您可以推断出所触发的模式的最大数量按 CALL 顺序排列,如清单 10 所示。完整的 RDR 实现的代码可通过下载获得(参见 下载)。
RDR 帮助查找不可用或冗余的规则。从频率输出文件中,您可以看到频率为 0 的规则从不会用到或只为特定数据集触发,规则集开发人员可删除这些规则,或者将它们放在末尾。
清单 10. 调用子例程
;------------------------------------------------
; PART NAMES COMMON PATTERNS HERE
;------------------------------------------------
\SUB Process_Part
;Clear a temporary variable
;-----------------RULE 1 ------------
**
CONCAT "\P1" {RuleAnnotate}
COPY "" temp
COPY "" temp1
*M|*|B
CALL_MachineName_Followed_By_Part
*P|*|B
CALL ManufacturerPlaceName_Followed_By_Part
*B|*|B
CALL MultplePartType
*R|*|B
CALL ManufacturerName_Followed_By_Part
*I|*|B
CALL Initial_Followed_By_Part
*+|B
CALL Plus_Followed_By_Part
*B|+
CALL PartType_Followed_By_Plus
*B|>
CALL PartType_Followed_By_Complex
*D|*|B
CALL PartContatainingDirectionalName
;-----------------RULE 17 ------------
B|^|[ {PartType}="" ]
CONCAT "\P17" {RuleAnnotate}
COPY [2] {PartNumber}
COPY_A [1] {PartType}
COPY "" temp
RETYPE [1] 0
RETYPE [2] 0
\END_SUB
|
顺序单一子例程已借助 RDR 模块化为多个子例程。
建立了初始规则和字典之后,在将规则应用于来自其他一些来源的数据时常常会体验到一定的性能下降。这是因为在我们从一个来源转移到另一个来源时,底层的数据特征会发生更改。集中构建一个新规则集既具有高成本有很耗时。RDR 允许我们以添加到默认规则集的异常的形式捕获新数据的特征。这有助于迅速恢复下降的性能。RDR 支持轻松识别必须添加异常的地方,首先识别基于特定案例发生失败的字段的树,然后识别已失败并且必须使用 TRUE 分支修补异常的树中的规则。可以通过对比手头的案例与已添加异常的节点中的案例来获得上下文。
图 3 和图 4 显示了为新来源修补的规则示例。在默认的规则集中,可以通过使用字典分类令牌来识别部件类型。这些令牌可以是 “bolt”、“nut”、“screw” 等。但是,在某些组织中,最佳做法是将部件类型与部件名称串联。例如,bolt 是一种部件类型,可以将它与 CarriageBolt 等区域名称串联起来,创建部件名称/类型组合(例如 CarriageBolt)。对于这些情形,可添加一条异常规则,将部件指示器处理为令牌中的子字符串。
图 3. 检测对新规则的需要
图 4. 添加规则
RDR 提供了一种方法来标注 QualityStage 规则,以便跟踪规则执行,帮助识别用不到/冗余的规则,还可以帮助实现最优的规则排序(将经常触发的规则放在开头部分,减少标准化流程的执行时间)。RDR 实现的规则集也很容易维护,只要规则集开发人员知道需要新规则的准确位置。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 不带 RDR 的部件名称的样例规则集 | NonRDRPat.zip | 10KB | HTTP |
| 标记了 PAT 的 RDR 实现样例 | AnnotatedPat.zip | 10KB | HTTP |
| 实现了 RDR 的样例规则集 | RDRImplementedPat.zip | 10KB | HTTP |
学习
- 访问 InfoSphere
Information Server 信息中心。
- 了解关于 通过标准化使数据保持一致 的更多信息。
- 在 developerWorks 中国网站 Information Management 专区 了解关于 Information Management 的更多信息。查找技术文档、操作文章、培训、下载、产品信息等。
- 随时关注
developerWorks 技术活动 和 网络广播。
- 在 Twitter 上关注 developerWorks。
获得产品和技术
- 使用 IBM 产品评估试用版软件 构建您的下一个开发项目,可直接从 developerWorks 下载获得。
讨论
- 参与论坛讨论。
- 查阅
developerWorks 博客 并加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。

