IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management  >

将非结构化内容集成到分布式联邦系统中,第 1 部分: 为 WebSphere Information Integrator Content Edition 构建连接器

连接器开发计划

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Ryan Graciano (graciano@us.ibm.com), 软件工程师, IBM

2006 年 1 月 12 日

本系列文章将向读者介绍一种用于 WebSphere® Information Integrator Content Edition(II CE)的新式连接器的开发,它为任意数量的异构内容存储库和工作流系统提供一种单一的基于 Java™ 的双向接口。通过 II CE,可以将新式内容存储库和工作流系统无缝地添加至已经利用 II CE API 的企业应用程序中。本文所关注的是连接器开发过程的计划阶段。

简介

WebSphere Information Integrator Content Edition(II CE)为任意数量的异构内容存储库和工作流程序提供一种单一统一的基于 Java 的双向接口。通过该接口,应用程序开发人员可以很容易地将所有的信息源数据集成到新的或现有的企业应用程序中。

存储库可由 Content Edition 使用连接器进行访问,这些连接器部署在 J2EE™ 应用服务器(如 WebSphere Application Server)上。如果仍无法获得所需要的连接器,那么除了 Content Edition 所带的许多连接器外,还可以使用一种服务提供接口(Service Provider Interface,SPI)形式的、灵活的连接器 SDK,它可以帮助开发人员自由地将另外的存储库集成到 Content Edition 的联邦系统中。通过 SPI,可以将新的内容存储库和工作流系统无缝地添加到已经利用 Content Edition API 的企业应用程序中。

本系列文章将向读者介绍一种新连接器的开发。本文所关注的是内容存储库连接器的计划,在以后的文章中将带领读者实际编写和部署一个新的连接器。

WebSphere Information Integrator OmniFind Edition (OE) Version 8.2.1 是一种企业搜索系统,我们已经开发了一种用于它的连接器,作为系列文章中的示例。随着 OmniFind 连接器示例的改进,这些文章将越来越多地引用它的特性,以使读者了解各种概念与实际的连接器开发间的关系。

OmniFind 8.2.1 版
在这里提醒大家注意:自 8.2.1 版以来的最新版 OmniFind Edition 已经发行,并且做了改进,例如在最近的 OmniFind 版本中已经将集合加入联邦。连接器示例仍然可以运行在 OmniFind Edition 8.2.2 和 8.3 版上,但是本文所描述的某些限制将不再存在。至于修改或更新连接器示例以更适合最新版的 OmniFind,这是留给读者的习题。我会在下一篇文章中指出如何进行此类更新。




回页首


了解存储库

在开发连接器的过程中,进行全面的计划是最为重要的一步;但是,对于首次进行连接器开发的人员而言,这可能是一项令人望而生畏的工作。Content Edition 提供一种模板文档,称为 Connector Feasibility Study,告诉连接器的程序设计者从哪里入手。可行性研究的设计目的是引导开发人员进行一组存储库研究和连接器设计任务,从而为他们的连接器开发打下坚实的基础,同时避免在连接器开发工作开始后发生设计返工的情况。

连接器开发的第一步是理解存储库的词汇表、特性和布局,因此可行性研究就从这里开始。该研究鼓励您在存储库中使用本机工具进行实验。这是关键的一步,因为通过这一步就会知道最终用户使用存储库的感觉;形成对存储库的充分了解并在头脑中形成关于存储库内部和外部的清晰图像,这也是极其重要的。

在研究存储库的时候,请格外关注该研究第 1.3 节中所提出的问题。这些问题有助于从连接器开发人员的角度来考虑连接器的概念,同时还会揭示一些实现起来更具挑战性的连接器特性,在开始为开发周期进行资源计划时,这会是很有益处的。

让我们来快速复习一下第 1.3 节 Product Concepts 中的几个最重要的问题,以提供关于每一个问题的更多的详细内容,并说明如何运用关于存储库内部的知识来设计连接器。虽然我们在这里只强调几个问题,但是对于连接器设计而言,能够彻底理解所有这些问题的答案是至关重要的。

惟一的存储项 ID

  • 问题:

    哪些存储库项目的标识符是具有惟一性的?

  • 解释:

    在 II CE API 中,存储库中的项目(如内容和文件夹)必须具有惟一的存储项 ID。

文件夹

  • 问题:

    存储库中的内容是如何组织的?

  • 解释:

    II CE 使用基于文件夹的层次结构浏览存储库的内容。这个问题本质上是在问 II CE 应如何表示存储库的这种层次结构。存储库的层次结构可以仅仅是一个视图,将内容存储在多个位置上。在另外一些情况中,存储库的层次结构可以代表一种底层文件系统,将内容限制在一个单一位置上。

    虽然 II CE 的每一个存储库具有一个单根的文件夹层次结构,但是存储库却可能具有多个正交的导航层次结构。如果是这样,那么可能就需要决定如何将多个存储库层次结构表示为 II CE 中的单一层次结构。


    图1. 文件夹层次结构例子
    文件夹层次结构例子

    存储库组织内容的方法可能不只一种,例如,对于一个存储项而言,它可能同时被包含在文件夹和全局类别当中。如果最终用户在查找内容时使用类别比使用文件夹更普遍,而且将这两种概念都包含到文件夹层次结构中是不可行的,那么,您可能希望建立类别对应于 II CE 文件夹的映射,来取代更显而易见的映射。

    最后,许多存储库完全不具有导航结构,只能通过搜索进行访问。

  • 问题:

    对于存储库中的内容,是浏览的做法更常见,还是搜索的做法更典型呢?

  • 解释:

    通常,II CE ItemFinder 用来浏览连接器。如果连接器支持浏览功能,那么就需要适当地执行 ItemFinder。对于标准的、基于文件夹的分层存储库,如文件系统,就相当简单了。当 ItemFinder 请求一个诸如 E:\/mnt/data/content 的文件夹时,文件系统连接器(File System Connector)就会取出所请求目录下的所有子文件夹和文件的指定属性。但另一方面,对于 OmniFind 连接器示例,我们有一个主要基于搜索的存储库。在 OmniFind 的情况下,会提供一种搜索的方式;当 ItemFinder 请求一个名为 developerWorks Articles 的文件夹时,OmniFind 连接器实际上会对企业搜索(Enterprise Search,ES)服务器上所有标记着 developerWorks Articles 类别的项目执行查询。由于文档和其他类别可以继承父类别的标记,从而产生一个完整的层次结构。因而,连接器隐含地在基于搜索的 OmniFind 存储库中实现了浏览功能。如果在您的基于搜索的存储库中存在合乎逻辑的、高性能浏览需求,那么您最好在您的连接器中对其加以实现。

内容

  • 问题:

    存储库存储的是原始内容、内容元数据,还是二者都有?

  • 解释:

    在 II CE 中,通常可以将内容分成两部分:二进制数据或文件(称为原始内容),以及描述内容的结构化数据(称为元数据)。许多存储库具有存储原始内容和元数据的独特方法,例如,OmniFind 并不是真的将项目的原始内容存储在它的索引中。而是对原始内容进行语法分析,索引中包含分析后的版本,但不会存储原始内容。由于在 OmniFind 8.2.1 中无法取出原始内容的数据,因此,OmniFind 连接器不能支持原始内容检索。OmniFind 8.3 提供一种依靠某些数据源检索项目原始内容的方法,这是一种需要在 OmniFind 连接器的未来版本中实现的特性。

    某些存储库(如许多文件系统)会呈现相反的情况;原始内容会被存储,但是除了文件名以外几乎无法得到元数据。

    在其他的存储库中,原始内容和属性之间不存在很明显的区别。例如,内容的属性值可以包含在按照内容进行的全文搜索中。OmniFind 使用户可以将某些属性配置为可全文搜索的,所以,当用户按照一个术语进行全文搜索时,可能会吃惊地发现搜索结果的原始内容中不包含该术语。在预先考虑消费者问题时应注意此类行为。

    有时候,不容易判定什么是原始内容,什么是属性。这通常不是关键性的判定,也没有绝对正确或错误的答案。一种好办法是:考虑一下存储库是用来管理哪种信息的,于是就将那种信息做为原始内容;然后再考虑一下存在哪些关于原始内容的信息,就将其做为属性。

    另一个有帮助的规则是:将结构性数据和非结构性数据进行区分。例如,可以容易地把一个整数或一个 50 个字符的文本字段作为属性,而 BLOB、CLOB 和文件可能更适合做为原始内容。

  • 问题:

    可以将内容分为多个部分吗?或者,可以将其与其他内容进行链接吗?

  • 解释:

    原始内容并非总是以一对一的关系与存储库中的单一项目相关联。在某些存储库中,一个单一的内容项目可以具有多条原始内容(在 II CE 中称为页)。项目还可以具有与其他项目的链接。链接关系可以遵循父-子模式(在 II CE 中称为多部分的内容),或者简单地对其命名(在 II CE 中由属性和扩展的数据类型 INTERNAL_ATTACHMENT 或 EXTERNAL_ATTACHMENT 表示)。所链接的项目也可能有它们自己的原始内容、属性和与其他项目的链接。如果存储库使用多部分的内容,那么连接器应实现 getMultiPartNativeContent 方法。


    图2. 多部分的内容
    多部分的内容
  • 问题:

    存储库是否为内容规定 mimetype?

  • 解释:

    通常,II CE API 中的内容对象与一个 mimetype 相关联。mimetype 使客户机应用程序可以更容易地确定原始内容的查看和编写要求。然而,不是所有的存储库都提供获得原始内容的 mimetype 的简单方法,如果情况是这样,那么应使连接器尽其最大努力自已确定 mimetype 。通常,可以通过检查文件的扩展名来确定 mimetype。在进行项目检索时,OmniFind 存储库会返回内容 mimetype ,这供 OmniFind 连接器使用。在建立内容时,存储库需要 mimetype,尽管如此,这必须由连接器动态地进行确定。在本系列的下一篇文章中会讲到 OmniFind 连接器示例,它提供一个 MimeTypeUtil 类为连接器所创建的内容确定 mimetype。

元数据

  • 问题:

    是否存在不同类型的元数据?数据是如何格式化的?有日期和时间型数据吗?

  • 解释:

    Content Edition 支持多种数据类型的元数据,如 String、Integer 和 Datetime。项目属性总是作为字符串由 II CE API Property 对象提供并从 II CE API Property 对象中检索出来;但是,请注意:属性类型使客户机应用程序将值转换为更适合的格式这项工作变得很琐碎。应该注意:如果是 Date 和 Datetime 类型,那么存储于 Property 对象中的值应该是一个长整数,表示自 1970 年 1 月 1 日 00:00:00 GMT 起所经过的秒数。Time 类型也是一个长整数,表示自午夜起的毫秒数,以设置属性时所在的时区为当地时区。Java 提供一种以这种格式使用 java.util.Date.getTime() 获得日期或时间的简单方法。

  • 问题:

    元数据是否按类进行组织?如果是,那么类会改变吗?

  • 解释:

    存储库可以为某类项目上获得的一组属性定义一个模式,该模式在 II CE 中称为项目类,可以应用于任何存储库项目,这取决于项目在存储库内的分类方式。定义项目类所使用的方法可以有很大区别。某些存储库具有不可改变的项目类,对其的设定是基于项目类型的;而其他的存储库则允许存储库管理员或终端用户对类进行定义,对其的设定是基于项目的。

    跨越存储库的所有项为一个特殊的项目类型(如内容项目或文件夹)定义一组属性是很普通的做法。在这种情况下,可以为连接器定义一个全局项目类,作为对那些一直可以进行访问的属性进行检索的方法。

    OmniFind 是一种没有任何项目类概念的存储库,相反,它依靠用户来定义该为某一个项目设置什么样的属性。然而,OmniFind 搜索结果行之间具有一些共有的属性。因此,OmniFind 连接器仅为存储库项目定义全局项目类,对于不具有项目类的存储库,这是一种一般的解决方案。另一种可选择的方法是使用项目类设计器,它使 II CE 管理员可以为连接器动态地配置项目类,这样就可以使连接器意识到这些项目类,即使存储库并不正式支持它们也无妨。

  • 问题:

    可以将新的元数据属性添加到一个项上吗?

  • 解释:

    II CE API 中的 Content 对象允许用户从内容项中检索一组元数据属性。正如在回答前面的问题时所讨论的那样,这组属性通常与一个项目类相关联。具有更加严格的项目类的存储库会将元数据操作限制到项目类内部的属性范围内。

    某些存储库,尤其是那些没有真正项目类的存储库,没有这种限制。例如,OmniFind 允许用户在开始创建时就为内容对象添加新的属性。II CE 支持这种属性添加。在用户开始更新或创建内容时,通过存储库,连接器不仅可以查找从项目类中所了解到的属性,还可以查找用户添加的任何属性。

    如果存储库不支持这种动态的属性添加,那么它应该忽略额外的属性。





回页首


围绕存储库 API 进行设计

在花费时间了解了存储库如何工作之后,下一步就是要研究它的可用接口。最通常的情况是根据接口所提供的功能和可使用该接口的编程环境来选择接口。如果可以,则首选 Java API,因为 II CE 是一种 J2EE 产品,在 Java 中编写的连接器理所当然会更容易实现。但是,连接器已经编写到了大多数普遍应用的 API 类型中,不仅仅是 Java API。连接器的开发人员总是会有办法,而且到最后选择会归结为要确保 API 公布足够的功能。在少数情况下,可能最终会使用不只一个 API 来获得所需要的所有功能。

在选择任何特殊的方法前,必须先好好地理解 Content Edition 连接器的要求。连接器开发人员在研究可用于本机存储库的接口时,需要记住几个设计点:

J2EE 设计

通常,II CE 在(如来自 IBM 和 BEA 的)J2EE 应用服务器上运行。为了使设计和开发简单化,连接器本身是普通的老式 Java 对象(POJO),但是其可以由 II CE 所提供的系统架构以许多不同的方式容纳。在 II CE 所提供的 EJB 中容纳连接器对象是连接器部署最常见的场景。由此产生的 EJB 可以在与 II CE 相同的应用服务器上运行,可以在另外的服务器机器上运行,也可以为了更好地利用应用服务器的可伸缩性特性而在服务器机器集群上运行。如果必须将连接器与容纳 II CE 的应用服务器相隔离,那么在单独的 J2EE 应用服务器实例中,可以使用远程 EJB 来容纳连接器,不管该服务器实例是本地的还是远程的。

如果无法获得该连接器的应用服务器,或者不希望该连接器使用应用服务器,则可以使用许多其他方法。RMI 代理在一个单独的 Java Virtual Machine(JVM)上容纳连接器,使用 RMI 可以在本地或远程访问该 JVM。SOAP 代理在一个可以通过 SOAP 访问的单独的 J2EE 应用服务器实例中容纳连接器。最后,直接模式将所有的 II CE 组件(包括连接器)导入同一个 JVM 中,而没有 J2EE 应用服务器。

无论连接器的部署方式是什么或位于哪里,它总是会作为 EJB 打包,如果您不是 J2EE 专家也请不要担心,因为不必编写连接器程序。II CE 连接器 SDK 将会替您考虑 EJB 的问题,从而使您把精力集中在 POJO 实现映射代码的问题上,映射代码是存储库所特有的。然而,必须了解一些规则和设计考虑,以免破坏 EJB 的技术要求。我在这里列出了在开发连接器的过程中很可能会遇到的一些要求和限制,但是在开始编写任何代码前,请再复习全部的内容。有关需要考虑的 EJB 问题的完整描述,请参考 EJB Specification

  • 连接器必须是可串行化的

    应用服务器使用一种称为挂起的过程,在这个过程中,EJB 可以得到释放,并在需要使用之前一直被存储在磁盘上。在应用服务器之间,挂起的原因和频率是不同的。但是,挂起通常只有当服务器的负载极大,或者 EJB 长时间空闲时才会发生。

    应用服务器可以选择在任何时间挂起您的连接器,因此连接器对象应具有摆脱这种 Java 串行化和解串行化过程的能力而不受到损害。请在考虑如何使用存储库 API 时记住上述这一点。是否需要连接器不断引用存储库中的对象呢?如果是,则需要这些对象是可串行化的,否则,就应该在串行化过程中将其删除,在解串行化过程中重新建立。

    在开发本文中的连接器示例的过程中,我曾经遇到过一个问题,可以作为很好的例子来说明这个问题。在早期的连接器设计中,我引用了 OmniFind BrowseService 对象并将其作为实例变量存储。当运行请求应用服务器挂起 EJB 的测试程序时,发现了下列异常:


    java.io.NotSerializableException
    						
    CNTR0005W: An enterprise bean could not be passivated:
    StatefulBeanO(BeanId(VeniceBridge#vbr_omnifind.jar#
    OmniFindConnector,1056f901e68),state=PASSIVATING) 
    com.ibm.ejs.container.activator.StatefulActivateOnceActivationStrategy@25042504
    java.rmi.RemoteException: passivation failed; nested exception is:
    java.io.NotSerializableException: com.ibm.es.api.browse.RemoteBrowseService
    

    为了解决这个问题,我重构了连接器,使其不再依赖存储在实例变量中的 BrowseService 对象。另一种可供选择的解决方案是:在串行化和解串行化过程中,分别实现 writeObject(java.io.objectOutputStream)readObject(java.io.ObjectInputStream) 方法来处理和恢复 BrowseService 对象。J2SE API 指出,这些方法可以由实现 Serializable 接口的任何对象所使用。

    幸运的是,在我还没有太深入到编写代码的工作中时便尝试着测试挂起功能,所以我所选择的解决方案就不很困难;但是,如果在开发周期的后期出现这种情况,那么改正这样的问题将会是项费时的工作。

    可以在开发过程的早期执行一些简单的挂起测试,以避免出现串行化问题。应用服务器上包括控制 bean 挂起方式的设置值,甚至还可能提供强制 bean 挂起的方法。一种测试挂起的方法是:将存储的 bean 的数量设置为一个极小的数,从而,每当 bean 进入不活动状态时,应用服务器就会对其进行挂起。在使应用服务器频繁地对 bean 进行挂起以后(最好在完成连接器上的所有操作后),快速运行通常会对连接器运行的所有测试。请侧重于这样的测试:那些涉及到作为实例变量存储的对象的测试,因为它们最有可能出现问题。

    为了验证连接器正在挂起,而且应用服务器的设置值也在为测试正常工作,可以改变 II CE 日志的设置值,以打印 EJB 级的调试消息。在 II CE 管理工具中,先单击 Configuration Data,再单击 Custom Logging 选项后面的椭圆,以打开 Custom Logging Editor>,并添加下一行中的内容:


    调试记录
    						
    	log4j.category.com.venetica.vbr.ejb=DEBUG,A1,A2

    当发生 EJB 的生命周期事件(比如挂起)时,连接器就会将一条消息输出到标准输出上。通常,该消息在应用服务器日志中出现,这主要由应用服务器的配置方式所决定。

    串行化安全

    串行化会带来一些与安全有关的问题。如果将连接器程序写到了磁盘上,那么可能就会暴露一些敏感性的数据。例如,连接器的 public void logon(AuthBundle) 方法代码显示:


    不安全的登录方法
    						
    	protected AuthBundle _credentials = null;
    	
    	public void logon( AuthBundle encrypted ) {
    	    _credentials = unsealAuthBundle( encrypted );
    	}

    这里有什么错误呢?连接器中的 logon(AuthBundle) 方法将会接收包含存储库凭证的加密身份验证信息,从本质上说,这是敏感性的信息。然后,logon(AuthBundle) 方法会对该信息进行解密,产生明文的文件凭证。显而易见,这个验证过程会经常发生。如果解密后的信息只存在于执行该方法的过程中,那就会非常好,连接器在活动时不会被挂起,在执行 logon(AuthBundle) 过程中的连接器当然是活动的;但是,将解密后的 AuthBundle 存储到实例变量(_credentials)中,则是个错误的做法,在连接器被挂起以及应用服务器将其写入磁盘的过程中,未经身份验证的人就可能进入临时文件中检索凭证。

    绝不要将敏感性信息存储到串行化的对象中,在使用存储库的 API 时也请牢记这一点。

  • 连接器不应加载本机库

    如果连接器需要使用 JNI 来访问存储库 API 的本机库,那么很难从 EJB 内部运行它。EJB 的技术规定禁止使用 JNI,因为它损害了应用服务器的稳定性、安全性和可伸缩性。如果连接器必须使用 JNI,那么只能从外部 VM 中的 RMI 代理上运行连接器。建议在应用服务器上使用 JNI 时不要放宽 EJB 限制,因为这可能会损害它的稳健性。如果应用服务器支持 JNI,那么 JNI 访问中的一个错误都会使整个应用服务器停止运行!

  • 连接器不应对文件系统或文件描述符进行直接访问

    连接器不应请求任何其部署不需使用的资源,或在连接器的配置中无法获得的资源。Content Edition 提供 BridgeConfig,使您可以检索连接器的配置数据(由 II CE Administration Tool 提供),从而不需要直接从文件系统中读取配置数据。然而,某些连接器需要进行本机文件系统访问,以从存储库中检索原始内容;或者,检索可由存储库动态生成的外部配置数据。在审查存储库 API 文档时,请关注这些要求,并考虑如何解决这些问题。即使用配置数据来部署连接器的方法可行,也可以从应用服务器请求文件,而不是直接打开文件。

如果连接器不能在这些限制或任何其他的 EJB 限制下工作,那么有两种方法可供选择:对应用服务器进行配置以放宽这些限制,或者在 RMI 连接器代理中运行连接器。RMI 连接器代理没有任何 EJB 技术要求中所规定的限制。从一开始就不必理会 EJB 的技术要求,而是依靠 RMI 连接器代理来使连接器在部署时工作,这一点是非常吸引人的;但是,我还是要反对这种做法。尤其在当生产环境可以从应用服务器所提供的管理、安全和可伸缩性中获得益处时,我们最希望获得这样一种连接器:它支持灵活的系统架构并可以在应用服务器上随意部署。即使并不期望马上就从应用服务器上运行连接器,也最好保留这种可能性。

并发

连接器不需要是线程安全的,因为 CE SPI 保证连接器对象实例一次只需要考虑一个用户的情况(执行的线程) 。但是,也会存在多个连接器对象实例,它们都在同一时间访问同一台 Java Virtual Machine(JVM)上的存储库 API。 这可能会导致在类级别(使用静态数据的情况)的代码中或存储库 API 中出现潜在的并发问题。诸如此类的问题会给设计工作带来很大的影响,因此应尽早发现。在评估 API 时,请确认 API 为线程安全的,需要时,请与生产存储库的厂家联系确认此事。非线程安全的 API 会增加许多额外的访问协调工作,还会看到显著的性能冲击,因为在每一个 JVM 上一次只能有一个线程访问存储库。

请想像这样一种场景:有 60 个客户机要访问存储库,因此就会存在 60 个不同的 EJB 会话;本质上可能就会有 60 个不同的线程。如果其中的 30 个客户机同时试图对存储库执行任何操作,那么 29 个客户机就要等待那 1 个客户机完成。在设计连接器时,请尽力避免这种资源争用的情况。


图3. 资源争用场景
资源争用场景

会话管理程序

通常,与其他因素相比,会话管理程序更容易影响连接器的设计。让我们来看看 II CE 上的客户机期望连接器如何工作,这样就可以全面了解存储库会话管理程序应该如何工作了。客户机应用程序开始运行时先启动与 II CE 服务器的连接,并且请求一个 Repository 对象。该 Repository 对象代表客户机与连接器之间的一个连续会话。


客户机应用程序示例
				
// Get connection to Content Edition Access Services
User user = user.initialize(); 
// Request a repository session from Access Services. On the application server
// side, a new stateful session bean is created for the client. The stateful bean
// is a SPIServerBean, which forwards client requests to the connector object
// created for your bean. In our case, this is a newly created OmniFindBridge
// object; this is the connector that we have written
Repository repo = user.getRepositoryByID( MyOmniFindServer ); 
// Logon to the repository. The SPIServerBean will forward this request to 
// OmniFindBridge 
repo.logon( myusername, mypassword, null );

在 bean 的桥接类内部,logon(AuthBundle) 方法被调用。例如,在 OmniFindBridge.java 中,运行下列代码:


OmniFindBridge 登录方法
				
public void logon(AuthBundle bundle) throws LogonException {
   logDebug( "In logon" );
   OmniFindSearch.loginTest( _config, _bundle ); // Throws exception for bad credentials
   _bundle = bundle; // Notice that we save the encrypted version of the bundle 
}

于是,客户机与连接器之间便达成了信任;从客户机的角度来看,会话被建立起来。接下来对 Repository 对象的每一个操作都假设客户机已经登录。对用户而言,登录连接器和登录存储库是一样的,尽管在 logon(AuthBundle) 中不曾真正触及到存储库。

logon(AuthBundle) 是无线程的,因为 OmniFind 是无状态存储库,不支持连续会话。在 OE 中,向 Enterprise Search 服务器发出的任何请求都伴随着凭证。logon(AuthBundle) 方法则只是验证凭证在当时是有效的。

这引出了一个重要问题:连接器必须为客户机、甚至为不支持会话的存储库保持会话的幻影。对于 OmniFind,连接器会记住加密的登录凭证,并在每一次操作前登录。

对于支持连续会话的存储库,连接器会登录进入存储库中并保存会话。请注意:这要求更注意串行化问题,因为完成挂起后存储库会话会被恢复。

功能和语言

请考虑在评估存储库本机工具时所获悉的内容,以及通常如何使用这些工具。API 是否提供所需要的一切内容?是否可能需要多个接口来完成所希望的所有目标?某些存储库具有适合不同任务的不同子系统,每一个子系统具有自己的 API。

请优先选用 Java API,因为 II CE 是基于 Java 的。Java API 往往也为串行化和并发问题做了更好的准备。非 Java 的 API 可能会存在问题,因为它们往往需要本机库才能正常运行,这会有损于实现适应于 EJB 的目标。在诸如 COM 或 .NET® API 这样的本机 API 的情况下,通常可以利用纯 Java 解决方案在 Java 和本机 API 之间进行桥接。这些第三方产品使您可以完全在 Java 下编写连接器程序,这将大大简化依据本机 API 开发连接器的工作。

Web 服务:对于 JNI 的备选方案

考虑用 Web 服务 API(尤其是 SOAP,但 XML 有时优于 HTTP)来代替本机 API 也是一种明智的选择。在考虑该选择时,请务必仔细确保所有需要的功能都作为 Web 服务被公布,并且选择的 API 可以满足性能要求。在某些本机 API(如 C 和 C++ API)的情况下,JNI 可能是惟一的选择。然而,创建包装本机 API 的 Web 服务 API 可能是可行的方法。这样,就可以从 Java 连接器上调用 Web 服务 API 了。通过开发 Web 服务所使用的语言,可以将 JNI 彻底去掉;至少,可以进行 VM 外部的 JNI 调用。

OmniFind API

在 OmniFind 连接器中,可以使用两种 API —— IBM Search and Index API(SIAPI)和 Data Listener API。SIAPI 为 Enterprise Search 提供搜索接口,以及许多查看元数据(比如类别信息)的功能。SIAPI 为只读的,不含有任何添加、删除或修改搜索索引的方法。在这里开始使用 Data Listener API。因为我希望获得一种既可编写又可读取数据的连接器,所以在设计时不得不同时想着这两种 API。幸运的是,这两种 OE API 都是基于 Java 的,而且都是线程安全的。在未来的 OmniFind 版本中,除了用于开发本系列文章中的例子的 8.2.1 版以外,Data Listener API 的功能均被合并进 SIAPI 中。潜在的连接器功能改进会使其简化,从而只使用一种 API。





回页首


将存储库映射到 II CE API:案例研究

将存储库映射到 II CE API 是连接器计划中最为重要的一步。所选择的映射会影响到连接器设计的方方面面。在计划工作进行到这个阶段以前,您应该已经非常全面地了解了存储库需要提供什么概念、功能和接口,因此也许早就开始考虑如何映射某些存储库概念了。根据存储库,这些可能是非常显而易见的。对于某些存储库而言,文件夹会非常直接地映射至 II CE Folder,一组定义的属性映射至 ItemClass 等等;然而,对于其他存储库而言,可能会有对于 Folder 的许多种解释。事实上,对于某些存储库而言,会难以确定完全映射在 Repository 对象本身上的是什么!

OmniFind 案例研究

让我们来看一个真实的映射例子,这是作为本系列文章的示例的 OmniFind 连接器。作为一种企业搜索系统而不是内容管理系统,OmniFind 要求更具创造性地将其概念映射至 II CE 。使用一种不寻常的存储库确实可以为映射过程带来一点儿乐趣;我认为内容集成是乐趣,但是您可能不这么想。

我相信,从最基础的地方开始计划是最容易的方法。首先,大致了解内容是什么,而内容检索和管理则是所有工作中的最后一项。然后,就可以确定应该如何通过其他的 II CE 特性(如文件夹和项目类)使该内容及其元数据成为可访问的。当我观察 Search 和 Index 的 API 时明显地发现,OmniFind 搜索结果中的一行应该是连接器中的一个内容项目。对于结果的每一行,有一定数量的总是能够访问的属性,这些属性就变成了全局项目类。OmniFind 中其余的元数据以字段形式出现,不遵循任何特定模式,因此不容易将其分为项目类。所以,OmniFind 连接器只为内容支持一种单一的全局项目类,这样每个项目可能会有无限多的专门的其他属性。内容和属性的映射非常容易,但是浏览暗喻会怎样呢?如果有,那么什么样的 OmniFind 概念可以作为 II CE 文件夹呢?

对文件夹进行映射

OmniFind 将它的结果组织为类别,每个类别是一个基于规则的搜索结果集,具有给定的 ID 和描述性名称。类别也是可浏览的,每个类别只具有一个父类别。我判断肯定能够从类别构建出好的文件夹,因此下一步就必须大致了解类别本身是如何被访问的。在类别之上是否还有另外一级抽象(用户愿意通过它使用 II CE 进行浏览)?实际上,连接器可以将不只一种概念映射到文件夹;例如,如果 OmniFind 的类别之上具有分类法 的概念,那么连接器可能会将分类法和文件夹都表示成类别。如果决定将分类法和类别都用作文件夹,那么连接器很可能将一个项目类映射到这两者,以便区分它们。

事实证明:OmniFind 确实有不同的类别系统。在由 8.2.1 SIAPI 所公布的最一般级别上是集合,它包含分类法。这样,分类法就拥有了一个根类别,它可以是其他许多类别的父类别。因此,下面就是连接器开发人员自顶向下看到的 OmniFind 8.2.1 分类结构:


OmniFind 分类
				
* Enterprise Search Server (Possible CE concept: Repository?)
    * Collection1 ... CollectionN (Root folder? Repository?)
        * Taxonomy1 ... TaxonomyN (2nd-level folder? Root folder? Repository?)
            * Category1 ... CategoryN (Folder)
                * Result1 ... ResultN (Content)

现在,我不得不对在设计中要包含哪种类别系统才是合理的做出判断。可能会选择尽可能大的范围,以便为 ES Server 构建 Repository,也可以将连接器的定位降低到分类法级别,从而使所有的文件夹都是类别。

一个小的研究显示:Enterprise Search(ES)8.2.1 自然地分隔了集合。在 ES Administration 应用程序中,集合是分别被管理的,同时在 ES Search Application 中也是分别被搜索的。最重要的是,也必须分别登录到集合,而且也不能保证一组凭证对每个集合都有效。

OmniFind 安全和 II CE 会话管理程序

现在,请考虑:当必须分别登录连接器根文件夹中的每一个文件夹时,在连接器上所进行的查询会有什么固有的困难。如果还记得我们先前就会话管理程序所讨论的内容,那么就会回想起我们的连接器应维护与存储库进行连续会话的幻影,即使这种会话实际上并不存在,亦应如此。在 II CE 端的用户希望只登录一次连接器,因此连接器就必须进行额外的工作来维护跨每一个集合的多个会话。

这是一种工作量巨大而回报很少的工作。事实上,如果考虑到在 OmniFind 8.2.1 中集合也是要分别搜索的,那么可能还有更多需要做的工作。这意味着,ItemFinder 执行和搜索代码必须做更多的事情,因为它们可能要针对任何项目组合运行,而这些项目来自要分别进行访问的集合!代码的复杂性将会大大提高,很明显,这会损害最终的产品。

在开发自己的连接器时很可能会遇到这样的情况。请始终仔细考虑每一种不同选择所带来的性价比。在 OmniFind 8.2.1 的情况中,若连接器使用多集合方式,则成本相当高;但是,在确定它是否会带来任何利益前,必须考虑确实可以使用 II CE 来联合这些集合。如果用户希望使用 II CE 进行跨集合搜索,那么只需在 II CE Administration Tool 中配置多个 OmniFind 连接器,并且使用 II CE 将搜索联合起来。这也更适合 OmniFind 身份验证模型,因为可以利用 II CE Single Sign-On 系统来登录到各个集合上。

选择一种存储库:分类法

最后,我决定将分类法映射到 II CE 存储库概念。我发现,OmniFind 限制每一个集合只能有一个用户定义的分类法,因此从概念的角度来说,让分类法处于存储库级类似于对于存储库使用集合。作为附加的优点,这会使我的 II CE Folders 映射至 OmniFind 中的惟一概念上,因为它们都是类别。当不必处理可能存在的多个文件夹类型时,在连接器中编写文件夹检索方法会更加容易,可以使用不同的本机存储库 API 方法对每一种文件夹类型进行访问。

对 II CE 查询语言进行映射

既然已经考虑了诸如内容、文件夹、项目类这样一些基础概念的映射,那么就开始看看如何将 II CE 查询语言映射到 OmniFind Search 和 Index API。对查询进行映射是项棘手的工作,因为存储库通常以非常不同的方式处理类似的概念。目标存储库可能支持,也可能不支持全文(原始内容)搜索或参数(基于属性的)搜索。如果对两者都支持,那么可以在同一次查询中使用它们吗?它可能支持 AND 或 OR,但是如果支持,是否存在任何特殊情况呢?这些操作符会被嵌套在括号中并与其他的查询语言操作符混合在一起吗?请您对这种情况保持敏感:结果可能完全不是 II CE 用户所期望的情况。

我遇到了 II CE 的 <> 操作符这样一个大绊脚石。在 II CE 查询语言中,这是不等于 操作符,例如,如果希望对所有不包含 content integration 的文档进行查询,那么可以搜索:


II CE 的 “异” 运算查询
				
phrase<>'content integration'

在 OmniFind 中,与该概念关系最密切的映射是 - 符号,其在大多数情况下是可用于搜索的 “异” 运算操作符,但是不会生成它自己的结果。我曾尝试搜索术语 -content integration,没有得到结果;相反,搜索 -content integration +rulebased::c1 时就返回了大约 9,000 个结果。搜索术语 rulebased::c1 指定已经定义的一个类别;因此,当用户跨整个 存储库搜索所有与某种标准 匹配的文档时,不完善的映射会成为问题。

虽然 II CE 用户期望进行只有一个 “异” 运算的搜索,但是 OmniFind 不允许这样做。只使用排除一个术语的 “异” 运算来搜索全部文档是不可行的。这是一个很好的例子:对于不完全与 II CE 查询语言相一致的行为,应该在文档中加以说明。

新的连接器开发人员的通病是:关注以最精密的技术方式将存储库项目映射到 II CE API 概念,从而将不自然的映射强加给存储库。然而,这不总是理想的场景。最终产品不仅应该在技术上是强大的,而且对于熟悉存储库的终端用户还应具有直观性。如果从概念上说,连接器中的映射与用户和已有系统之间的交互一致,那么用户就更容易过渡到使用 II CE 编写的应用程序。





回页首


结束语

在准备编写连接器时,请考虑集成目标,希望解决什么问题?用户期望如何与存储库进行交互?连接器会在什么样的环境下运行?性能、可伸缩性和安全要求是什么?充分的计划会产生有效的、可维护的连接器,并且可以使用户更容易进行非结构性内容管理。

请在将来继续阅读本系列文章的下一篇,它将带领读者告别计划阶段,进入开发阶段,将呈现并解释在本文中经常提及的 OmniFind 连接器的源代码,并展示如何应用 II CE SDK 构建并部署连接器。






回页首


下载

描述名字大小下载方法
Connector feasibility studyconnector_feasibility_study.doc464 KB  FTP|HTTP
关于下载方法的信息Get Adobe® Reader®


参考资料

学习

获得产品和技术
  • 使用 IBM 试用软件 改进您的下一个开发项目,可以通过从 developerWorks 直接下载这些软件。


讨论


关于作者

Ryan Graciano 是 II Content Edition 工程团队的成员,在北卡罗莱纳州的 Charlotte 工作。他目前主要关注为 WebSphere Information Integrator Content Edition 提供测试自动化。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM、DB2、DB2 Universal Database 以及 WebSphere 是 IBM 公司在美国和其他国家所使用的商标。 Java 和所有基于 Java 的商标是 Sun Microsystems, Inc. 在美国和其他国家所使用的商标。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。

IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款