从非结构化信息中获得更多的价值。研究一个简单的文本挖掘应用程序如何使用 UIMA SDK 构建的文本分析引擎在文档中寻找人名。然后,另一个 UIMA 组件将结果写入 DB2® 数据库中的表。然后利用这些数据,使用 DB2 Intelligent Miner 寻找在文档中经常同时提到的人之间的强关联。
简介
人们越来越希望使用信息技术从组织中的非结构化信息中获得更大的价值。IBM 最近引入了新的 Unstructured Information Management Architecture(UIMA)框架(参见 参考资料),这个框架简化了分析非结构化媒体对象(比如文档)的系统的开发和部署,可以用来提供语义搜索和文本挖掘等功能。文本挖掘就是用于从文本中提取信息的数据挖掘技术。接下来,详细描述一个非常简单的文本挖掘应用程序。
概述
本文中描述的文本挖掘应用程序称为 Preston,它对文档进行分析,寻找提到的人名,并使用文本挖掘寻找常常同时提到的人。尽管这种技术只是众多有用的文本挖掘技术之一,但是它演示了这类应用程序的主要特性,并为介绍 UIMA 的使用提供了一个具体示例。它还演示了如何组合结构化数据库和文本挖掘。本文面对的读者是希望了解如何使用新的 UIMA 技术将非结构化和结构化信息联系在一起的人。
图 1 给出了 Preston 的概况。这个程序对存储为 DB2 数据库表中的文本字段的文档进行分析。UIMA 框架中的组件从数据库读取并分析文档,寻找以某种格式提到的名称,然后将结果写到另一个数据库 Extracted Information Database(EIDB) 中。这些组件是使用 UIMA SDK 中的工具开发和部署的,UIMA SDK 可以从 developerWorks 获得(参见 参考资料)。对 EIDB 中的信息要进行分析后处理,以便准备进行文本挖掘,这是使用 DB2 Intelligent Miner 完成的。整个应用程序可以很容易地在笔记本计算机上运行。
图 1. 本文中描述的 Preston 文本挖掘应用程序的概况
在本文中作为示例使用的文档是来自 Internet Movie Database(IMDB)的演员和其他人员的传记信息(参见 参考资料)。为了进行说明,我使用 IMDB 内容的子集构建了一个 DB2 结构化数据库,将这些传记信息作为文本字段保存在数据库中。
用 UIMA 进行文本分析
UIMA 组件从源数据中的非结构化数据字段中提取出结构化的数据。不同的组件从源数据库中读取文档、分析文档来寻找提到的人名以及将结果保存到一个新数据库(Extracted Information Database,EIDB)中。
文档是由 SQLReader 从源数据库中读取的,这个组件实现了 UIMA 的 CollectionReader 接口,是使用 SDK 开发的。当 UIMA 框架调用 SQLReader 的初始化方法时,它使用 JDBC™ 连接到数据库并发出一个 SQL SELECT 语句,这个语句在 SQLReader 存储的 ResultSet 对象中返回需要的数据,比如文本字符串。然后,这个框架使用 CollectionReader 接口的迭代器类方法(比如 getNext())实际地获取每个文档的文本和元数据。这些数据在一个 UIMA 定义的数据对象中返回给框架,这个对象称为 Common Analysis Structure(CAS)。实际上,因为正在分析文本文档,所以这个数据对象是文本 CAS(TCAS),但是为了简单,本文忽略这一区别,只讨论 CAS。当框架调用 getNext 时,它提供一个空的 CAS。SQLReader 用来自 ResultSet 中当前行的数据填充 CAS。所需代码的结构见 清单 1。它显示了如何将来自输入表的 TRIVIA 列的文档文本和一些元数据(比如文档的 URI)放进 CAS 中。SQLReader 还必须实现 hasNext() 方法(这里未显示)以便完成迭代器接口。
清单 1. 在 SQLReader 的 getNext 方法中对 CAS 进行初始化。为了简单,省略了错误检查。 Connection conn;
ResultSet rs;
// Not shown: code to set up the Connection and to
// populate the ResultSet from the input database
public void getNext( CAS cas) {
// Not shown: code to check that the ResultSet contains more data
// Get the document text and put it into the CAS
String content = resultSet.getString( "TRIVIA"); //get document text
JCas jcas = cas.getJCas();
jcas.setDocumentText( content); // set document text
// Construct a URI for this document
String id = rs.getString( idColName); // get primary key
String url = conn.getMetaData().getURL(); // database URL
String uri = url + "/" + tableName + "/" + idColName + "#" + id;
// set URI into a SourceDocumentInfo
SourceDocumentInfo docInfo = new SourceDocumentInfo( jcas);
docInfo.setURI( uri); // set uri feature value
docInfo.addToIndexes();
// Advance to next row in the ResultSet
nextRow();
}
使用一个 XML 描述符文件让 UIMA 框架了解 SQLReader。每个 UIMA 组件都有这样的文件,可以使用 SDK 中的工具或手工创建这种文件。描述符指向组件的实现,在这种情况下是一个类文件,还包含组件需要的任何配置信息。对于 SQLReader,描述符包含源数据库的 URL 和登录所需的用户 id/密码等信息。在进行初始化时,使用 UIMA 提供的方法读取这些信息。
描述符中另一个非常重要的信息是组件使用的类型系统的引用。CAS 将数据存储为有类型的结构,类型系统定义了类型以及类型之间的关系。图 2 显示 Preston 中使用的类型系统。类型系统是使用 SDK 工具定义的,这些工具还创建与类型系统中的类型对应的 Java ™ 类。清单 1 中的 SourceDocumentInfo 就是这样的类。它的 URI 属性用于保存 SQLReader 创建的文档 URI。(在 UIMA 处理结束时,这个 URI 将从 CAS 复制到 EIDB 中。)
图 2. Preston 使用的 UIMA 类型系统。内置的 UIMA 类型名显示为斜体。箭头指出继承关系。
当框架从 SQLReader 获得了 CAS 之后,将它传递给一个文本分析引擎(text analysis engine,TAE) 以便进行实际的分析。TAE 可以很复杂,由几个组件组成,包括其他 TAE。但是,在 Preston 中,TAE 只包含一个组件 NameReferenceAnnotator,这个组件实现了 UIMA 定义的 Annotator 接口。标注器是基本的文本分析组件。它的工作是使用提供给它的 CAS 中的信息(也就是文档文本),寻找一些新数据,然后将这些数据添加到 CAS 中。NameReferenceAnnotator 使用一个正则表达式寻找特定格式的人名,IMDB 文档中在提到人名时采用这种格式。(见 图 3。)人名放在单引号中,后面是 “(qv)”;很容易用正则表达式寻找这种格式。人名中惟一的复杂情况是人名本身可能包含一个或多个撇号。这个图还说明了 IMDB 如何消除人名的二义性,比如这里的 John Barrymore,在数据库中可能有多个人都叫这个名字。这对于后面一个步骤是有意义的。
图 3. 来自 IMDB 的文档示例,说明了源数据中人名使用的特殊格式。Son of actor 'John Barrymore (I)' (qv) and actress 'Dolores Costello' (qv).
Annotator 接口中最重要的方法是 initialize 和 process。当框架调用 initialize 时,NameReferenceAnnotator 从描述符以字符串形式读取正则表达式并编译它。然后,当调用 process 时,它在从 CAS 收到的文档文本中寻找与正则表达式匹配的地方。每当找到匹配时,就将它作为图 2 所示的类型系统中的类型实例存储在 CAS 中。每个名字存储为一个 NameReference 对象,这个对象包含正则表达式找到的名字字符串,它的开头和结尾字符位置设置为 NameReference 从 Annotation 内置类型继承来 begin 和 end 整数特性。NameReference 还包含一个 DocumentEntity 引用。这个结构的功能是存储关于文档中提到的每个实体(人)的信息。如果多次提到一个实体,那么每次提到时都引用同一个文档实体。使 Preston 比较简单的一个因素是:在 IMDB 数据中,提到同一个人的所有地方都采用完全相同的形式。所以,很容易识别适当的 DocumentEntity。如果必须对 Preston 进行扩展来处理其他类型的输入数据,那么必须能够处理同一名字的不同形式。例如,如果在 图 3 所示文档的较长版本中提到 “Mr Barrymore”,那么必须意识到这引用了与 “John Barrymore (I)” 一样的实体。进行这种连接所需的处理称为文档内共同引用(in-document co-reference)。在 Preston 中,不需要这种处理,因为 IMDB 数据非常一致。
创建 Extracted Information Database
为了在 NameReferenceAnnotator 从文档集合中发现的信息上进行文本挖掘,所有 CAS 中的提及信息和文档实体信息必须写入一个结构化数据库。这是在文档处理流程结束时进行的(参见 图 1)。在处理结束时接收每个 CAS 的组件称为 CAS 消费者,UIMA 为这个组件提供了 CasConsumer 接口。一个 UIMA 处理管道可以有多个 CAS 消费者,在从 Text Analysis Engine 退出时,这些 CAS 消费者依次接收每个 CAS。Preston 使用