一、历史背景
Oracle数据库的全文检索技术已经非常完美,Oracle Text使Oracle9i具备了强大的文本检索能力和智能化的文本管理能力。Oracle Text是Oracle9i采用的新名称,在Oracle8/8i中它被称作Oracle interMedia Text,在Oracle8以前它的名称是Oracle ConText Cartridge。
二、Oracle Text 索引文档时所使用的主要逻辑步骤如下 :
(1) 数据存储逻辑搜索表的所有行,并读取列中的数据。通常,这只是列数据,但有些数据存储使用列数据作为文档数据的指针。
(2) 过滤器提取文档数据并将其转换为文本表示方式。存储二进制文档 (如 Word 或 Acrobat 文件) 时需要这样做。过滤器的输出不必是纯文本格式 — 它可以是 XML 或 HTML 之类的文本格式。
(3) 分段器提取过滤器的输出信息,并将其转换为纯文本。包括 XML 和 HTML 在内的不同文本格式有不同的分段器。转换为纯文本涉及检测重要文档段标记、移去不可见的信息和文本重新格式化。
(4) 词法分析器提取分段器中的纯文本,并将其拆分为不连续的标记。既存在空白字符分隔语言使用的词法分析器,也存在分段复杂的亚洲语言使用的专门词法分析器。
(5) 索引引擎提取词法分析器中的所有标记、文档段在分段器中的偏移量以及被称为非索引字的低信息含量字列表,并构建反向索引。倒排索引存储标记和含有这些标记的文档。
三、需要的权限
要使用Oracle Text,必须具有CTXAPP角色或者是CTXSYS用户。Oracle Text为系统管理员提供CTXSYS用户,为应用程序开发人员提供CTXAPP角色。具有CTXAPP角色的用户可执行以下任务:创建索引,管理 Oracle Text 数据字典,包括创建和删除首选项,进行Oracle Text 查询,使用 Oracle Text PL/sql程序包。
如图所示:
四、具体的实现
文本装入文本列后,就可以创建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 (包含多种语言中的非索引字的多语言非索引字表)。
具体操作实践
1、 创建词法分析器及相关词表
Begin |
2、 在需要创建全文索引的表中创建索引(索引类型必须是 ctxsys.context,即应用上下文索引)
create index idx_person_desc on personinfo(persondesc) |
3、进行全文索引的同步
exec ctx_ddl.sync_index('idx_user_info', '20M'); |
具体理解
Oracle实现全文检索,其机制其实很简单。即通过Oracle专利的词法分析器(lexer),将文章中所有的表意单元(Oracle 称为 term,此处我理解为单词或者一些有意义的词语) 找出来,记录在一组以 dr$开头的表中,同时记下该term出现的位置、次数、hash 值等信息。检索时,Oracle 从这组表中查找相应的 term,并计算其出现频率,根据某个算法来计算每个文档的得分(score),即所谓的‘匹配率’。而lexer则是该机制的核心,它决定了全文检索的效率。Oracle 针对不同的语言提供了不同的 lexer, 而我们通常能用到其中的三个:
basic_lexer: 针对英语。它能根据空格和标点来将英语单词从句子中分离,还能自动将一些出现频率过高已经失去检索意义的单词作为‘垃圾’处理,如if , is 等,具有较高的处理效率。但该lexer应用于汉语则有很多问题,由于它只认空格和标点,而汉语的一句话中通常不会有空格,因此,它会把整句话作为一个term,事实上失去检索能力。以‘中国人民站起来了’这句话为例,basic_lexer 分析的结果只有一个term ,就是‘中国人民站起来了’。此时若检索‘中国’,将检索不到内容。
chinese_vgram_lexer: 专门的汉语分析器,支持所有汉字字符集。该分析器按字为单元来分析汉语句子。‘中国人民站起来了’这句话,会被它分析成如下几个term: ‘中’,‘中国’,‘国人’,‘人民’,‘民站’,‘站起’,起来’,‘来了’,‘了’。可以看出,这种分析方法,实现算法很简单,并且能实现‘一网打尽’,但效率则是差强人意。
chinese_lexer: 这是一个新的汉语分析器,只支持utf8字符集。上面已经看到,chinese vgram lexer这个分析器由于不认识常用的汉语词汇,因此分析的单元非常机械,像上面的‘民站’,‘站起’在汉语中根本不会单独出现,因此这种term是没有意义的,反而影响效率。chinese_lexer的最大改进就是该分析器能认识大部分常用汉语词汇,因此能更有效率地分析句子,像以上两个愚蠢的单元将不会再出现,极大提高了效率。但是它只支持 utf8, 如果你的数据库是zhs16gbk字符集,则只能使用笨笨的那个Chinese vgram lexer。
以上的说法是针对于Oracle8i或者是更低级版本的,在Oracle 9.2中采用 Chinese_lexer 分析器测试是没有这个问题的。
如果不做任何设置,Oracle 缺省使用basic_lexer这个分析器。要指定使用哪一个lexer, 可以这样操作:
第一,在ctxsys用户下建立一个preference:
ctx_ddl.create_preference('cnlex','CHINESE_LEXER'); |
第二,在建立intermedia索引时,指明所用的lexer:
create index idx_person_desc on personinfo(persondesc) |
这样建立的全文检索索引,就会使用CHINESE_LEXER作为分析器。
使用job定时同步和优化
在intermedia索引建好后,如果表中的数据发生变化,比如增加或修改了记录,怎么办?由于对表所发生的任何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$I_RSK1$I where rownum<=20; |
可以看到,该表中保存的其实就是Oracle 分析你的文档后,生成的term记录在这里,包括term出现的位置、次数、hash值等。当文档的内容改变后,可以想见这个I表的内容也应该相应改变,才能保证Oracle在做全文检索时正确检索到内容(因为所谓全文检索,其实核心就是查询这个表)。那么如何维护该表的内容呢?总不能每次数据改变都重新建立索引吧!这就用到sync 和 optimize了。
同步(sync):将新的term 保存到I表。
优化(optimize):清除I表的垃圾,主要是将已经被删除的term从I表删除。
检查全文索引是否创建成功
1、检查DR$myindex$I是否存在,其中的 myindex 代表建立的索引名称;
2、检查全文索引是否创建成功,最好采用 Contains来检查,具体的语法为
Contains(ColumnName,SearcherKey) > 0 |
列如,按上面创建的全文索引,可以使用如下的语句:
Select * From PERSONINFO Where Containts(PERSONDESC, 'abcd',1) > 0 |
如果你创建的全文索引不成功,则返回失败,其内容为:
ORA-20000: Oracle Text error: DRG-10599: 列没有编制索引
当然,如果你创建成功,则会正确返回数据。还有一个检查全文索引是否创建成功的方法是感觉创建全文索引后的查询速度。
测试数据
下面是对一个表进行操作时,在同一台机器中获得的测试数据。
PersonInfo表中共有 182263 条记录,其中persondesc不为null的记录数为180187 条记录,
其中,persondesc 包括 “大学”两个汉字的记录数为 21579 条记录
persondesc 包括 “1999”两个汉字的记录数为 10889条记录
测试一 、直接用like 来查询中文“大学”
SQL: Select count(*) From personinfo Where persondesc like '%大学%' |
时间开销:耗时 40秒 688 毫秒
测试二 、直接用like 来查询英文“1999”
SQL: Select count(*) From personinfo Where persondesc like '%1999%' |
时间开销:耗时 47秒 218毫秒
测试三 、未创建全文索引时,直接用dbms_lob.instr 来查询中文“大学”
SQL: Select count(*) From personinfo Where dbms_lob.instr(persondesc,'大学',1,1)>0 |
时间开销:耗时 47秒 031毫秒
测试四 、未创建全文索引时,直接用dbms_lob.instr 来查询英文“1999”
SQL: Select count(*) From personinfo Where dbms_lob.instr(persondesc,'1999',1,1)>0 |
时间开销:耗时 44秒 360毫秒
测试五 、未创建全文索引时,直接用Contains 来查询中文“大学”
SQL: Select count(*) From personinfo Where Contains(persondesc,'大学',1)>0"; |
执行失败: ORA-20000: Oracle Text error: DRG-10599: 列没有编制索引
测试六 、未创建全文索引时,直接用Contains 来查询英文“1999”
SQL: Select count(*) From personinfo Where Contains(persondesc,'1999',1)>0"; |
执行失败: ORA-20000: Oracle Text error: DRG-10599: 列没有编制索引
测试七 、采用CHINESE_LEXER词法分析器创建全文索引后,直接用Contains 来查询英文“1999”
SQL: Select count(*) From personinfo Where Contains(persondesc,'1999',1)>0"; |
时间开销:第一次查询耗时 469毫秒,后面的多次查询耗时 210毫秒左右
查询出来的记录数比在未建立索引时用like、dbms_lob.instr方式查询出来的记录数要少一些
测试八 、采用CHINESE_LEXER词法分析器创建全文索引后,直接用Contains 来查询中文“大学”
SQL: Select count(*) From personinfo Where Contains(persondesc,'大学',1)>0"; |
时间开销:第一次查询耗时 9秒359毫秒,后面的多次查询耗时 210毫秒左右
***查询出来的记录数比在未建立索引时用like、dbms_lob.instr方式查询出来的记录数要少一些
测试九 、采用CHINESE_LEXER词法分析器创建全文索引后,用dbms_lob.instr 来查询中文“大学”
SQL: Select count(*) From personinfo Where dbms_lob.instr(persondesc,'大学',1,1)>0 |
时间开销:耗时 54秒 953毫秒
测试十 、采用CHINESE_LEXER词法分析器创建全文索引后,直接用dbms_lob.instr 来查询英文“1999”
SQL: Select count(*) From personinfo Where dbms_lob.instr(persondesc,'1999',1,1)>0 |
时间开销:耗时 52秒 652毫秒
总体感觉Oracle的中文全文索引不是很好。后续版本或许会有所改进吧。
【编辑推荐】
详解Oracle DELETE和TRUNCATE 的区别
展开全部语法delete from aa truncate table aa 区别 from后面可以写条件,truncate不可以。 from记录是一条条删的,所删除的每行记录都会进日志,而truncate一次性删掉整个页,因此日至里面只记录页释放,简言之,delete from更新日志,truncate基本不,所用的事务日志空间较少。 from删空表后,会保留一个空的页,truncate在表中不会留有任何页。 4.当使用行锁执行 DELETE 语句时,将锁定表中各行以便删除。 truncate始终锁定表和页,而不是锁定各行。 5.如果有identity产生的自增id列,delete from后仍然从上次的数开始增加,即种子不变,而truncate后,种子会恢复初始。 不会触发delete的触发器,因为truncate操作不记录各个行删除。 总结和 delete只删除数据不删除表的结构(定义) drop语句将删除表的结构被依赖的约束(constrain),触发器(trigger),索引(index); 依赖于该表的存储过程/函数将保留,但是变为invalid状态。 语句是dml,这个操作会放到rollback segement中,事务提交之后才生效;如果有相应的trigger,执行的时候将被触发truncate,drop是ddl, 操作立即生效,原数据不放到rollback segment中,不能回滚. 操作不触发trigger。 语句不影响表所占用的extent, 高水线(high watermark)保持原位置不动 显然drop语句将表所占用的空间全部释放 truncate 语句缺省情况下见空间释放到 minextents个 extent,除非使用reuse storage; truncate会将高水线复位(回到最开始)。 4.速度,一般来说: drop> truncate > delete。 5.安全性:小心使用drop 和truncate,尤其没有备份的时候.否则哭都来不及。 6.使用上,想删除部分数据行用delete,注意带上where子句. 回滚段要足够大. 想删除表,当然用drop 想保留表而将所有数据删除. 如果和事务无关,用truncate即可. 如果和事务有关,或者想触发trigger,还是用delete如果是整理表内部的碎片,可以用truncate跟上reuse stroage,再重新导入/插入数据。
什么是标书目录样式?
标书目录一样均是招标文件里有提供的。 做标的话就按照那个目录做并且排序。 例如以下:
第8节 【投标文件】经济标格式工程量清单计价格式
1、投标总价;
2、总说明;
3、工程项目投标报价汇总表;
4、单项工程投标报价汇总表;
5、分部分项工程量清单计价表;
6、分部分项工程量清单综合单价分析表;
7、措施项目清单计价表(一);
8、措施项目清单计价表(二);
9、其他项目清单计价表汇总表;
10、规费、税金项目清单与计价表。
怎么样制作目录
目录的制作目录是用来列出文档中的各级标题及标题在文档中相对应的页码。 首先介绍Word的一个概念:大纲级别。 Word使用层次结构来组织文档,大纲级别就是段落所处层次的级别编号,Word提供9级大纲级别,对一般的文档来说足够使用了。 Word的目录提取是基于大纲级别和段落样式的,在Normal模板中已经提供了内置的标题样式,命名为“标题1”、“标题2”,…,“标题9”,分别对应大纲级别的1-9。 我们也可以不使用内置的标题样式而采用自定义样式,但有点麻烦。 下文中的目录制作方法直接使用Word的内置标题样式,关于自定义样式的方法请参阅Word的帮助文档。 目录的制作分三步进行。 1)修改标题样式的格式。 通常Word内置的标题样式不符合论文格式要求,需要手动修改。 在菜单栏上点“格式|样式”,列表下拉框中选“所有样式”,点击相应的标题样式,然后点“更改”。 可修改的内容包括字体、段落、制表位和编号等,按论文格式的要求分别修改标题1-3的格式。 2)在各个章节的标题段落应用相应的格式。 章的标题使用“标题1”样式,节标题使用“标题2”,第三层次标题使用“标题3”。 使用样式来设置标题的格式还有一个优点,就是更改标题的格式非常方便。 假如要把所有一级标题的字号改为小三,只需更改“标题1”样式的格式设置,然后自动更新,所有章的标题字号都变为小三号,不用手工去一一修改,即麻烦又容易出错。 关于如何应用样式和自动更新样式,请参考Word帮助。 3)提取目录。 按论文格式要求,目录放在正文的前面。 在正文前插入一新页(在第一章的标题前插入一个分页符),光标移到新页的开始,添加“目录”二字,并设置好格式。 新起一段落,菜单栏选“插入|索引和目录”,点“目录”选项卡,“显示级别”为3级,其他不用改,确定后Word就自动生成目录。 若有章节标题不在目录中,肯定是没有使用标题样式或使用不当,不是Word的目录生成有问题,请去相应章节检查。 此后若章节标题改变,或页码发生变化,只需更新目录即可。 注:目录生成后有时目录文字会有灰色的底纹,这是Word的域底纹,打印时是不会打印出来的(如果你愿意浪费一张纸可以试着打印一下目录)。 在“工具|选项”的“视图”选项卡可以设置域底纹的显示方式。 ²
发表评论