通过支持原生存储 XML 文档,IBM® DB2® 9 向着混合型数据库系统迈出了革命性的一步。XQuery(DB2 中新的主要语言)允许以优化的方式操作 XML。但是,XML 也常常包含大块文本,无法用 XQuery 轻松地搜索它们。为了高效地搜索文档的这些非结构化部分,DB2 提供了一个全文搜索解决方案。本文主要关注 DB2 文本搜索的基本知识,包括创建文本索引和管理。本文还讨论 DB2 全文搜索的特定特性,比如用模糊搜索、接近搜索和词根化在 XML 文档中搜索关键字或短语。

Holger Seubert (hseubert@de.ibm.com), DB2 Text Search Development, EMC

Holger SeubertHolger Seubert 是一位 IBM 软件工程师,他主要关注 DB2 中的 XML 技术。他在位于德国 Boeblingen 的 IBM 开发实验室开始从事 XML 文档和 IBM 层次化数据库系统(IMS)之间的映射技术。Holger 现在从事 DB2 中的 XML 全文搜索解决方案的设计和实现。



Sabine Perathoner-Tschaffler (spera@de.ibm.com), DB2 Text Search Development, EMC

SabineSabine Perathoner-Tschaffler 是 IBM Boeblingen 实验室的软件工程师。她从事 DB2 中的全文搜索领域,重点在 XML 方面。



2006 年 7 月 21 日

XQuery 是用于访问 XML 数据的 W3C 标准,提供了许多用来导航和查询 XML 文档的扩展。也可以使用这种语言根据全文搜索条件搜索 XML 文档吗?答案是 “还不行”。XQuery 中目前不支持全文搜索特性。其原因在于 XQuery Data Model,这是每个 XQuery 表达式的基础。为了能够高效地搜索全文数据,需要关于组成数据文本内容的各个单词及其位置的信息。但是,在 XQuery Data Model 中,文本只是一个 “黑盒”。数据模型没有表示文本节点中的单词或符号的概念;它只是将元素或属性的文本内容表示为一个后续节点。

因此,XQuery 最多只能进行子字符串匹配。这个功能是用内置函数 contains() 实现的,这个函数以一个上下文和搜索词作为参数。

由于 DB2 9 将 XQuery 作为主要语言,在 DB2 命令窗口中可以执行以下 XQuery 表达式:

db2 => XQuery contains("e power of XML", "owe")

如前所述,contains() 函数实现子字符串匹配,因此对于以上查询返回 true。尽管用户搜索的是 “owe”,但是 contains() 也返回 “power” 等单词,这些可能不是用户实际上要寻找的搜索结果。还没有将文本搜索功能包含进 XQuery 语言中的标准。显然,这是 XQuery, Version 1 要完成的任务之一,已经在一个单独的工作组开始研究工作了:XQuery 1.0 and XPath 2.0 full text

在等待这个新标准出台的同时,目前能够根据关键字和短语搜索相关的 XML 文档吗?下一节简要概述 DB2 的全文搜索功能,它允许对 XML 进行感知结构的文本搜索。

DB2 Net Search Extender

在对 XML 文档进行文本搜索时,要同时考虑实际内容和文档结构。一种典型的场景是将文本搜索限制在特定的元素或整个 XML 文档结构的子树上,比如:

“寻找在 abstract 元素中有 ‘XML’ 和 ‘database’,并且在 title 元素中有 ‘text search’ 和 ‘Viper Release’ 的所有文档,这两个词应该在同一句话中。”

在 DB2 中,这种感知结构的 XML 文档全文搜索是通过 DB2 Net Search Extender(NSE)实现的,这是 DB2 附带的一种单独安装的特性。

文本搜索集成到 SQL 中,DB2 优化器在运行时会对它进行优化。可以使用 DB2 Control Center 执行创建和维护索引等管理任务。

Net Search Extender 使用 SQL 搜索数据库表的列中存储的文本数据。Net Search Extender 并不使用字符串匹配连续地搜索文本数据(就像 XQuery contains() 函数所做的那样),而是使用文本索引。使用文本索引使文档搜索的效率大大提高,因为不需要像进行子字符串匹配时那样在查询时检查文本数据。文本索引通常包含关于从文本文档中提取的相关词的信息。在 XML 文档的情况下,文本索引中不但包含重要的词汇,而且包含它们在 XML 文档结构中的位置。

既然已经熟悉了 Net Search Extender 的基本原理,就可以开始学习如何使用它对 XML 数据执行全文搜索。下一节中讨论如何创建文本索引。

为文本搜索做准备

搜索 DB2 中的 XML 文档需要执行的任务分成两部分:

  1. 索引管理任务
  2. 全文搜索

本节简要讨论这两种任务,使用的示例针对 清单 1 中定义的 “product” 表。注意,“product” 表的 “description” 和 “comments” 列是 XML 类型的(换句话说,“description” 和 “comments” XML 文档原生存储在数据库中)。

清单 1. 表定义
create table product (
    pid varchar(10) primary key not null,
    description xml,
    comments xml
    );

“product.description” 和 “product.comment” 列中存储的 XML 数据示例分别见 图 1图 2。后面的查询示例搜索这些 XML 文档的特定元素。“DB2 Viper 快速入门” (developerWorks,2006 年 3 月)讨论了如何在 DB2 中插入 XML 文档。

图 1. “product.description” 列的数据示例
产品 XML 数据示例
图 2. “product.comments” 列的数据示例
评论 XML 数据示例

首先考虑一下对 “product” 表执行文本搜索操作时需要做什么,比如搜索在评论的 “message” 元素中有单词 “satisfactory” 的产品的名称,或者在描述的 “details” 元素中有短语 “sugar and creamer” 的产品的名称。

在使用 Net Search Extender 之前,必须先启动它的实例服务,见 清单 2

清单 2. 启动 Net Search Extender 实例服务的命令
db2text start

注意,这个命令调用一个单独的可执行程序 db2text。以后会看到,任何文本索引管理任务都需要用命令 db2text 来执行。

在启动 Net Search Extender 之后,对 DB2 数据库启用文本搜索操作。这个步骤创建必需的管理表以及各种用户定义函数(UDF)和存储过程(STP),这是对 DB2 数据进行全文搜索所需要的,而且对每个数据库只执行一次。

对数据库 “test” 启用文本搜索操作的命令如下:

清单 3. 对数据库 “test” 启用文本搜索操作的命令
db2text enable database for text connect to test

如果还没有设置 DB2DBDFT 环境变量,那么所有 Net Search Extender 管理任务都需要 connect to <dbname> 子句,其中的 <dbname> 是数据库的名称。以下命令假设设置了 DB2DBDFT

在为数据库启用文本搜索操作之后,可以在以各种格式(比如 XML)存储文本数据的列上创建文本索引。create index 命令定义文本索引属性,比如更新频率、文档格式、索引目录等等,从而建立文本索引基础设施。关于各种索引属性的更多信息,请参考 Net Search Extender 文档。本文中的示例使用一个基本的文本索引创建过程,见 清单 4

清单 4. 在 “product.description” 上创建文本索引 ix1
 db2text create index ix1 for text on product(description)

清单 4 中的命令在 “product” 表的 “description” 列中本机存储的 XML 文档上创建一个名为 “ix1” 的全文索引。

注意,在创建文本索引之后,文本搜索还不能找到任何结果,因为此时文本索引不包含任何数据。如果没有指定更新频率,那么需要显式地对数据和文本索引进行同步。对文本索引进行同步的任务称为索引更新,通常在创建文本索引之后立即执行。

清单 5. 使文本索引与基表中的数据同步
db2text update index ix1 for text

索引更新过程可以使用 清单 5 中的命令手工执行,也可以使用后台守护进程自动执行。自动索引更新可以在创建索引时用索引属性指定,也可以以后使用 alter index 命令指定。

下面总结一下在 DB2 中准备全文搜索操作所需完成的步骤:

表 1. 在 DB2 中准备全文搜索操作的步骤
步骤说明示例
步骤 1启动 Net Search Extender 实例服务db2text start
步骤 2为数据库启用全文搜索db2text enable database for text
步骤 3创建全文索引db2text create index ixName for text on table(column)
步骤 4更新前面创建的全文索引db2text update index ixName for text

在完成这四个管理步骤之后,就可以对 XML 数据进行全文搜索了。那么,可以用来寻找相关信息的实际搜索特性是什么?


寻找要找的东西

用 Net Search Extender 执行全文搜索最常用的方法是使用它的 SQL 标量搜索函数 CONTAINS()。可以将它用在能够使用标准 SQL 的地方,而且可以将它与 SQL WHERE 中的其他条件轻松地组合在一起。另外,它与 DB2 优化器紧密集成,提供了很好的运行时性能。(还有其他两个用于更特殊情况的搜索方法,但是本文不讨论它们。)以下示例演示如何使用标量 CONTAINS() 函数执行全文搜索:

清单 6. 标量 CONTAINS 函数
SELECT column
FROM table
WHERE CONTAINS(column-name, 'search-criteria')=1;

CONTAINS() 函数有两个参数:列名(建立应该进行全文搜索的上下文)和应该应用的实际搜索条件。

Net Search Extender 的基本搜索条件具有以下特性:

  • 布尔操作用于搜索词的合并(AND)、分离(OR)和排斥(NOT)
  • 搜索词可以是单一单词短语,例如 “New”、“York” 或“New York”
  • 接近搜索可以搜索同一句子或同一段落中的单词
  • 模糊搜索可以搜索与搜索词拼写相似的单词
  • 通配符搜索使用前、中和尾匹配

Net Search Extender 提供的更高级的搜索特性如下:

  • 用于更广泛查询的词表支持,它不但搜索特定的搜索词,还通过用户定义的关系搜索相关的词
  • 搜索结构化文档或附加列中的数值范围
  • 词根化将搜索词缩减成它的词根,然后再进行搜索(只针对英语)

为了在 XML 文档的文档结构中进行目标明确的搜索,Net Search Extender 通过以下措施提供基于部分的搜索

  • 将搜索限制到 XML元素
  • 将搜索限制到 XML 属性
  • 支持混合内容类型的 XML 元素

既然已经了解了 Net Search Extender 提供的搜索特性的基本概念,现在就通过示例讲解它们的实际使用方法。

使用 SQL 和 XQuery 进行文本搜索

下面的查询访问 清单 1 中建立的 “product” 表。“product.description” 列中存储的 XML 数据示例见 图 1。后面的查询示例搜索这个 XML 列中的特定元素。

考虑下面这个对 “product” 表的简单文本搜索,它返回在产品信息(在 “product.description” 列中)的文档结构中有单词 “creamer” 的所有产品标识符(“pid” 数据):

清单 7. 文本搜索的基本语法
SELECT pid
FROM product
WHERE CONTAINS(description,' "creamer" ')=1;

通过使用 SQL/XML 函数 XMLQUERY(),可以让产品信息的各个 XML 元素出现在结果中。下面的查询返回文档结构中有单词 “creamer” 的产品的 “name” 元素:

清单 8. 结合使用文本搜索功能和 XMLQUERY()
SELECT XMLQUERY('$prod//name' passing description as "prod")
FROM product
WHERE CONTAINS(description, ' "creamer" ')=1;

清单 8 中的 SQL 全文搜索查询也可以用 XQuery 表示为:

清单 9. XQuery 上下文中的文本搜索
XQUERY for $prod in db2-fn:sqlquery("SELECT description
  FROM product
  WHERE CONTAINS (description, ' "creamer" ')=1")
return $prod//name

全文搜索表达式在 SQL 上下文中表达,相关的 XML 文档在 XQuery 上下文中使用 db2-fn:sqlquery() 输入函数进行处理。

在前面的示例中,文本搜索在整个 XML 文档结构上执行(换句话说,在所有文本节点和属性值上执行,而不管搜索条件匹配文档中的哪些部分)。那么,怎么将文本搜索限制到特定的 XML 元素或 XML 属性上呢?

将文本搜索限制到 XML 元素或属性上

将文本搜索限制到文档结构中的特定部分是 XML 全文搜索最常用的特性之一。在 DB2 Net Search Extender 中,将文本搜索限制到 XML 文档的特定元素或子树是用一个完全限定的 XPath 表达的。这个 XPath 标识应该搜索的 XML 文档结构部分。

Net Search Extender 支持缩写的 XPath 位置-步骤语法,允许使用子轴(/)和属性轴(@)。不支持其他 XPath 表达式或功能。

例如,可以用以下查询将对单词 “creamer” 和 “pattern” 的文本搜索限制到 “product.description” 中产品 XML 文档的 “name” 元素:

清单 10. 用 SECTION 子句将搜索限制到 XML 元素或属性
SELECT XMLQUERY('$prod//name' passing description as "prod")
FROM product
WHERE CONTAINS(description,'
             SECTION("/product/description/name") ("creamer","pattern") ')=1;

SECTION 子句作为文本搜索条件的一部分,标识出应该在 XML 文档结构的哪个部分中进行文本搜索。根据 XPath 标准的定义,上面的示例使用位置步骤标识出产品 XML 文档结构中的 XML “name” 元素。SELECT 语句返回在 “name” 元素中有任何次序的单词 “creamer” 和 “pattern” 的所有产品的 name 元素。

使用 XQuery,同样的查询也可以写成:

清单 11. XQuery 作为主要语言
XQUERY for $prod in db2-fn:sqlquery("SELECT description
     FROM product
     WHERE CONTAINS(description,
                    ' SECTION("/product/description/name") ("creamer","pattern" ')=1)
  return $prod//name

另外,还可以使用属性轴将文本搜索限制到特定的 XML 属性,见下面的示例:

清单 12. 将文本搜索限制到 XML 属性
SELECT XMLQUERY('$prod//name' passing description as "prod")
FROM product
WHERE CONTAINS(description,'
                SECTION("/product/description/category/@catx")"sterling" ')=1;

SECTION 子句使用对应的 XPath 将文本搜索限制到 “catx” XML 属性。这个查询返回 “catx” XML 属性值为 “sterling” 的所有产品的 “name” 元素。

清单 12 演示如何在同一 部分中搜索不同的词。还可以将不同 部分中的搜索组合起来。使用布尔 AND 操作符(&),清单 13 中的查询返回在 “category” 元素的 “catx” 属性中有 “sterling” 而且在 “name” 元素中有 “creamer” 的所有产品的 “name” 元素:

清单 13. 在不同的部分中进行搜索
SELECT XMLQUERY('$prod//name' passing description as "prod")
FROM product
WHERE CONTAINS(description,' SECTION("/product/description/category/@catx")"sterling"
                    & SECTION("/product/description/name")"creamer" ')=1;

跨元素边界进行搜索

有时候会遇到具有混合内容类型的 XML 元素,也就是既包含文本数据,也包含其他 XML 元素。例如,以下 XML 元素 “sentence” 包含一些文本和另一个元素 “entity”:

图 3. 混合内容类型的 XML 元素
混合内容类型的示例

在这种情况下,希望跨元素边界进行搜索(换句话说,在 “sentence” 元素中搜索短语 “IBM Software Group” 应该能够找到其他元素中出现的搜索词)。Net Search Extender 能够处理混合内容,即跨元素边界进行搜索。

假设将上面的 XML 片段存储在表 “product” 的列 “description” 中,以下查询返回一个结果:

清单 14. 查询结果
SELECT description
FROM product
WHERE CONTAINS(description,'
               SECTION("/sentence") "IBM Software Group" ')=1;

尽管符号 “IBM” 是元素 “entity” 的直接文本节点,而文本搜索的范围是 XML 元素 “sentence”,但是查询找到了一个结果。

到目前为止,还没有充分揭示全文索引的实力。您已经看到了将搜索限制到文档结构的特定部分的示例,但是 Net Search Extender 还提供了表达搜索条件的其他方式。

文本搜索的实力

除了将文本搜索限制到特定的元素或属性之外,Net Search Extender 还提供了几个用来定义文本搜索条件的其他特性。例如,可以将文本搜索限制到只匹配同一句子中出现的单词(接近搜索)。

下面几节提供前面提到的几个搜索特性的示例。

清单 15 中的查询寻找不仅在 XML 文档的 “details” 元素,而且在同一句子 中有 “pattern” 和 “sugar and creamer” 所有产品的产品标识符:

清单 15. 接近搜索
SELECT pid
FROM product
WHERE CONTAINS(description, 'SECTION("/product/description/details") "pattern"
               IN SAME SENTENCE AS "sugar and creamer"')=1;

这个示例中组合了两个结构化约束:搜索被限制到一个特定的元素(“details”),而且在这个元素的文本内容(它的文本节点)中,搜索限制到在同一句子中出现的单词。注意,搜索词 “sugar and creamer” 组成一个短语,这会搜索在句子中出现的三个单词 “sugar”、“and” 和 “creamer”。另一方面,要在同样的上下文中搜索任意次序的 符号 “creamer”、and” 和 “sugar”,可以使用下面的表达方式:

清单 16. 短语搜索和符号搜索之间的差异
SELECT pid
FROM product
WHERE CONTAINS(description, 'SECTION("/product/description/details") "pattern"
                IN SAME SENTENCE AS ("creamer","and","sugar")')=1;

布尔操作符

可以使用布尔操作符 “&”(AND)、“|”(OR)和 NOT 将不同的搜索词组合起来。下面的示例使用布尔操作符 AND 和 OR 组合几个搜索词:

清单 17. 使用布尔操作符 AND 和 OR
SELECT pid
FROM product
WHERE CONTAINS(description, 'SECTION("/product/description") 
"pattern" & "creamer" | "sugar" ')=1;

这个查询返回在 description 元素中有 “pattern” 并且有 “creamer” 或 “sugar” 的所有产品的 “pid”。

可以使用布尔操作符 NOT 从搜索结果中排除特定的词。例如,清单 18 中的查询搜索在 “description” 元素中有 “pattern” 和 “creamer”,但是没有 “sugar” 的文档:

清单 18. 布尔操作符 NOT
SELECT pid
FROM product
WHERE CONTAINS(description,
         'SECTION("/product/description") "pattern" & "creamer" & NOT "sugar" ')=1;

模糊搜索

另一个流行的特性是模糊搜索。模糊搜索寻找包含与提交的搜索词拼写相似的词的文档。因此,需要匹配前 3 个字符。当文档中可能有错误的拼写时,常常使用模糊搜索。

清单 19. 模糊搜索寻找拼写相似的词
SELECT pid
FROM product
WHERE CONTAINS(description,
      'SECTION("/product/description") FUZZY FORM OF 80 "patern" & "creamer"')=1;

注意,“patern” 拼写错了,但是用模糊搜索可以找到包含拼写正确的 “pattern” 的文档。匹配级别(在这个示例中是 80)指定精确度。精确度的范围在 1 到 100 之间,100 是精确匹配。

词根化

搜索单词的词根形式将搜索词缩减成它的词根,然后再进行搜索。下面的示例搜索 “patern” 的模糊形式或 “creamy” 的词根形式。词根化搜索返回在文本内容中有 “creamer”、“creamed” 或 “cream” 等词的文档。

清单 20. 对 “creamy” 进行词根化搜索
SELECT pid
FROM product
WHERE CONTAINS(description, 'SECTION("/product/description")
           FUZZY FORM OF 42 "patern" | STEMMED FORM OF "creamy"')=1;

通配符

Net Search Extender 支持两种用于通配符搜索的字符匹配:

  • 匹配任何单一字符(_)
  • 匹配任意数量的任何字符(%)

使用通配符搜索的一个查询示例见 清单 21

清单 21. 用通配符进行搜索
SELECT pid
FROM product
WHERE CONTAINS(description, 'SECTION("/product/description") "pat_ern" & "cream%" ')=1;

这个查询将匹配在 “description” 元素中包含 “pattern” 和 “creamer” 等词的文档。

总需要考虑的一个问题

您可能会奇怪,为什么到目前为止还没有在 “product” 表的 “comments” 列中进行搜索。这是因为要用它讲解在 XML 文档中进行搜索的一个重要方面:总是返回完整的 XML 文档作为搜索结果,而不只是出现匹配的特定文档部分或元素。

我们以 “comments” XML 文档为例讲解这个问题,这些文档的基本结构见 图 2。与 “product” 文档相比,这些文档有一个不同的结构性质。在 “comments” 元素中,有多个重复的 “comment” 元素。

例如,要搜索在评论的 “message” 元素中有 “disappointing” 词根形式的产品的名称,可以编写下面的查询:

清单 22. 搜索在评论的 “message” 元素中有 “disappointing” 词根形式的产品的名称
SELECT XMLQUERY('$prod//name' passing description as "prod")
FROM product
WHERE CONTAINS(comments, 'SECTION("/comments/comment/message")
                          STEMMED FORM OF "disappointing"')=1

这个查询以以下方式返回产品的名称:

<name>Sterling Sugar & Creamer by Gorham</name>
   1 record(s) selected.

只要不直接访问重复的部分,比如这个示例中 “comments” 列中的 “comment” 元素,那么搜索具有重复文档部分的 XML 文档无需任何进一步的考虑就可工作。

但是,如果希望获得发表了包含 “disappointment” 的评论的顾客的 “customerID”,那么第一种寻找这一信息的方法如下:

清单 23. 获得发表了包含 “disappointment” 的评论的顾客的 “customerID”
XQuery for $co in db2-fn:sqlquery("SELECT comments
                    FROM product
                    WHERE CONTAINS(comments,
                         'SECTION("/comments/comment/message")
                          STEMMED FORM OF "disappointed"')=1")
       return $co//customerID

返回的 XML 元素序列是:

清单 24. 返回的 XML 元素序列
<customerID>1187594</customerID>
<customerID>238461</customerID>

  2 record(s) selected

可以看到,没有发表 包含 “disappointment” 的评论的顾客的 “customerID” 也返回了。

类似,这个查询在 SQL 上下文中可以表示为:

清单 25. SQL 上下文中表示的同一查询
SELECT XMLQUERY('$co//customerID' passing comments as “co”)
FROM product
WHERE CONTAINS(comments, 'SECTION("/comments/comment/message")
                          STEMMED FORM OF "dissapointed"')=1

返回的序列是:

<customerID>1187594</customerID><customerID>238461</customerID>

  1 record(s) selected.

同样,这个搜索查询返回两个 “customerID” 元素,因为搜索总是返回完整的 XML 文档。在处理 XML 搜索结果时,考虑到这个方面很重要。但是,如何能够获得要寻找的单一 “customerID” 呢?

在不使用词根化那样的高级搜索功能的情况下,解决方案可能是使用前面介绍过的 contains() XQuery 内置函数。

以下查询使用全文搜索信息过滤出在 “message” XML 元素中有 “disappointing” 的那些文档。对这些文档的搜索返回满足搜索条件的完整 “comments” 文档。与前面的查询相反,以下查询使用 contains() XQuery 函数在 message 元素上添加一个谓词。这样的话,满足全文搜索条件的这些文档会根据 XPath 谓词进一步进行过滤。

清单 26. 满足全文搜索条件的文档根据 XPath 谓词进一步进行过滤
SELECT XMLQUERY('$co/comments/comment[contains(message,"disappointing")]
                    /customerID' passing comments as "co")
FROM product
WHERE CONTAINS(comments, 'SECTION("/comments/comment/message")
                          "disappointing"')=1;

同样的查询也可以在 XQuery 上下文中表示:

清单 27. XQuery 上下文中表示的同一查询
XQuery for $co in db2-fn:sqlquery('SELECT comments FROM product
         WHERE CONTAINS(comments,
        ''SECTION("/comments/comment/message") "disappointing" '')=1')
       return $co/comments/comment[contains(message,"disappointing")]/customerID

这两个查询都返回发表了不满意评论的顾客的 “customerID” 元素。

<customerID>238461</customerID>

  1 record(s) selected

XML 名称空间考虑事项

在 XML 数据属于特定的非默认名称空间的情况下,在搜索文档结构中的特定元素或子树时必须使用完全限定的名称(名称空间前缀+元素名称)。

假设 XML 产品数据的元素属于一个以 “ns” 为前缀的名称空间。

图 4. 具有名称空间的 XML 产品数据
具有名称空间的 XML 产品数据

对于前一个搜索示例,Net Search Extender 在这种情况下找不到任何结果:

清单 28. Net Search Extender 找不到任何结果
SELECT pid
FROM product
WHERE CONTAINS(description,
           'SECTION("/product/description/details") "pattern"')=1;

用来定义要搜索的 XML 部分的 XPath 表达式没有包含名称空间前缀 —— 换句话说,没有包含完全限定的元素名称(QName)。

SECTION 参数中必须使用完全限定的 XML 元素名称,才能搜索示例文档:

清单 29. 在 SECTION 参数中使用完全限定的 XML 元素名称
SELECT pid
FROM product
WHERE CONTAINS(description,
           'SECTION("/ns:product/ns:description/ns:details")
           "pattern"  IN SAME SENTENCE AS "sugar and creamer"')=1;

Net Search Extender 按照元素/属性名称在文档中出现的形式对它们进行匹配,包括任何名称空间前缀。但是,如果使用默认名称空间,那么就不必给元素加前缀!

对如何定位 XML 文档结构中的各个部分进行配置的一种方法是使用 Net Search Extender 文档模型。下一节解释它的使用方法。

NSE 文档模型揭秘

可以使用 Net Search Extender 文档模型配置结构化文档(比如 XML)中要搜索的范围。文档模型主要控制文档结构的哪些 部分要建立索引、这些部分如何 建立索引以及在搜索期间用哪些名称 引用这些文档部分。

有两种文档模型:

  • 默认文档
  • 用户定义的定制文档模型

要使用定制的文档模型,就必须在创建文本索引时指定一个文档模型。如果没有通过索引参数提供定制的文档模型,那么 Net Search Extender 使用它的默认模型。

到目前为止,本文中的示例都使用 Net Search Extender 提供的默认文档模型。默认文档模型的性质是:

  • 文档的所有部分都建立索引(对于 XML 文档,这包括所有元素和属性)
  • 可以使用与 XPath 相似的语法将搜索限制到特定的文档部分
  • 数值不建立索引,所以不支持数值比较或范围搜索

如果使用定制的文档模型,就可以:

  • 定义 XML 文档的哪些部分应该建立索引,哪些部分应该排除在索引之外
  • 为某些 XML 子树、XML 元素或属性定义定制的名称
  • 将 XML 元素或属性内容定义为数值,从而允许在此内容上进行数值比较或范围搜索

文档模型本身是一个 XML 文档,它采用一种预定义的语法(语法定义见 Net Search Extender 文档)。文档模型在一个文件中定义,它们指定对结构化文档(例如 XML 格式的文档)进行解析和建立索引的模型。在创建索引期间,模型文件作为参数传递,而且只在此期间被读取;以后的修改不影响现有的索引。

图 5 针对产品数据(参见 清单 1)定义了一个定制文档模型。这个文档模型存储在文件 nsemodel.xml 中。

图 5. 定制文档模型
NSE 定制文档模型

每个 XML 文档模型都以 “XMLModel” 元素开头。XMLModel 可以有两个 XML 子元素:

表 2. NSE XML 模型文件元素
模型文件元素说明
XMLFieldDefinition这个元素为 XML 文档的特定部分、元素或属性(由 “XMLFieldDefinition” 的 “locator” 属性标识)定义一个定制的名称
XMLAttributeDefinition这个元素在可以用于数值(参数化)搜索的 XML 元素或 XML 属性上定义一个 NSE 属性

locator 属性

这两个模型文件元素 “XMLFieldDefinition” 和 “XMLAttributeDefinition” 都用 “locator” 属性标识源 XML 文档的部分。locator 属性支持子轴(/)、后代及本身轴(//)和属性轴(@)。

另外,模型文件还支持在指定位置时使用通配符。清单 30 中的示例 (1) 定义的 locator 属性标识 “product” 元素的所有子元素。在示例 (2) 中,location 属性引用属于特定名称空间 “ns” 的 “product” 的所有子元素。

另外,locator 属性还可以标识特定的节点类型。Net Search Extender 支持评论节点(清单 30 中的示例 3)和处理指令(PI)节点。另外,还可以像示例 4 那样定义元素的组合。

清单 30. locator 属性值示例
(1) locator="/product/*"
(2) locator="/product/ns:*"
(3) locator="/product/comment()
(4) locator="name | details"

总之,locator 属性定义应该建立索引的文档部分。可以使用 XPath 表达式的一个子集来指定 locator 属性:

  • 子轴(‘/’ 或 ‘child::’)
  • 后代及本身轴(‘//’)
  • 属性轴(‘@’ 或 ‘attribute::’)
  • 评论类型节点测试(‘comment()’)和 PI 类型节点测试(‘processing-instruction()’)
  • 节点的组合(‘|’)
  • 通配符(‘*’)

name 属性

“XMLFieldDefinition” 或 “XMLAttributeDefinition” 元素的 “name” 属性定义一个名称,可以用这个名称引用 “locator” 属性值标识出的 XML 文档结构部分。

对于名称的定义,可以使用三个特殊的变量支持自动生成 name 值:

表 3. name 属性的特殊值
属性值说明
name="$(NAME)"表示 locator 属性的 XPath 表达式标识出的 XML 元素或属性的限定名称(QName)
name="$(LOCALNAME")表示 locator 属性的 XPath 表达式标识出的 XML 元素的局部名称(没有名称空间前缀)
name="$(PATH)"表示 locator 属性的 XPath 表达式标识出的 XML 元素或属性的绝对路径

根据默认文档模型的性质,可以猜到它定义为下面这样:

图 6. 默认文档模型的定义
默认文档模型的定义

type 属性

“type” 属性只能与 “XMLAttributeDefinition” 一起使用。惟一允许的值是 NUMBER,这指定 locator 属性标识出的元素或属性可以用于参数化搜索。

使用定制文档模型的索引定义

定义了定制模型文件之后,就可以在创建索引时使用它。一个使用定制文档模型的文本索引定义如下:

清单 31. 定义使用定制文档模型的文本索引
db2text create index ix2 for text on product(description)
                   format xml documentmodel XMLModel in nsemodel.xml

在创建索引时指定的文档模型参数指定模型文件的根元素。在 XML 的情况下,根元素是 <XMLModel>。另外,需要指定位置(模型文件的文件名)。

在根据定制文档模型创建新索引 “ix2” 并更新刚创建的索引之后,就可以开始根据文档模型中描述的规则搜索文档结构。

利用定制文档模型搜索结构

根据定制文档模型的性质,可以使用文档模型中定义的名称标识应该进行搜索的文档结构部分。没有在文档模型中由 locator 属性标识的任何其他文档部分不会建立索引,因此不能搜索它们。

例如,以下查询将搜索限制到 图 5 的文档模型中名称 “description” 所标识的文档部分,从而返回一个结果:

清单 32. 查询结果
SELECT pid
FROM product
WHERE CONTAINS(description,'SECTION("description") "pattern"')=1;

但是,根据用 图 5 的定制文档模型定义的索引,执行以下查询却不返回结果,尽管引用了文档的相同部分:

清单 33. 查询结果
SELECT pid
FROM product
WHERE CONTAINS(description, 'SECTION("/product/description/details") "pattern"')=1;

参数化搜索

根据 图 5 的模型文件中的 “XMLAttributeDefinition”,可以对 “price” 元素的值进行参数化搜索。以下查询寻找价格在 50 和 120 之间的产品:

清单 34. 参数化搜索
SELECT pid
FROM product
WHERE CONTAINS(description, 'ATTRIBUTE "price" BETWEEN 50 AND 120')=1;

如果希望寻找价格大于 120 美元的产品,就需要考虑货币种类,那么应该怎么办?看一下 图 1 中的 XML 文档示例,会发现货币种类是 XML 元素 “price” 的一个属性。除了使用关键字 “BETWEEN” 进行范围搜索之外,还可以使用操作符 GREATER THAN(‘>’)和 LESS THAN(‘<’)进行参数化搜索。考虑货币种类需要使用 XMLEXISTS() SQL/XML 函数:

清单 35. 使用 XMLEXISTS() SQL/XML 函数
SELECT pid
FROM product
WHERE CONTAINS(description, 'ATTRIBUTE "price" > 120')=1 AND
      XMLEXISTS('$prod/product/description/price[@currency="us"]'
      passing description as "prod");

结束语

DB2 Net Search Extender 提供了一种灵活的查询语言,可以根据复杂的获取操作(例如涉及布尔组合、通配符和模糊搜索)寻找相关信息。因此,可以将搜索限制到文档结构中的特定 XML 元素或 XML 属性。可以利用 Net Search Extender 定制文档模型对 DB2 中感知结构的搜索进行进一步配置。


致谢

感谢 Cindy Saracco、Bert van der Linden、Stefan Momma 和 Michael Haide 对本文进行了审阅。

参考资料

学习

获得产品和技术

  • 下载 DB2 9 测试版本 和 Net Search Extender,尝试本文中描述的查询技术。
  • 使用 IBM 试用软件 构建您的下一个开发项目,这些软件可以从 developerWorks 直接下载。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management, XML
ArticleID=148454
ArticleTitle=DB2 中的 XML 全文搜索
publish-date=07212006