博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
增强 WebSphere Service Registry and Repository 的搜索功能
阅读量:2494 次
发布时间:2019-05-11

本文共 11868 字,大约阅读时间需要 39 分钟。

了解如何使用 Apache Lucene 和 Spring 框架创建关键字插件,以将全文搜索添加到 WebSphere® Service Registry and Repository 中。

IBM WebSphere Registry and Repository(以下称为 Service Registry)让您能够以受管控的方式存储、组织和搜索与服务、服务之间的关系以及服务生命周期相关的技术文档。Service Registry 是基于分层数据库的技术,可以在更传统的关系数据库管理系统 (RDBMS) 上构建 XML 数据库引擎,以便能够方便地管理接近原始 XML 形式的 XML 文件。Service Registry 允许您描述 XML 文档中各部分之间的逻辑关系(例如,WSDL 文件中的接口和数据结构描述)和维护各部分之间的内部关系。它还允许您在不同的文档及其逻辑部分之间建立关系。

在 Service Registry 中,文档、逻辑对象和关系生命周期都可以从通过状态机实现的定义良好、可自定义或可替换的流程进行管理。除了以上所述的逻辑实体之间的结构化静态关系之外,Service Registry 还可以使用本体(特别是分类法)来创建这些实体之间的动态关系。这些分类法可归纳对象之间的语义关系。

Service Registry 的另一个相关功能是从其内部 XML 表示形式中派生出来的,该功能能够搜索使用类似 Xpath 的语言的文档和逻辑实体,从而能够使用结构和语义关系模型来导航对象网络。但是,Service Registry 当前缺少全文搜索功能,这意味着使用关键字或其他更先进的条件进行搜索当前还不可能。

在本文中,您将了解如何使用 Service Registry 的可扩展性框架和以下两个开源项目将全文搜索功能引入到其中:Apache Lucene 和 Spring 框架。我们将通过一些场景来说明,对于每个解决方案而言,实现的方便性与集成的普遍性之间的权衡。这两个解决方案的插件代码可在部分中找到。

为了全面了解技术实现,您应适当掌握一些 Java™ 知识,但是在参与一般性讨论时对此并没有严格要求。

Service Registry 具有一个可扩展性框架,该框架允许您开发一些插件来增强产品本身的内部行为的多个方面。插件方法在文档操作(创建、更新和删除,以下称为 CRUD 操作)的特定阶段中调用,并且可隐式用于允许或拒绝对象更改。

Service Registry 允许以下三种类型的插件:

  • Validator,在 CRUD 操作执行之前调用,因此在对象未到达存储区域之前,对象还不是一成不变的,您可以对其进行更改。
  • Modifier,在 CRUD 操作之后调用,可用于更改与对象相关的信息,但是不能轻易地更改对象本身。
  • Notifier,在 CRUD 操作完成之后调用,可用于实现通知机制,但是无法修改对象本身。
图 1. 逻辑插件结构

我们将利用验证器插件的功能来更改对象表示形式,以便引入新对象的属性,新对象属性将使用从正在处理的文本形式的文档中派生出来的关键字(或统计上相关的令牌)来填充。

通过使用 XPath 功能搜索属性内部的子字符串,我们将能够使用基于关键字的搜索方法对文档进行全文搜索。使用本体对通用(二进制)文档进行 XPath 查询的示例如下:

/WSRR/GenericDocument[classifiedByAnyOf(.,'')]

而使用全文搜索功能时,您可以使用如下查询:

/WSRR/GenericDocument[classifiedByAnyOf(.,'') and matches(@keywords,'.*.*') ] 正如您所看到的,第二个查询同时使用了本体 (classifiedByAnyOf) 和基于全文的谓词,实现了两种不同的搜索策略(本体和全文)之间的集成。这一集成的基础是谓词匹配,它允许正则表达式在一个属性(或所有属性)之上匹配。

验证器插件的角色是从提交的文档中提取关键字,将这些关键字放入属性关键字中,然后让运算符匹配并让 XPath 执行其余的操作。

此挑战的另一部分是找到一种智能且可重用的方法来对文档进行分析,从文档中提取统计上相关的令牌,然后使这些令牌可用于 Service Registry。我们将使用 Apache Lucene 来实现这一点。具体来说,我们将使用名为 token extraction 的主索引函数的附带行为。

当 Lucene 为文档建立索引时,它将执行分析(或标记化),此操作可能是非常复杂且依赖于语言的,但是会创建令牌及其在文档中出现的频率的映射。我们将截取 Lucene 索引的这一阶段,使用能产生相同结果的两种不同实现战略来提取令牌。

要牢记的一点是,我们的解决方案要求我们能够为多种不同的业务文档建立索引,其中包括 PDF 文档、Word 文档和 Excel 文档等。Lucene 只能为纯文本文档建立索引,因此我们需要找到一种方法将纯文本从上面提到的那些富文档格式的文档中提取出来,然后将其提供给 Lucene。(当然,XML 文件本身就是纯文本,不需要进行任何形式的转换。)为执行这一提取操作,我们将利用另外两个开源项目,如下所示:

  1. Apache POI,用于处理 Microsoft™ 文档,如 Word 和 Excel 生成的文档
  2. PDFBox,用于处理 PDF 文档

图 2 显示了一般索引流程:

图 2. 索引流程

同一逻辑方案同时应用于基于 RAM 和基于 Spring 的实现。在第二种情况下,文档转换器和索引引擎组件及其子组件通过描述符在外部进行定义,然后使用 Spring 进行实例化。

Lucene 内存方法将基于 RAM 的存储与非常快的文档分析器组合在一起,方便了针对高度优化的实现进行自定义。基本上,基于 RAM 的存储意味着索引的文件表示形式保存在 RAM 中,因此无法在不同的应用程序之间进行共享。这些索引仍然是专有的,因此不需要详细描述访问控制策略。高度优化的实现降低了 Lucene 的自定义灵活性,但是提供了一个速度非常快的索引引擎。

如果您不需要在不同的应用程序之间共享索引,就不必关心能否外部声明索引引擎的结构,只要看能否为 Service Registry 提供全文搜索即可,这是为您提供的一种策略。

如果需要在不同的应用程序之间共享索引,请继续阅读下面的内容。

之前的解决方案的缺点之一是,从编写代码的角度来看,找不到既能提供灵活性又不会影响性能、不会增加代码复杂性的简单方法。基本上,转换流是硬编码的,无法方便地进行更改,除非提供某种灵活性框架。

Spring 框架有一个非常有趣的特性,那就是其反向控制 原则(也称为 Hollywood 原则,就好像在说,“请别给我打电话,我会与您联系”)的实现方式,此原则指出,无需通过显式引用将组件连接到代码中,只需通过声明组件在接口和类型中的依赖性建立组件结构,然后让某一其他组件解决这些依赖性并将请求的组件注入请求者中即可。

从编写代码的角度来看,如果您有如下显式依赖项:

class A {	public void theMethod() {		B dependency = new B();		dependency.someOtherMethod();	}}

那么可以将其转换为如下形式:

class A {	public void theMethod(B dependency) {		dependency.someOtherMethod();	}}
通过这种方式,您就可以通过此方法接口将第一个代码片段的隐式依赖项变为显式,将创建和注入实际 B 对象的职责移交给另一个组件,这一点可以由配置文件驱动,而不是由代码本身驱动。使用这一简单更改配置文件的方法(在 Spring 情形中,更改 XML 描述符),您可以更改组件的实现方式以使用不同的索引策略。

在此我们将不再继续深入讲述有关 Spring 框架及其编程模型的详细信息,现在我们将回顾一下基本逻辑工作流:

  1. 创建一个 XML 文件,描述您要使用的 bean 或组件,以及使用它们的方式。
  2. 在您的代码中,创建 ApplicationContextBeanFactory 类的一个实例,然后将引用传递给 XML 描述符。
  3. Bean 入门。

本图中的另一个重要部分是,Spring 框架提供了特定于 Lucene 集成的集成模块和编程模型,此模块和模型提供了一组可与 Spring 框架的声明方法结合使用的 bean,极大地促进了 Lucene 应用程序的开发。

在我们的示例中,我们将使用 Spring 来声明索引引擎、存储类型(基于 RAM 或基于文件)、文档转换器(以及文档转换器识别文档类型的方式,以便能够将文档分派给适当的处理程序)和模板 bean(在 Spring 用语中,它能消除 Lucene API 对 Spring 用户的复杂性)。

在本部分中,您将逐步了解如何对集成插件进行编码,以及了解涉及到的不同框架的技术方面的知识。

因为我们将提供同一索引功能的两种实现,所以我们把这些实现隐藏在工厂 (DocumentAnalyzerFactory) 后面,该工厂公开了单个、通用的接口 (DocumentAnalyzer),如下所示:

package com.ibm.luceneintegration;public interface DocumentAnalyzer {	public static final int DEFAULT_MAX_TERMS = 50;		String[] getMostFrequentTermsAsArray(String name,byte[] content) throws Exception ;	String[] getMostFrequentTermsAsArray(String name,byte[] content, int maxTerms) throws Exception ;	String getMostFrequentTerms(String name,byte[] content) throws Exception ;	String getMostFrequentTerms(String name,byte[] content, int maxTerms) throws Exception ;}

此接口提供了同一方法的四种变体,能够以逻辑方式将二进制内容转换为最常用的令牌的列表,最终限制了此列表的长度。

name 参数基于扩展名猜测文档类型。可以使用不同的技术来猜测类型,但是,为了简单起见,我们将坚持使用基于名称的猜测。

Service Registry 验证插件将使用 DocumentAnalyzerFactory 来选择文档分析器,使用所选的分析器对每个文档进行解析,检索令牌列表,然后将此列表注入与文档相关的 XML 描述元数据的属性中,来支持 XPath 混合查询。您将了解实现上述操作的两种可能的方法,但是您可以方便地编码其他可适应插件基础设施的实现。

图 3 显示了插件代码的简化版本:

图 3. 插件代码

此插件显示了 CRUD 方法之一(方法 (3))的实现,仅为了说明代码。

如果传递的对象为 Document 类型,则意味着该对象是二进制对象,而不是基于 XML 的技术文档,可以传递给负责对其进行处理的 injectProperty 方法。此方法 (2) 检索内容和文档的名称,然后使用文档分析器实现(通过工厂)计算最常用的令牌的集合,最后调用 setPropertyValue 方法 (1) 将 keywords 属性的值设置为关键字集的字符串表示形式。

此实现基于 Lucene 核心和专用包,即 Lucene Memory,此包可提供内存中索引功能。正如您在 中看到的,索引工作流包括:

  • 文档标记化,它是将二进制文档转换为包含文档的大部分内容的纯文本的阶段
  • 索引引擎,它负责在统计层面上分析纯文本(由二进制文档派生而来),然后计算令牌的列表,按使用频率排序

在我们的实现中,第一步是通过 Converter 类实现的(为了简洁起见,此处并未显示第一步,但是可以在包括的中找到)。Converter 类提取文档名称(可能是从文件名派生的)的扩展名,然后使用此扩展名将文档分派给适当的文本提取程序:

  • Apache POI 用于 Microsoft Excel 和 Word 文档
  • PDFBox 用于 PDF 文档
  • Java Swing 用于 RTF 文档

AnalyzerUtil 类(源自 Lucene Memory 包)用于从纯文本中提取最常见的术语。此类负责直接在 RAM 中创建动态、可变的索引。虽然此类的使用可以实现非常快的索引处理,但是它所创建的索引不可供进一步的操作访问。

Spring 实现基于多个组件的使用,每个组件都提供了特定的功能:

  • Spring 框架,利用“反向控制”模式和声明方法
  • Spring 模块,用于 Spring 和 Lucene 集成
  • Lucene Core,用作索引引擎
  • PDFBox,用于 PDF 文档处理
  • Apache POI,用于 Microsoft Word 和 Excel 文档处理

Spring 框架是使用 XML 描述符文档配置的,如图 4 中的简化示例所示:

此配置文件可以逻辑划分为以下四个主要部分:

  1. 存储 Bean,用于为索引定义存储区域。在本例中,有以下两个存储 Bean:基于 RAM(仅限会话期间)和基于文件系统(持久性的)。
  2. 索引引擎,用于定义文本分析(分析程序)所用的策略和用于记录索引的索引存储。
  3. 文档转换,指定据以猜测文档类型的策略(在本例中,此策略是基于扩展名猜测文档类型,但是您可以更改此方法),和将扩展名与最终负责将特定的文档类型转换为纯文本的文档处理程序联系在一起的映射
  4. 模板,是对象 Facade,可以将 Lucene API 包装为一个更简单的编程模型,并且可以链接到搜索引擎。

使用依赖项注入机制可以将这些 Bean 绑定在一起:

  1. 搜索引擎(IndexFactory Bean)有一个 Directory 类型的属性,该属性可能会因两个类型均为 Directory 的存储 Bean 中的一个而满负荷。
  2. 模板组件有一个 IndexFactory 类型的属性,该属性是索引引擎的派生物,可能会因索引引擎而满负荷。

当您将引用作为 Bean 的属性的值时,实际上就是在调用依赖项注入,并且无需编写某一类粘合代码来将组件绑定在一起。

您可能会看到,虽然文档处理程序管理器 Bean 应链接到模板,但是它并未直接链接到任何 Bean。这是由于 Spring 模块组件代码存在缺陷。

Spring 对象(ApplicationContext 或 BeanFactory)可以使用此配置文件来创建 Bean,注入依赖项,以及执行许多其他此处未显示的操作。

正如您所看到的,基于 Spring 的实现的代码主要使用 ApplicationContext 来初始化 Spring 组件和检索要使用的 Bean:

ctx = new ClassPathXmlApplicationContext("conf.xml");		mgr = (DocumentHandlerManager)ctx.getBean("documentHandlerManager");template = (LuceneIndexTemplate)ctx.getBean("template");

对于处理的每个文档,文档处理程序管理器 Bean 用于自动猜测文档类型并将其路由到适当的文档处理程序,以用于纯文本提取,如下所示:

Document doc = mgr.getDocumentHandler(name).getDocument(new HashMap(), new ByteArrayInputStream(content));Field contents = doc.getField("contents");Field myContents = new Field("contents",contents.stringValue(),Store.YES,Index.TOKENIZED,TermVector.YES);doc.removeField("contents");doc.add(myContents);

第一行非常奇妙,它使用外部化文档处理程序管理器配置。Spring 的强大之处在于,能够在不了解插件代码可以处理哪些文档类型的情况下完成插件代码,能够以声明方式方便地更改这一设置,并对现有插件代码没有任何影响。

其余行用于处理文档处理程序管理器的缺省行为,缺省行为创建的 Document 对象不能被索引,只能被解析,这意味着不可能检索最常用的术语列表。因此,此代码将检索内容字段,然后创建一个可供索引的新文档。

接下来,文档将发送给 Template 对象,由该对象使用在配置文件中指定的索引引擎执行实际索引。模板编程模型规定,在文档插入此模型后即可使用回调方法读取索引。在我们的实现中,此方法将访问索引,检索术语和频率向量,然后使用此向量提供给 SortedMap,这可以保证按照频率值进行排序,允许我们提取已按频率排序的术语的子集,如下所示:

int docNumber = reader.termDocs().doc();TermFreqVector[] freqs = reader.getTermFreqVectors(docNumber);TermFreqVector vector = freqs[0];int[] frequencies = vector.getTermFrequencies();String[] terms = vector.getTerms();SortedMap map = newTreeMap(Collections.reverseOrder());		for (int i=0; i

在获得排序的映射后,您可以只提取有限的术语集,最后将它们写出为单个字符串(通过粘合集成代码完成)。

在本部分中,您将了解如何在 Eclipse 中部署插件,如何配置应用服务器,如何将插件加载到 Service Registry 中,以及如何对解决方案进行测试。

在下载了完整的插件源项目(该项目包含在 中,与除 Service Registry 运行时客户端之外的所有依赖项绑定在一起)之后,您可以通过完成以下步骤将此项目导入到 Eclipse 安装中:

  1. 启动 Eclipse,指向一个空工作区。
  2. 在 Eclipse 中,选择 File => Import
  3. 在 Import 对话框中,选择 General => Existing Projects into Workspace,然后单击 Next,如图 5 所示。
    图 5. 选择导入类型
  4. 如图 6 所示,在 Import Projects 对话框中,浏览至下载的存档文件。Eclipse 将自动选择该文件中包含的唯一的项目。
    图 6. 选择存档文件
  5. 单击 Finish 以构建项目。最终的工作区应如图 7 所示。
    图 7. 初始工作区
  6. 通过右键单击 WSRRplug-inExport.jardesc 并选择 Open JAR Packager 立即生成二进制插件 JAR 文件。
  7. 在 JAR File Specification 对话框中,选择适当的 JAR 文件名,然后单击 Finish,如图 8 所示。
    图 8. 指定 JAR 文件

为了运行插件,您需要自定义应用服务器的配置,尤其是与类路径相关的配置,如本部分中所述。您可以使用此处描述的解决方案对插件进行测试,但是不应将此解决方案用于生产环境中,因为这些类路径操作尚需考证。

要测试解决方案,将需要以下存档文件,这些文件在本文中的部分提供:

  • wsrrplugin.zip,包含插件代码
  • WSRRFullTextDependencies.zip,包含运行时依赖项。将此文件解压缩到运行 Service Registry 的计算机上的目录中。例如,在一个 Linux 平台上,您可以创建目录 /usr/local/WSRRplug-inDependencies,然后使用以下命令解压缩依赖项存档:
    unzip -d /usr/local/WSRRplug-inDependencies
  • workspace.zip,包含工作区文件

要自定义应用服务器,请执行以下操作:

  1. 如果承载 Service Registry 的应用服务器尚未运行,请启动它。例如,在 Service Registry 典型的 Linux 安装中,输入以下命令:
    /opt/IBM/WebSphere/AppServer/bin/startServer.sh server1
  2. 将浏览器指向 http://localhost:9060/ibm/console,从左侧导航栏中选择 Servers => Application servers,然后在右侧窗格中选择 server1
  3. 在右侧窗格中,选择 Server Infrastructure => Java and Process Management => Process Definition => Java Virtual Machine。Java Virtual Machine Configuration 对话框将显示,如图 9 所示。
    • Classpath 字段中,指定依赖项存档展开到的目录中包含的每个 JAR 文件的完整路径。
    • Generic JVM arguments 字段中,添加以下文本:
      -Dcom.ibm.luceneintegration.factoryClass=com.ibm.luceneintegration.spring.FullSpringIntegration

      此文本将设置一个系统范围的属性,该属性可被工厂类读取,用于在集成实现之间进行切换,此时使用 Spring 模型。

    • 单击 OK 保存配置。
      图 9. 应用服务器配置
  4. 输入以下命令注销并重新启动服务器:
    /opt/IBM/WebSphere/AppServer/bin/stopServer.sh server1/opt/IBM/WebSphere/AppServer/bin/startServer.sh server1

该应用服务器现在已配置为承载可部署到 Service Registry 中的插件。

您现在应该获得了您的插件 JAR 文件,无论是通过下载获得的,还是从 Eclipse 工作区中创建的。

  1. 通过将浏览器指向 http://localhost:9080/ServiceRegistry 打开 Service Registry Web 用户界面。
  2. 选择 Perspective => Configuration,如图 10 中所示。
    图 10. 选择 Configuration 透视图
  3. 在左侧导航窗格中,选择 Active Configuration Profile => Plug-ins => JARs,然后在右侧窗格中单击 Load JAR Plug-In,如图 11 中所示。
    图 11. 加载 JAR 插件
  4. 在下一个对话框中,浏览至插件文件,指定名称(如 WSRRLuceneplug-in),然后单击 OK
  5. 当 Details 窗格显示之后,在左侧窗格中选择 Validation Properties
  6. 在右侧窗格中,单击 Validation properties plug-in (ValidationProperties),如图 12 中所示。
    图 12. 选择验证属性
  7. 在右侧窗格中,选择 Content 选项卡,然后查找以下文本:
    validators=com.ibm.sr.api.SRTemplateValidator,com.ibm.sr.api.SRBusinessModelValidator
    添加逗号和以下值(该值是新的集成验证器的类名称):
    com.ibm.luceneintegration.wsrr.FullTextValidator
  8. 单击 OK

验证器现在已经就位,并连接到 Service Registry。您处理的下一个文档将包含新属性 keywords,它允许您在 XPath 查询中执行全文搜索。

要确保一切都能按预期工作,请执行以下操作:

  1. 切换到 Service Registry Administrator 透视图。
  2. 在左侧导航窗格中,选择 Service Documents => Other Documents,然后在右侧窗格中单击 Load Documents
  3. 浏览至要搜索的文档(PDF、Excel 或 Word),输入文件的命名空间、描述和版本,然后单击 OK,如图 13 中所示。
    图 13. 导入文档
  4. 在确认消息中单击 Finish
  5. 加载文档后,您应看到带有指向该文档的链接的摘要页。单击此链接即可转到文档描述页。
  6. 在文档描述页上,单击 Properties 链接。Properties 对话框将显示,如图 14 所示。
    图 14. 具有新 keywords 属性的文档属性

您应看到新的 keywords 属性,包含可在文档中找到的最相关的令牌的列表。

现在即可体验真正的乐趣!尝试搜索

Service Registry Web UI 提供了一个查询向导,该向导将指导您创建 XPath 查询,但是此向导当前不接受通配符,这使我们无法使用它对我们的新搜索功能进行测试。但是,我们可以通过利用 Service Registry 保存的搜索功能解决这一局限性。

  1. 在 Service Registry Web UI 中,在左侧窗格中选择 Queries => Query Wizard,然后在右侧窗格中选择 All Entities 并单击 Next,如图 15 中所示。
    图 15. 打开 Query 向导
  2. 在下一个对话框中,指定 Dummy 作为属性名称,并指定 Dummy 作为属性值,然后依次单击 NextFinish
  3. 此查询可能不会返回任何结果,但是将为您提供保存此查询的选项,如图 16 中所示。在 Save this Search 部分中,为此搜索指定一个名称,如 mysearch,然后单击 Save
    图 16. 保存查询
  4. 在左侧窗格中,选择 MyService Registry => My Saved Searches => mysearch,如图 17 中所示。
    图 17. 选择保存的搜索
  5. 在 Details 对话框中,选择 Additional Properties 下的 Properties,然后单击 queryExpression
  6. 输入一个 XPath 查询,并使用匹配谓词来利用全文搜索功能,然后单击 OK。例如,要搜索我们在上一部分中导入的特定的 IBM 红皮书 ,您可以在 executeQuery 属性中使用以下 XPath 查询:
    /WSDL/GenericDocument[matches(@keywords,".*soa.*")]
  7. 通过选择 MyService Registry => My Saved Searches => mysearch 并单击 Run Search 重新运行此查询,如图 18 中所示。
    图 18. 重新运行保存的查询

您可以使用此流程来测试使用本体和全文查询的集成插件,例如:

/WSRR/GenericDocument[classifiedByAnyOf(.,’’) and matches(@keywords,’.*.*’) ]

在本文中,您学习了如何创建 Service Registry 插件来扩展搜索功能。具体来说,您了解到如何使用开源 Apache Lucene 项目将索引功能添加到 Service Registry 中,以及如何执行全文搜索。还学习了如何使用开源 Spring Framework 项目将插件代码的一些结构化方面外部化,通过增加灵活性和能力以声明方式添加或更改功能。通过一起使用 Spring Modules 项目,您学习了能够以更简单、支持 Spring 的方式与 Lucene 交互的简化编程模型。

您可以使用您所掌握的技术来添加许多其他的功能(如,处理英语以外的语言以及从特定的文档属性或启发式进程中确定这些语言的能力),也可以基于 Lucene 查询语音及其可与 Wikipedia 和 WordNet® 集成的能力集成语义搜索。基于文件的存储可以使索引具有持久性,还允许您重新找回这些索引并执行其他查询,甚至在 Service Registry 外部也可以。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-417707/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14789789/viewspace-417707/

你可能感兴趣的文章