Oracle Text 是一种功能强大的搜索技术,它内置于 Oracle 数据库的所有版本(包括免费提供的快捷版 (XE))中。它所提供的开发 API 使软件开发人员能够轻松实现功能齐备的内容搜索应用程序。
Oracle Text 可用于搜索结构化和非结构化文档,是对 SQL 通配符匹配的补充。Oracle Text 支持使用基本的布尔运算符(AND、OR、NOT、NEAR 等)将多个搜索条目组合到一起,此外,它还具有更高级的功能,如 soundex 和模糊搜索,以及结果排序等。该技术支持数百种文件类型,包括 Microsoft Office 和 PDF。Oracle Text 适合多种与搜索相关的使用情况和存储结构。Text 的应用领域包括电子商务、文档和记录治理,以及问题跟踪等。可检索的文本可以结构化形式驻留在数据库中,也可以非结构化形式驻留在本地文件系统中或 Web 上。
Oracle Text 提供完整的基于 SQL 的搜索 API,该 API 包含自定义查询运算符、DDL 语法扩展、一组 PL/SQL 过程和数据库视图。通过 Text API,应用程序开发人员可完全控制索引、查询、安全、演示以及有时会需要的软件配置,在开发即需即用的非自定义软件时尤为如此。通过即需即用的软件产品,您希望使软件的配置尽可能简约,即使这意味着要在产品开发中多做一些前期工作也是如此。降低应用程序的复杂性通常会在产品生命周期的后期,尤其是在支持、维护和未来产品开发阶段中见到成效。
Oracle Text 还支持文档级授权,而文档级授权通常很难在统一的同时保持高性能。借助 Text,组合了关系数据与非结构化数据的混和查询也得到了很好的支持。对于授权,这意味着您可以将全文搜索和授权合并到一个查询中。独立结果集和获得最终结果所需的过滤阶段的数量可最大程度地缩减,从而简化了应用程序的开发。Oracle Text 使应用程序开发人员从繁琐的开发中解脱出来,可以集中精力进行性能优化。
Oracle Text 也是编程语言不可知的,并且也可以同样卓越的表现为 PHP 以及 Java 应用程序工作。
前一段时间,我需要提高企业内容治理 (ECM) 系统的搜索功能。我首先对 Oracle Text 的使用进行了评估。评估证实 Oracle Text 是一种构建应用程序搜索非常可行的技术:它具有高级搜索功能,支持大量不同的文件类型,可高度自定义,同时高度可伸缩。原有搜索技术的一个缺点是,您需要在数据库外部运行文件内容搜索,然后运行数据库元数据搜索,对结果进行授权,最后,合并独立的结果集。使用 Oracle Text,所有这些操作都可以在数据库中进行。ECM 系统已经使用 Oracle 数据库来存储元数据。因为此项技术已经推出,因此客户自然会选择使用,而且它也不会给客户增加任何成本。
在数据库中执行自由文本搜索查询的简单方法类似于:
SELECT * FROM issues
WHERE LOWER(author) LIKE '%Word1%' AND LOWER(author) LIKE '%word2%' ...
使用这种方法,每一列都需要与每个要害字单独进行匹配。在每一列中,可以任何顺序与要害字进行匹配。然而,关系数据库的设计使得它不会像上面那样有效地执行查询,而且使用这种方法会产生极其不可伸缩的应用程序。当然,您可以设计自己的索引和搜索解决方案,但是,那样您可能不会优化使用您的资源,在您已经为将搜索技术作为数据库的一部分付出了成本的情况下尤为如此。
本文讨论 Oracle Text 在虚拟的问题跟踪应用程序中的使用。在这个应用程序中,用户可以创建一些包含元数据和可选附加文件的问题。该应用程序利用 Oracle Text 实现元数据和可选附加文件内容的全文搜索功能。
此处给出的示例已经在 Linux 的 Oracle 数据库 XE 上进行了测试,这些示例应该同样也可在其他 Oracle 平台上运行良好。
索引进程与搜索
Oracle Text 为可检索的数据项建立索引之后,用户才能够通过搜索查找内容。编制索引是确保搜索性能的常用方法。Oracle Text 的索引进程是根据管道建模的,在这个管道中,从数据存储检索来的数据项经过一系列转换之后,其要害字会添加到索引中。该索引进程分为多个阶段,每个阶段都由一个单独的实体来处理,并可由应用程序开发人员来配置。
Oracle Text 具有适合不同用途的不同索引类型。对于大型文档的全文搜索,适合使用 CONTEXT 索引类型。该索引进程包括以下几个阶段:
数据检索:只是将数据从数据存储(例如 Web 页面、数据库大型对象或本地文件系统)中取出,然后作为数据流传送到下一个阶段。
过滤:过滤器负责将各种文件格式的数据转换为纯文本格式。索引管道中的其他组件只能处理纯文本数据,不能识别 Microsoft Word 或 Excel 等文件格式。
分段:分段器添加关于原始数据项结构的元数据。
词法分析:根据数据项的语言将字符流分为几个字词。
索引:最后一个阶段将要害字添加到实际索引中。
索引构建完成后,应用程序即可通过普通的 SQL 查询执行最终用户输入的搜索。
安装 Oracle Text
在默认情况下,Oracle Text 随 Oracle 数据库 XE 一起安装。如何使用的是其他数据库版本,您需要自己安装 Oracle Text 功能。安装了此功能后,您只需创建一个普通的数据库用户,并赋予该用户 CTXAPP 角色。这样,用户即可执行特定的索引治理过程:
CREATE USER ot1 IDENTIFIED BY ot1;
GRANT connect,resource, ctxapp TO ot1;
文件索引
此处,您要创建一个文本表,用于为存储在问题跟踪系统中的附加文件内容建立索引。附加文件存储在文件系统中。除了应用程序的数据模型所需的列之外,文本基表还包括一个绝对文件路径和一个格式列。
CREATE TABLE files (
id NUMBER PRIMARY KEY,
issue_id NUMBER,
path VARCHAR(255) UNIQUE,
ot_format VARCHAR(6)
);
INSERT INTO files VALUES (1, 1, '/tmp/oracletext/found1.txt', NULL);
INSERT INTO files VALUES (2, 2, '/tmp/oracletext/found2.doc', NULL);
INSERT INTO files VALUES (3, 2, '/tmp/oracletext/notfound.txt', 'IGNORE');
此处 ot_format 的值是 Oracle Text 在索引过程中解析出来的。NULL 值表明系统会为文件自动选择一个过滤器,而假如值为 IGNORE,系统会跳过整个文件。
可以使用以下语句创建文本索引:
CREATE INDEX file_index ON files(path) INDEXTYPE IS ctxsys.context
PARAMETERS ('datastore ctxsys.file_datastore format column ot_format');
该语句将启动索引进程,索引进程将通过存储在基表中的路径在文件系统中检索文件,然后对内容进行过滤并建立索引。这样便创建了一个区分大小写并具有精确匹配语义的 CONTEXT 索引。该索引进程可以多种方式进行自定义,例如支持前缀和后缀匹配。
虽然大部分时间过滤阶段无需为每个文件指定文件格式即可很好地运行,但是,在基表中添加这一列可以对索引进程进行进一步控制。例如,使用格式列,您可以跳过某些文件类型不为其建立索引。当您只想正式支持应用程序中 Oracle Text 所支持的部分文件格式时,这一列非常有用。
Oracle Text 还可用于元数据的全文搜索。在示例应用程序中,有一个名为 issues 用于存储问题元数据的表。该表的定义如下:
CREATE TABLE issues (
id NUMBER,
summary VARCHAR(120),
description CLOB,
author VARCHAR(80),
ot_version VARCHAR(10)
);
ot_version 列为索引列,可用于强制为特定文档重新建立索引。该表可使用测试数据填充:
INSERT INTO issues VALUES (1, 'Jane', 'Text does not make tea',
'Oracle Text is unable to make morning tea', 1);
INSERT INTO issues VALUES (2, 'John', 'It comes in the wrong color',
'I want to have Text in pink', 1);
用户索引
Oracle Text 可为来自不同数据源的数据建立索引。Oracle Text 可用于问题跟踪系统,提供对问题元数据的全文搜索。在默认情况下,您可为单个列中的值建立索引,但是,假如要合并多个表的数据,您需要创建一个自定义的 PL/SQL 过滤器过程。我将演示如何创建这样的过程,这个过程将起到存储抽象的作用。然后,该索引进程将迭代文本表中所有的行,为每一行调用过滤器过程。过滤器过程将返回所有与问题相关的有待建立索引的文本。
-- declare indexing procedure
CREATE PACKAGE ot_search AS
PROCEDURE issue_filter(rid IN ROWID, tlob IN OUT NOCOPY CLOB);
END ot_search;
/
-- define indexing procedure
CREATE PACKAGE BODY ot_search AS
PROCEDURE issue_filter(rid IN ROWID, tlob IN OUT NOCOPY CLOB) IS
BEGIN
FOR c1 IN (SELECT author, summary, description FROM issues WHERE rowid = rid)
LOOP
dbms_lob.writeappend(tlob, LENGTH(c1.summary)+1, c1.summary ' ');
dbms_lob.writeappend(tlob, LENGTH(c1.author)+1, c1.author ' ');
dbms_lob.writeappend(tlob, LENGTH(c1.description), c1.description);
END LOOP;
END issue_filter;
END ot_search;
/
-- define datastore preference for issues
BEGIN
ctx_ddl.create_preference('issue_store', 'user_datastore');
ctx_ddl.set_attribute('issue_store', 'procedure', 'ot_search.issue_filter');
ctx_ddl.set_attribute('issue_store', 'output_type', 'CLOB');
END;
/
-- index issues
CREATE INDEX issue_index ON issues(ot_version) INDEXTYPE IS ctxsys.context
PARAMETERS ('datastore issue_store');
搜索
CONTAINS 运算符用于搜索 CONTEXT 索引。虽然 CONTAINS 运算符语法的确支持 soundex 匹配等更高级的功能,但在这些示例中,我们只用了简单的布尔运算符来合并要害字。对于 Oracle Text 支持的语言,模糊匹配和词根还原都是默认启用的。要利用这些高级搜索功能,只需将 fuzzy() 或 $ 查询运算符分别与 CONTAINS 运算符结合使用即可。通配符字符可用于前缀和后缀匹配的 CONTAINS 查询。下面是一些简单的查询示例:
SELECT id FROM issues WHERE CONTAINS(ot_version, 'color AND pink', 1) > 0;
SELECT id FROM issues WHERE CONTAINS(ot_version, 'jane OR john', 1) > 0;
索引维护
由于基表数据是由索引复制的,因此这些数据需要定期与索引进行同步。在 CTX_DDL PL/SQL 程序包中可以发现索引维护过程。下面给出了一个示例,显示如何更新索引以反映基表更改:
EXECUTE ctx_ddl.sync_index('issue_index', '2M');
该同步过程为操作提供了索引名称和使用的内存量。也可以让数据库定期自动执行此项任务。您也可以选择使用操作系统或其他计划工具来启动同步。例如,在 Unix 系统上,可安排以下 shell 脚本与 Cron 作业,使系统按计划执行同步:
#!/bin/sh
eXPort ORACLE_SID=orcl
export ORAENV_ASK=NO
source /usr/local/bin/oraenv
sqlplus ot1/ot1@XE > synch.log <
WHENEVER SQLERROR EXIT 5;
EXECUTE ctx_ddl.sync_index('issue_index', '2M');
EOF
CTX_DDL 程序包还包含其他有用的过程,例如索引优化,用于消除索引碎片和清除过期的数据。
假如出现错误,可通过 CTX_USER_INDEX_ERRORS 视图跟踪索引错误。
数据库根据索引列更改跟踪文档的变更,因此,假如您希望强制 Oracle Text 重新为某些文档建立索引,可以更新相应行的索引列,如下所示:
UPDATE files SET path=path WHERE id = 4;
这将在同步索引时更新 id 为 4 的文件的索引要害字。