微软BI 之SSIS 系列 - 使用 Script Component Transformation 转换不规则文件

浏览: 4614

开篇介绍

在 微软BI 之SSIS 系列 - 使用 Script Component Source (脚本任务-源) 解析不规则文件 这篇文章中我们使用到了 Script Component Source 来解决不规则文件的加载与解析操作,同样的我们也完全可以使用 Script Component Transformation 来解决这个问题。

所用的源文件,表结构都和 微软BI 之SSIS 系列 - 使用 Script Component Source (脚本任务-源) 解析不规则文件 是一样的。

Script Component Transformation 的使用

在使用 Script Component Source 的时候,是把 Script Component 当作 Source 源来使用的。在我们这个例子中,则是把 Script Component 当作一个 Transformation 转换控件来使用的,这时我们的数据源是可以在数据流中显示看到的。

创建一个包并创建一个数据流,并在数据流中将文件链接管理器配置好,和上文配置中一样,整个文件的行我们当作一列来使用。

创建一个文件数据源并绑定这个文件链接管理器。

它往下输出的时候是只有一个输出列的。

在数据流中选择 Script Component 并且选择 Transformation 转换功能。

检查 Input Columns 中 Employee 列是否选中。

在 Input and Outputs 选项中,默认显示是 Input0, Output0,我们把 Output0 改为 FILE_MESSAGE,并且按照目标表创建相应的列(可参照 微软BI 之SSIS 系列 - 使用 Script Component Source (脚本任务-源) 解析不规则文件  一文中的格式)。

全部创建完之后的效果。

并且要注意到在两个 Output 处它们的 SynchronousInputID 绑定的是 Input0,即来自于文件源中的输入。这里的 SynchronousInputID 默认是 None 或者 0, 为 None 或者 0 的时候表示这里的 Script Transformation 是异步的,即处理完所有输入之后,再一次性向下游输出, Input 和 Output 是两个不相关的管道,Buffer。如果这里绑定了来自于某一个数据源的 Input,那么表示是同步的,即在 Input 输入到 Script Transformation 的时候来自于 Input 0 中的列将会和 FILE_MESSAGE Output 中的列汇入在一起向下输出,Input0 中的列也会和 EMPLOYEE 中的列汇入在一起向下输出。此时,在 Script 脚本中,ProcessInput 方法里面,这两个 Buffer 即 FILE_MESSAGE 和 EMPLOYEE 都是可以被读取的。

在脚本中,这段代码就非常简单。Input0Buffer 能够直接访问到来自 EMPLOYEE 和 FILE_MESSAGE 中的列就说明了这个组件设置的是同步的。

 public override void Input0_ProcessInputRow(Input0Buffer Row)
{
//string name; //50
//string position; //50
//string hireDate; // 12
//string birthDate; //12
//string email; //12
//string phone; //25
//string marriage; //1

// 如果行以 FILE CREATED DATE 开始
if (Row.EMPLOYEE.StartsWith("FILE CREATED DATE"))
{
// 则只取文件日期部分
Row.FILECREATEDDATE = Row.EMPLOYEE.Substring(19, 10);
}
// 如果达到第二行
else if (Row.EMPLOYEE.StartsWith("TOTAL EMPLOYEES"))
{
Row.TOTALEMPLOYEES
= int.Parse(Row.EMPLOYEE.Substring(16, 10));
}
else if (Row.EMPLOYEE.StartsWith("*"))
{
//不做处理
}
else
{
// 剩下的部分是主体内容部分,直接按照固定的列位置描述截取字符串
Row.NAME = Row.EMPLOYEE.Substring(0, 50);
Row.POSITION
= Row.EMPLOYEE.Substring(50, 50);
Row.HIREDDATE
= Row.EMPLOYEE.Substring(100, 12);
Row.BIRTHDATE
= Row.EMPLOYEE.Substring(112, 12);
Row.EMAIL
= Row.EMPLOYEE.Substring(124, 50);
Row.PHONE
= Row.EMPLOYEE.Substring(174, 25);
Row.MARRIAGE
= Row.EMPLOYEE.Substring(199, 1);
}
}

添加两个 Audit,并添加 PathAnnotation 提示,观察一下两个输出的结果。

执行包并可以看到 Data View 中两个 Output 输出都与 Input0 中的 EMPLOYEE 列汇合了。

再与我之前在其它文章或者 天善学院 的 ETL 课程中总结到的,判断这个转换组件是否是同步还是异步的最简单标准就是:看来自于源比如 A 的数据列在经过这个转换组件比如 B 之后,B 下方的组件 C 是否还能够看到 A 中的原始数据列。

  • 如果不能看到,即为异步转换控件,输入不等于输出。说明在经过转换组件 B 的时候,来自于 A 的 Buffer 到了 B 这个点时,它的生命周期就结束了。B 会重新创建一个新的 Buffer 供 C 来使用,这个新的 Buffer 是经过了一系列的转换变成了一个新的输出。
  • 如果能看到,即为同步转换控件,输入等于输出。说明在经过转换组件 B 的时候,来自于 A 的 Buffer 到了 B 这个点时,它的生命周期并未结束。B 可能创建了一些新的列,但是这些列可能是在数据流执行之初就已经被初始化了,实际上还是同一个 Buffer 向下输出。

先来处理 FILE_MESSAGE 中的输出,添加一个 Conditional Split 条件拆分控件,对照上图只抽取不为空的行数据。

直接绑定 OLE_DB_DESTINATION 并指向目标表。

同样的如法炮制右边 Employee 详细信息处理。

创建 OLE DB Destination 并指向相应的目标表,执行包,左边有 2 条进入,右边有 290 条。

右边是正确的,左边为什么是 2 条呢? 查看数据库可以看到这个结果。 但是,这个已经不是什么问题了,将这两条数据的两个列合并成一条数据我相信已经没有什么难度了,略。

总结

实际上在 微软BI 之SSIS 系列 - 使用 Script Component Source (脚本任务-源) 解析不规则文件 文章中使用 Script Component - Source 这种解法就完全可以解决这个问题,在这里通过这个例子只是为了演示在 Script Component 组件在同步与异步之间的角色转换。

Script Component Source 虽然是转换控件,但是当它作为源的时候,实际上是看不到 Input 配置选项的,并且它的 Output 也是没有办法关联上 Input 的,因此它就是一个 异步转换控件。在 微软BI 之SSIS 系列 - 使用 Script Component Source (脚本任务-源) 解析不规则文件 这篇案例中,它的源是在 Connection Manager 中的文件数据源。

但是在本文的案例中,是可以非常清晰的看到 Input0 输入源,并且可以绑定到这个数据源,这里是一个 同步转换

通过这两篇文章中的案例对比,Script Component 在同步和异步上的表现形式应该是可以看得出来。可以看到在使用 Script Component - Transformation 同步转换的时候,向下输出的 Buffer 带着太多上游来的列,而大多数列下游是不需要的,这一部分是需要我们通过 Conditional Split 去处理,并且最终输出的结果还需要简单的第二次处理。

当然,我们已经使用 Script Component - Source , Script Component - Transformation (同步) 解决了这个不规则文件加载的问题,其实我们还可以通过 Script Component - Transformation (异步) 的方式来解决。那么通过 Transformation 异步方式,我们就可以把关于 Conditional Split 的逻辑判断提前到 Script Component 中,并且来自上游的输出在 Script Component - Transformation (异步) 中经过完全的行清洗之后再创建新的 Buffer 向下输出,这样的数据格式就不需要再额外处理了。

Script Component - Tranformation (异步) 其实有某些场景下使用的非常多,比如在 Script Component 中直接访问 ADO.NET 关联数据库数据,做循环清洗处理再往下输出;比如做统计的用途,统计完所有输入数据后再创建新的 Buffer 往下输出。但关于 Script Component - Tranformation (异步) 的内容就不再一一写了(一篇博客从代码整理,思路整理,语言组织整理,到一个字一个字敲完,差不多一屁股就是2-3个小时 ^_~ .......),只提示下它的实现需要重写一些方法。

那么关于哪一种效率更高,取决你不规则文件的复杂程度,一般情况下没有太大区别。比如一个百万级的简单的不规则文件,我记得大概的数据是差不多 400 M 不到的宽文件在 4G 的小虚机上应该不到 2 分钟就可以全部加载到数据库中。输出的话,印象中大概不到10秒。大家有兴趣的话,可以详细做一下测试。

推荐 0
本文由 BIWORK 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

1 个评论

今天我碰到一个问题,我从源表中抽取事实表数据时,我想根据这个源表的数据去重商品SKU信息,然后追加到商品SKU表(款+色+码)里,因为在维度表里,数据库底层只有一个商品款号级别的表(款),色和码都存在事实表里面的,我从这个非重复的事实表里,我怎样去拿到去重的商品SKU信息,我想用多播的方式把抽取过来的数据另一支流去重SKU后追加到SKU表里,不知道这样的实施和我直接从源库里用DISTINCT事实表里的款+色+码,哪个操作起来比较效率好。感觉去源库里写SELECT DISTINCT,对源库不知道会不会也是个负担。

要回复文章请先登录注册