oracle一直致力于全文检索技术的研究,当oracle9i rlease2发布之时,oracle数据库的全文检索技术已经非常完美,oracle text使oracle9i具备了强大的文本检索能力和智能化的文本管理能力。oracle text是oracle9i采用的新名称,在oracle8/8i中它被称作oracle intermedia text,在oracle8以前它的名称是oracle context cartridge。使用oracle9i和oracle text,可以方便而有效地利用标准的sql工具来构建基于文本的新的开发工具或对现有应用程序进行扩展。应用程序开发人员可以在任何使用文本的oracle数据库应用程序中充分利用oracle text搜索,应用范围可以是现有应用程序中可搜索的注释字段,也可是实现涉及多种文档格式和复杂搜索标准的大型文档管理系统。oracle text支持oracle数据库所支持的大多数语言的基本全文搜索功能。本文将介绍如何使用oracle9i的全文检索技术来为自己的应用提供一个优秀的解决方案。
1 oracle text的体系架构
下图是oracle text的体系架构。
图1 oracle text的体系架构
以上面的体系架构图为基础,oracle text 索引文档时所使用的主要逻辑步骤如下:
(1)数据存储逻辑搜索表的所有行,并读取列中的数据。通常,这只是列数据,但有些数据存储使用列数据作为文档数据的指针。例如,url_datastore 将列数据作为 url 使用。
(2)过滤器提取文档数据并将其转换为文本表示方式。存储二进制文档 (如 word 或 acrobat 文件) 时需要这样做。过滤器的输出不必是纯文本格式 — 它可以是 xml 或 html 之类的文本格式。
(3)分段器提取过滤器的输出信息,并将其转换为纯文本。包括 xml 和 html 在内的不同文本格式有不同的分段器。转换为纯文本涉及检测重要文档段标记、移去不可见的信息和文本重新格式化。
(4)词法分析器提取分段器中的纯文本,并将其拆分为不连续的标记。既存在空白字符分隔语言使用的词法分析器,也存在分段复杂的亚洲语言使用的专门词法分析器。
(5)索引引擎提取词法分析器中的所有标记、文档段在分段器中的偏移量以及被称为非索引字的低信息含量字列表,并构建反向索引。倒排索引存储标记和含有这些标记的文档。
2 简单的示例
这里先给出一个简单示例说利用oracle text实现全文检索的方法与步骤,在后面在进行具体的说明。orcale9i提供了oracle text manager可以简化许多工作,所有在oracle text manager中完成的工作,都可以在通过pl/sql来实现。要使用oracle text,必须具有ctxapp角色或者是ctxsys用户。oracle text为系统管理员提供ctxsys用户,为应用程序开发人员提供ctxapp角色。
ctxsys用户可执行以下任务:启动oracle text服务器,执行ctxapp角色的所有任务。
具有ctxapp角色的用户可执行以下任务: 创建索引,管理 oracle text 数据字典,包括创建和删除首选项,进行oracle text 查询,使用 oracle text pl/sql程序包。
使用oracle text的步骤:
(1)创建表来保存某些文档。该示例使用一个主关键字列来标识每个文档,使用一个小的varchar2列来保存每个文档。
create table docs (id number primary key, text vachar2(80));
(2)将两个示例文档置入该表:
insert into docs values (1,the first doc);
insert into docs values (2,the second doc);
commit;
(3)使用oracle text manager来创建和修改首选项,首选项将与索引相关联。
(4)使用oracle text manager创建文本索引。另外,可以输入以下使用默认首选项的 sql 语句:
create index doc_index on docs(text) indextype is ctxsys.context;
(5)使用 contains 函数,发出基于内容的文档查询。例如:
select id from docs where contains (text, first) > 0;
这将在文本列包含单词 first (即文档1) 的 docs 中查找所有行。语句中的>0部分是有效的oracle sql所必需的,oracle sql不支持函数的布尔返回值。
以上只是一个简单的示例,旨在给出使用oracle text建立全文索引的完整步骤,归纳起来如下:
(1)建表并装载文本(包含带有需要检索的文本字段)
(2)配置索引
(3)建立索引
(4)发出查询
(5)索引维护:同步与优化(将在后面介绍)
3 文本装载
要实现文本的全文检索首先必须把正确的文本加载到数据库表中,默认的建立索引行为要求将文档装载在文本列中,尽管可以用其它方式 (包括文件系统和 url 形式)存储文档 (在”数据存储”选项进行设置)。默认情况下,系统应该将文档装载在文本列中。文本列可以是varchar2、clob、blob、char或bfile。注意,只有在将oracle7系统移植到oracle8的情况下才支持用long和long raw 这两个相反的列类型存储文本。不能为列类型nclob、date和number建立索引。
关于文档格式,因为系统能为包括html、pdf、microsoft word和纯文本在内的大多数文档格式建立索引,可以将其中的任何文档类型装载到文本列中(在”过滤器”选项中设置)。有关所支持的文档格式的详细信息,可以参阅oracle text users guide and reference 中的附录”supported filter formats”。
装载方法主要有以下几种:
(1)sql insert 语句
(2)ctxload 可执行文件
(3)sql*loader
(4)从 bfile 中装载 lob 的 dbms_lob.loadfromfile() pl/sql 过程
(5)oracle call interface
4 为文本建立索引
文本装入文本列后,就可以创建oracle text索引。文档以许多不同方案、格式和语言存储。因此,每个 oracle text 索引有许多需要设置的选项,以针对特定情况配置索引。创建索引时,oracle text可使用若干个默认值,但在大多数情况下要求用户通过指定首选项来配置索引。
每个索引的许多选项组成功能组,称为”类”,每个类集中体现配置的某一方面,可以认为这些类就是与文档数据库有关的一些问题。例如:数据存储、过滤器、词法分析器、相关词表、存储等。
每个类具有许多预定义的行为,称之为对象。每个对象是类问题可能具有的答案,并且大多数对象都包含有属性。通过属性来定制对象,从而使对索引的配置更加多变以适应于不同的应用。
(1)存储(storage)类
存储类指定构成oracle text索引的数据库表和索引的表空间参数和创建参数。它仅有一个基本对象:basic_storage,其属性包括:i_index_clause、i_table_clause、k_table_clause、n_table_clause、p_table_clause、r_table_clause。
(2)数据存储(datastore)类
数据存储:关于列中存储文本的位置和其他信息。默认情况下,文本直接存储到列中,表中的每行都表示一个单独的完整文档。其他数据存储位置包括存储在单独文件中或以其 url 标识的 web 页上。七个基本对象包括:default_datastore、detail_datastore、direct_datastore、file_datastore、multi_column_datastore 、url_datastore、user_datastore,。
(3)文档段组(section group)类
文档段组是用于指定一组文档段的对象。必须先定义文档段,然后才能使用索引通过 within 运算符在文档段内进行查询。文档段定义为文档段组的一部分。包含七个基本对象:auto_section_group、basic_section_group、html_section_group、news_section_group、null_section_group、xml_section_group、path_section_group。
(4)相关词表(wordlist)类
相关词表标识用于索引的词干和模糊匹配查询选项的语言,只有一个基本对象basic_wordlist,其属性有:fuzzy_match、fuzzy_numresults、fuzzy_score、stemmer、substring_index、wildcard_maxterms、prefix_index、prefix_max_length、prefix_min_length。
(5)索引集(index set)
索引集是一个或多个oracle 索引 (不是oracle text索引) 的集合,用于创建 ctxcat类型的oracle text索引,只有一个基本对象basic_index_set。
(6)词法分析器(lexer)类
词法分析器类标识文本使用的语言,还确定在文本中如何标识标记。默认的词法分析器是英语或其他西欧语言,用空格、标准标点和非字母数字字符标识标记,同时禁用大小写。包含8个基本对象:basic_lexer、chinese_lexer、chinese_vgram_lexer、japanese_lexer、japanese_vgram_lexer、korean_lexer、korean__morph_ lexer、multi_lexer。
(7)过滤器(filter)类
过滤器确定如何过滤文本以建立索引。可以使用过滤器对文字处理器处理的文档、格式化的文档、纯文本和 html 文档建立索引,包括5个基本对象:charset_filter、inso_filter inso、null_filter、procedure_filter、user_filter。
(8)非索引字表(stoplist)类
非索引字表类是用以指定一组不编入索引的单词 (称为非索引字)。有两个基本对象:basic_stoplist (一种语言中的所有非索引字) 、 multi_stoplist (包含多种语言中的非索引字的多语言非索引字表)。
5 查询
建立了索引,就可以使用 select 语句中的 contains 运算符发出文本查询。使用 contains 可以进行两种查询:单词查询和about查询。
5.1 词查询示例
词查询是对输入到 contains 运算符中单引号间的精确单词或短语的查询。在以下示例中,我们将查找文本列中包含 oracle 一词的所有文档。每行的分值由使用标签 1 的 score 运算符选定:
select score(1) title from news where contains(text, oracle, 1) > 0;
在查询表达式中,可以使用 and 和 or 等文本运算符来获取不同结果。还可以将结构性谓词添加到 where 子句中。可以使用 count(*)、ctx_query.count_hits 或 ctx_query.explain 来计算查询的命中 (匹配) 数目。
5.2 about查询示例
在所有语言中,about查询增加了某查询所返回的相关文档的数目。在英语中,about 查询可以使用索引的主题词组件,该组件在默认情况下创建。这样,运算符将根据查询的概念返回文档,而不是仅依据所指定的精确单词或短语。例如,以下查询将查找文本列中关于主题 politics 的所有文档,而不是仅包含 politics 一词的文档:
select score(1) title from news where contains(text, about(politics), 1) > 0;
6 显示满足查询条件的文档
通常,通过使用oracle text查询应用程序,用户可查看查询所返回的文档。用户从命中列表中选择一个文档,然后应用程序以某种形式显示该文档。通过oracle text,可以用不同的方式再现文档。例如,可以通过突出显示查询词来显示文档。突出显示的查询词可以是相关词查询中的词,也可以是英文 about 查询中的主题词。
以下是关于输出效果和用于每个输出效果的过程的信息:
突出显示的文档,纯文本格式版本(ctx_doc.markup)
突出显示的文档,html版本(ctx_doc.markup)
突出显示纯文本格式版本的偏移量信息(ctx_doc.highlight)
突出显示html 版本的偏移量信息(ctx_doc.highlight)
纯文本格式版本,无突出显示(ctx_doc.filter)
html版本文档,无突出显示(ctx_doc.filter)
7 索引维护
索引建好后,如果表中的数据发生变化,比如增加或修改了记录,怎么办?由于对表所发生的任何dml语句,都不会自动修改索引,因此,必须定时同步(sync)和优化(optimize)索引,以正确反映数据的变化。
在索引建好后,可以在该用户下查到oracle自动产生了以下几个表:(假设索引名为myindex):
dr$myindex$i,dr$myindex$k,dr$myindex$r,dr$myindex$n
其中以i表最重要,可以查询一下该表:
select token_text, token_count from dr$ myindex $i where rownum<=20;
查询结果在此省略。可以看到,该表中保存的其实就是oracle 分析你的文档后,生成的term记录在这里,包括term出现的位置、次数、hash值等。当文档的内容改变后,可以想见这个i表的内容也应该相应改变,才能保证oracle在做全文检索时正确检索到内容(因为所谓全文检索,其实核心就是查询这个表)。那么如何维护该表的内容,不能每次数据改变都重新建立索引,这就要用到sync 和 optimize了。
同步(sync):将新的term 保存到i表;
优化(optimize):清除i表的垃圾,主要是将已经被删除的term从i表删除。
oracle提供了一个所谓的ctx server来做这个同步和优化的工作,只需要在后台运行这个进程,它会监视数据的变化,及时进行同步。另外,也可以用以下的job来完成(该job要建在和表同一个用户下):
create or replace procedure sync
is
begin
execute immediate
alter index myindex rebuild online ||
parameters ( sync ) ;
execute immediate
alter index myindex rebuild online ||
parameters ( optimize full maxtime unlimited ) ;
end sync;
/
set serveroutput on
declare
v_job number;
begin
dbms_job.submit
(
job => v_job,
what => sync;,
next_date => sysdate, /* default */
interval => sysdate + 1/720 /* = 1 day / ( 24 hrs * 30 min) = 2 mins */
);
dbms_job.run ( v_job );
dbms_output.put_line ( submitted as job # || to_char ( v_job ) );
end;
/
job的sysdate + (1/720)是指每隔2分钟同步一次。具体的时间间隔,可以根据自己的应用的需要而定。
8 小结
文本对于各种规模的公司、机构组织来说,都是包含众多丰富信息的最有效载体,oracle text的推出,标志着oracle提供了一套崭新的技术,可以便捷安全的用于管理企业的文本信息。oracle text使应用程序开发者可以透明地将全文检索能力加入到基于sql的应用程序中,oracle text也是其他oracle产品的核心组件,比如oracle9ias portal,oracle ebusiness suite,oracle ultra search和oracle internet file system等。灵活运用oracle text提供的全文检索技术,就可以使自己的应用具备强大的全文检索能力。