基于规则的结构化数据知识抽取(二)

为了方便阅读,本文分成三篇文章进行发布,本文介绍抽取程序设计


根据前文设计的抽取规则,基于面向对象思想,采用Java语言设计开发,实现了较好的程序结构设计。

主体程序设计

UML设计如下:

设计说明:

  1. RowData作为核心数据结构,表示表中的一行数据,其他类都需要与RowData交互。为了便于实际数据格式扩展,RowData设计为接口,其方法getValue用于根据字段名获取字段值,并提供两个实现:RowDataFlat和RowDataKV,RowDataFlat表示普通JSON对象格式,可直接根据字段名获取值,RowDataKV是用两个数组分别字段名和字段值。由于getValue方法的参数是字段名,因此RowDataKV内部需要建立一个索引,方便快速找到对应字段的在数组中的位置。
  2. TableExtractor是连接数据与抽取规则、执行表数据抽取的类。为什么不是直接作为入口类(即图中ExtractManager承担的角色)?因为在规则中每个点规则和边规则,都可以指定要抽取的数据源表,规则与表的关系是多对多的关系,这样在抽取过程中,一些源表就可能被多次访问。由于大部分情况下,源表的数据规模都较为庞大、甚至无限(比如流数据),因此重复访问源表导致效率低下甚至完全不可行,所以程序逻辑首先确定源表,对每条数据,依次执行对应的若干条规则的抽取。TableExtractor即针对一个源表进行全部相关规则的抽取。
  3. DataSourceReader用于读取数据源,通过设计接口来支持多种数据源。提供了一个基于MongoDB的实现MongoReader,其配置信息除了数据库表信息以外,还有一个tableFormat字段,用于指定数据存储的格式,从而产生对应的RowDataFlat和RowDataKV数据结构。通过提供新的实现,可以读取其他数据库,不仅可以全量读取,还可以增加查询条件配置进行数据筛选,另外可以对接消息队列(如Kafka),实现流数据的抽取。
  4. Extractor是具体负责知识抽取的类,通过设计为抽象基类,便于节点和关系抽取类进行继承复用,同时方便TableExtractor进行动态调用。Extractor承担了抽取规则与抽取结果的桥梁,逻辑关系如下图所示。
  5. ValueExtractor是值粒度的抽取器,设计为接口,并根据规则定义提供了LiteralExtractor(对应字面值规则)、FieldExtractor(对应“@”规则)、RandomIDExtractor(对应“_”规则),PropExtractor较为特殊,表示属性抽取器,包含了属性ID、名称和属性值的值抽取器。ValueExtractor的extract方法,返回值为JsonElement类型,既支持简单值(如数字、字符串),又可以是对象类型。ValueExtractor通过工厂模式进行实例创建,方便进行规则扩展。
  6. ExtractManager对整个抽取过程进行管理,根据抽取规则和应用配置进行DataSourceReader和TableExtractor的初始化。ExtractManager维护了一个Map<String, TableExtractor>结构,是所有表ID与表抽取器的映射表。ExtractManager执行包括三个阶段:初始化阶段将规则逐条添加到对应的表抽取器中(若表抽取器未初始化先根据表ID先初始化,表ID直接对应了MongoDB中的表名);抽取阶段对各个表抽取器进行遍历,结果统一输出到ExtractResult对象中;输出阶段对ExtractResult中的结果进行序列化。

输出设计

通过ExtractResult进行输出结果收集、格式化输出。考虑几种常见场景:

  • 针对小规模数据,抽取过程可以快速完成,直接通过列表结构保存结果,最后一次性输出或返回
  • 针对大规模数据或抽取过程需要持续很长时间的情况,则需要将结果立即或批量进行输出,这样就可以作为消息队列的消费者、ETL的中间环节。

在MapReduce框架,map过程进行数据转换处理,处理结果结果通过上下文管理器(Context)发送给reduce节点(调用write方法),如下图所示。本程序中的ExtractResult作用就和Context类似。

 MapReduce作为大数据处理的经典框架,将很多分布式处理的很多细节都封装到框架之中,开发人员一般只需要提供合适的map和reduce方法即可,同时也可以根据需要对细节进行配置和定制化设计。这正是框架的内涵!值得我们深入领会学习。

关键业务设计

1、多字段抽取

部分信息抽取支持配置多个字段,包括ID、类型名称、关系的头尾节点ID等。支持多字段的目的是为了和表数据“看齐”,一些表的主键本身就包括多个字段。

程序中通过List<ValueExtractor>来支持多字段抽取。抽取结果通过特殊字符(目前是下划线)进行拼接。

2、冲突检测

规则可能要求对于某些属性是必填的,如果为空,则整条数据无效。规则中通过“mustFields”进行配置。“mustFields”中任意一个字段为空,则说明数据无效,抽取结果产生了“必填冲突”。

程序程序中对相应字段逐个进行检查,一旦不存在或为空,则加入到结果的must字段中,交给后续的知识融合程序进行处理,本程序自身并不进行处理,方便业务系统进行控制。当然,也可以在规则中增加相应的配置项,明确在遇到必填冲突时是否丢弃相应数据。

注意:关系的头尾节点实体都不能为空,这种情况是直接丢弃。

3、结果数据结构

抽取结果的结构设计为{id, name, type, typeId, must, props}的JSON结构,并不扁平化结构,属性都放在props字段中,这样设计的好处是避免属性数据与顶层字段id、name、type等冲突。但是这个问题在业务系统中往往较为棘手,例如常见的图数据库的存储结构设计,一般都是扁平化的(GoIN中基于ClickHosue的知识存储设计、neo4j的属性等),业务系统设计中需要特别注意,如果不小心直接将props提升到JSON顶层,可能导致必需的id、name、type等信息谬误。

接口设计

基于SpringBoot设计restful接口,API定义如下:

POST /_map/table -d ‘<rule-data>’

接口的body参数即前文定义的规则。

返回结果为{code, data }的JSON结构,其中data为{nodes, edges}的JSON对象结构。

设计总结

总结来说,抽取程序设计体现了几个特点:

  • 模块化:将程序划分为抽取管理器(ExtractManager)、数据源(DataSourceReader)、表抽取器(TableExtractor)、规则抽取器(Extractor)、值抽取器(ValueExtractor)等几个部分,各模块职责明确,程序易于维护
  • 高内聚:集中体现在规则抽取器的设计,将规则解析与抽取放到一起,规则修改时,只需要修改相应模块即可
  • 可扩展:各个模块都设计了接口,基于静态工厂进行实例创建,方便规则扩展(增加_、@以外的规则)、数据源扩展、数据格式扩展等。
  • 默认实现:针对数据源、结果输出等模块提供默认实现,方便使用
  • 可配置:针对数据源、数据格式等提供配置文件的配置
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值