扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
全文检索是一种将文件中所有文本与检索项匹配的文字资料检索方法。全文检索系统是按照全文检索理论建立起来的用于提供全文检索服务的软件系统。
创新互联公司长期为近千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为尚志企业提供专业的成都网站设计、成都网站制作,尚志网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。
判断检索效果的两个指标:
查全率=被检出相关信息量/相关信息总量(%)
查准率=被检出相关信息量/被检出信息总量(%)
Oracle全文检索配置方法:
1.检查数据库是否具有全文检索功能(这是针对已经建成使用的数据库)
查看用户中是否存在ctxsys用户,查询角色里是否存在ctxapp角色。以上两个中的1个不满足(不存在),则说明没有装过全文检索功能。
使用contains函数的时候,若没有全文检索则会报错的。
2.若没有,则需要手动建立,先建立全文检索要使用的空间
sqlplus / as sysdba --进入控制台
create tablespace Idx_ctxsys datafile '/oradata/sg186fx/ctxsys01.dbf size 10240M autoextend on next 32M maxsize 20480M;--创建全文检索使用的表空间
3.创建全文检索使用的用户和角色及相应的包,则需要执行oracle自带的一个脚本:cd $ORACLE_HOME/ctx/admin/catctx.sql
还是在sqlplus中执行:
@?/ctx/admin/catctx.sql ctxsys Idx_ctxsys temp nolock
在执行这个脚本的时候,输入了几个参数,第一个参数ctxsys为ctxsys用户的密码
第二个参数Idx_ctxsys为ctxsys用户要使用的表空间
第三个参数temp为ctxsys用户使用的临时表空间
第四个参数nolock为ctxsys用户处于解锁状态。
4.创建完成后,要登录ctxsys用户
connect ctxsys/ctxsys
执行以下脚本:@?/ctx/admin/defaults/drdefus.sql(这是个很重要的脚本,后面创建索引会使用该脚本创建的信息)
5.创建全文索引语法分析器
先要明确使用全文索引的用户,我要使用全文索引的是sgpm用户
因此
grant execute on ctxsys.ctx_ddl to sgpm with grant option;
connect sgpm/sgpm
设置语法分析器:
exec ctx_ddl.drop_preference('chinalexer');
exec ctx_ddl.create_preference('chinalexer','chinese_lexer');
设置词法属性:exec ctx_ddl.drop_preference('idx_c_store');
begin
ctx_ddl.create_preference('idx_c_store','BASIC_STORAGE');
ctx_ddl.set_attribut('idx_c_store','I_TABLE_CLAUSE','tablespaces Idx_ctxsy');
ctx_ddl.set_attribute('idx_c_store','I_INDEX_CLAUSE','tablespace Idx_ctxsy compress 2');
end;
/
6.创建索引
create index sgpm.idx_c_cons_name on sgpm.c_cons(cons_name) indextype is ctxsys.context parameters('lexer chinalexer storage idx_c_store');
7.同步索引
variable jobno number;
begin
dbms_job.submit(:jobno,'pkg_sp_tools.p_cont_sys_index();',sysdate,'trunc(sysdate)+19/24+1'); --执行的是个性化方法。
end;
/
普通的就是用:
exec ctx_ddl.sync_index('idx_c_cons_name');
到此,全文检索创建成功,contains函数就可以正常使用了。
注意:创建的过程中会出现ORA-29879:cannot create multiple domain index on a column listusing same indextype ,这说明在其他用户下已经建立了该索引。
不使用Oracle text功能,也有很多方法可以在Oracle数据库中搜索文本.可以使用标准的INSTR函数和LIKE操作符实现。
SELECT *FROM mytext WHERE INSTR (thetext, 'Oracle') 0;
SELECT * FROM mytext WHERE thetext LIKE '%Oracle%';
有很多时候,使用instr和like是很理想的, 特别是搜索仅跨越很小的表的时候.然而通过这些文本定位的方法将导致全表扫描,对资源来说消耗比较昂贵,而且实现的搜索功能也非常有限,因此对海量的文本 数据进行搜索时,建议使用oralce提供的全文检索功能 建立全文检索的步骤步骤一 检查和设置数据库角色首先检查数据库中是否有CTXSYS用户和CTXAPP脚色。如果没有这个用户和角色,意味着你的数据库 创建时未安装intermedia功能。你必须修改数据库以安装这项功能。 默认安装情况下,ctxsys用户是被锁定的,因此要先启用ctxsys的用 户。 步骤二 赋权 在ctxsys用户下把ctx_ddl的执行权限赋于要使用全文索引的用户,例:
grant execute on ctx_ddl to pomoho;
步骤三 设置词法分析器(lexer)
Oracle实现全文检索,其机制其实很简单。即通过Oracle专利的词法分析器(lexer),将文章中所有的表意单元(Oracle 称为 term)找出来,记录在一组 以dr$开头的表中,同时记下该term出现的位置、次数、hash 值等信息。检索时,Oracle 从这组表中查找相应的term,并计算其出现频率,根据某个算法来计算每个文档的得分(score),即所谓的‘匹配率’。而lexer则是该机制的核 心,它决定了全文检索的效率。Oracle 针对不同的语言提供了不同的 lexer, 而我们通常能用到其中的三个:
n basic_lexer: 针对英语。它能根据空格和标点来将英语单词从句子中分离,还能自动将一些出现频率过高已经失去检索意义的单词作为‘垃圾’处理,如if , is 等,具有较高的处理效率。但该lexer应用于汉语则有很多问题,由于它只认空格和标点,而汉语的一句话中通常不会有空格,因此,它会把整句话作为一个 term,事实上失去检索能力。以‘中国人民站起来了’这句话为例,basic_lexer 分析的结果只有一个term ,就是‘中国人民站起来了’。此时若检索‘中国’,将检索不到内容。
n chinese_vgram_lexer: 专门的汉语分析器,支持所有汉字字符集(ZHS16CGB231280 ZHS16GBK ZHT32EUC ZHT16BIG5 ZHT32TRIS ZHT16MSWIN950 ZHT16HKSCS UTF8 )。该分析器按字为单元来分析汉语句子。‘中国人民站起来了’这句话,会被它分析成如下几个term: ‘中’,‘中国’,‘国人’,‘人民’,‘民站’,‘站起’,起来’,‘来了’,‘了’。可以看出,这种分析方法,实现算法很简单,并且能实现‘一网打 尽’,但效率则是差强人意。
n chinese_lexer: 这是一个新的汉语分析器,只支持utf8字符集。上面已经看到,chinese vgram lexer这个分析器由于不认识常用的汉语词汇,因此分析的单元非常机械,像上面的‘民站’,‘站起’在汉语中根本不会单独出现,因此这种term是没有 意义的,反而影响效率。chinese_lexer的最大改进就是该分析器 能认识大部分常用汉语词汇,因此能更有效率地分析句子,像以上两个愚蠢的单元将不会再出现,极大 提高了效率。但是它只支持 utf8, 如果你的数据库是zhs16gbk字符集,则只能使用笨笨的那个Chinese vgram lexer.
如果不做任何设置,Oracle 缺省使用basic_lexer这个分析器。要指定使用哪一个lexer, 可以这样操作:
第一. 当前用户下下建立一个preference(例:在pomoho用户下执行以下语句)
exec ctx_ddl.create_preference ('my_lexer', 'chinese_vgram_lexer');
第二. 在建立全文索引索引时,指明所用的lexer:
CREATE INDEX myindex ON mytable(mycolumn) indextype is ctxsys.context
parameters('lexer my_lexer');
这样建立的全文检索索引,就会使用chinese_vgram_lexer作为分析器。
步骤四 建立索引
通过以下语法建立全文索引
CREATE INDEX [schema.]index on [schema.]table(column) INDEXTYPE IS ctxsys.context [ONLINE]
LOCAL [(PARTITION [partition] [PARAMETERS('paramstring')]
[, PARTITION [partition] [PARAMETERS('paramstring')]])]
[PARAMETERS(paramstring)] [PARALLEL n] [UNUSABLE];
例:
CREATE INDEX ctx_idx_menuname ON pubmenu(menuname)
indextype is ctxsys.context parameters('lexer my_lexer')
步骤五 使用索引
使用全文索引很简单,可以通过:
select * from pubmenu where contains(menuname,'上传图片')0
全文索引的种类
建立的Oracle Text索引被称为域索引(domain index),包括4种索引类型:
l CONTEXT
2 CTXCAT
3 CTXRULE
4 CTXXPATH
依据你的应用程序和文本数据类型你可以任意选择一种。
对多字段建立全文索引
很多时候需要从多个文本字段中查询满足条件的记录,这时就需要建立针对多个字段的全文索引,例如需要从pmhsubjects(专题表)的 subjectname(专题名称)和briefintro(简介)上进行全文检索,则需要按以下步骤进行操作:
Ø 建议多字段索引的preference
以ctxsys登录,并执行:
EXEC ctx_ddl.create_preference(' ctx_idx_subject_pref',
'MULTI_COLUMN_DATASTORE');
Ø 建立preference对应的字段值(以ctxsys登录)
EXEC ctx_ddl.set_attribute(' ctx_idx_subject_pref ','columns','subjectname,briefintro');
Ø 建立全文索引
CREATE INDEX ctx_idx_subject ON pmhsubjects(subjectname)
INDEXTYPE ISctxsys.CONTEXT PARAMETERS('DATASTORE ctxsys.ctx_idx_subject_pref lexer my_lexer')
Ø 使用索引
select * from pmhsubjects where contains(subjectname,'李宇春')0
全文索引的维护
对于CTXSYS.CONTEXT索引,当应用程序对基表进行DML操作后,对基表的索引维护是必须的。索引维护包括索引同步和索引优化。
在索引建好后,我们可以在该用户下查到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表删除。
当基表中的被索引文档发生insert、update、delete操作的时候,基表的改变并不能马上影响到索引上直到同步索引。可以查询视图 CTX_USER_PENDING查看相应的改动。例如:
SELECT pnd_index_name, pnd_rowid,
TO_CHAR (pnd_timestamp, 'dd-mon-yyyy hh24:mi:ss') timestamp
FROM ctx_user_pending;
该语句的输出类似如下:
PND_INDEX_NAME PND_ROWID TIMESTAMP
------------------------------ ------------------ --------------------
MYINDEX AAADXnAABAAAS3SAAC 06-oct-1999 15:56:50
同步和优化方法: 可以使用Oracle提供的ctx_ddl包同步和优化索引
一. 对于CTXCAT类型的索引来说, 当对基表进行DML操作的时候,Oracle自动维护索引。对文档的改变马上反映到索引中。CTXCAT是事务形的索引。
索引的同步
在对基表插入,修改,删除之后同步索引。推荐使用sync同步索引。语法:
ctx_ddl.sync_index(
idx_name IN VARCHAR2 DEFAULT NULL
memory IN VARCHAR2 DEFAULT NULL,
part_name IN VARCHAR2 DEFAULT NULL
parallel_degree IN NUMBER DEFAULT 1);
idx_name 索引名称
memory 指定同步索引需要的内存。默认是系统参数DEFAULT_INDEX_MEMORY 。
指定一个大的内存时候可以加快索引效率和查询速度,且索引有较少的碎片
part_name 同步哪个分区索引。
parallel_degree 并行同步索引。设置并行度。
例如:
同步索引myindex:Exec ctx_ddl.sync_index ('myindex');
实施建议:建议通过oracle的job对索引进行同步
索引的优化
经常的索引同步将会导致你的CONTEXT索引产生碎片。索引碎片严重的影响了查询的反应速度。你可以定期优化索引来减少碎片,减少索引大小,提高 查询效率。
当文本从表中删除的时候,Oracle Text标记删除的文档,但是并不马上修改索引。因此,就的文档信息占据了不必要的空间,导致了查询额外的开销。你必须以FULL模式优化索引,从索引中 删除无效的旧的信息。这个过程叫做垃圾处理。当你经常的对表文本数据进行更新,删除操作的时候,垃圾处理是很必要的。
exec ctx_ddl.optimize_index ('myidx', 'full');
实施建议:每天在系统空闲的时候对全 文索引进行相应的优化,以提高检索的效率
查询是数据的一个重要操作。用户发送查询请求,经编译软件变异成二进制文件供服务器查询,后返回查询结果集给用户,查询会产生一个虚拟表,看到的是表形式显示的结果,但结果并不真正的存储,每次执行查询只是从数据表中提取数据,并按照表的形式显示出来。
SELECT 列名
FGROM 表名
[WHERE 查询条件表达式]
[GROUP BY 分组表达式]
[HAVING 分组查询表达式]
[ORDER BY 排序的列名 [ASC或DESC]]
group by 用于对查询的结果分组统计,通过对group by后面的名字进行分组后输出结果。
group by后面还可以跟多列表示 多列分组 ,在多列分组时放前面的优先分组。
group by 列名,列名
having 子句用于限制分组显示结果,其只能和group by一起连用。在where中没有办法直接使用聚合函数,即sum avg等无法使用,所以引用了having,在having中可以使用这些函数。
order by 表示排序,后跟列名和排序方式。如果什么都不加默认为升序。ASC表示升序,DESC表示降序。
在Oracle中还可以设置多列排序
order by 列名1 升降,列名2 升降;
前面的为主要排序,后面的为次一级排序。
注:碰到自己与自己比较的情况下,不能用having,可以创建一个新列。
注:如果select语句同时包含group by,having,order by,按group by,having,order by排序
分组和聚合一起使用,目的是为了统计信息。
where是为了from服务的,只能跟 真实的字段 ,用来筛选from子句中指定的操作所产生的行
group by 用来分组where子句的输出
having 用来从分组的结果中筛选行
order by用来对筛选的结果进行排序
(1)分组函数:max min avg sum count
max表示该列的最大值,min表示该列的最小值,avg表示该列的平均值,sum表示该列的和,count表示该列的行数。
注:分组函数(max、min、avg、count、sum)只能出现在选择列表中having子句、order by子句、不能出现在where子句和group by子句中。
(2)多表查询
多表查询是指两个和两个以上的表或者是视图的查询,在实际应用中,当查询单个表不能满足需求时,一般使用多表查询。如:显示sales部门位置和其员工的姓名,这种情况下需要使用到(dept表和emp表)。
多表查询的连接一般可以分为:内连接、左外连接、右外连接、全连接。
注:在使用多表查询的时候每个表可以设置别名,如果表指定了别名,那么语句中所有语句必须使用别名,而不能再使用实际表名。且在写属性的时候如果属性为其中一个表特有的属性则不需要写别名,如果是两个表都有则必须指定是哪一个表的哪个属性格式为:表名.属性名。
select 列名 from 表1 别名,表2 别名...
注:e是emp的别名,d是dept的别名。
但如果对表进行了操作则需要设置别名,如:查询每个部门中工资高于该部门平均工资的员工人数。在其中有一个avg表,这个表必须设置别名(提醒:如果仅有一个被修改的表,则可以不设置别名,但如果有多个表则必须设置别名)。
内连接
内连接通过使用比较运算符来使每个表的通用列中的值匹配来组成一个新表,即:把两个表中间共有的那些行拿出来进行连接,如果某些行不是两个表共有的,则不进行连接。
select
from 表1
inner join 表2
on 匹配条件
或
select
from 表1 表2
where匹配条件
左外连接
左外连接与内连接的区别是:设置左外连接的时候设置了主表和附表,主表在前,附表在后。内连接是将两个表匹配的地方输出出来,而左外连接则是主表全写,附表一一对应,附表有则加上,没有不写。
select
from 表1
left join 表2
on 匹配条件
右外连接
右外连接和左外连接基本相同只是右外连接的主表写在后边。
select
from 表1
right join 表2
on 匹配条件
全连接
全连接是在等值连接的基础上将左表和右表的未匹配数据都加上,使用的关键字为full outer join或者full join。
select
from 表1
full join 表2
on 匹配条件
自连接
还有一种特殊情况即自连接,在Oracle中一个表无法与自己进行比较,所以当需要自己表的两个信息做比较的时候也需要使用连接来连接,即同一张表的连结查询。
(3)子查询
子查询是指嵌套在其他sql语句中的select语句,也叫嵌套查询。sql语句执行顺序为从右到左执行,所以在执行查询时会先执行左侧的子查询后进行主查询。
子查询分为单行子查询和多行子查询,单行子查询是指返回一行数据的子查询语句,多行子查询是指返回多行数据的查询语句。子查询还可以分为多列子查询、多行子查询、多列多行子查询。
在进行子查询时如果内部查询不返回任何记录,则外部条件中字段DEPTNO与NULL比较永远为假,也就是说外部查询不返回任何结果。
总结为:
单行子查询是指子查询只返回单列、单行数据
多行子查询是指返回单列多行数据,都是针对单列而言的
多列子查询则是指查询返回多个列数据的子查询语句
单行子查询
where deptno = (单行数值)
多行子查询
where deptno in ( 多行数值 )
多列子查询:
where (job,deptno)=(select job,deptno from emp where ename='KING')
多列多行子查询
where (job,deptno) in (select job,deptno from emp where ename='KING')
单行子查询
在单行子查询的外部查询中可以使用=、、、=、=、等比较运算符。
内部查询返回的结果必须与外部查询条件中字段(DEPTNO)相匹配。
多行子查询
在WHERE子句中使用多行子查询时,可以使用多行比较运算符(IN,ALL,ANY)。
IN:等于任何一个。
ALL:和子查询返回的所有值比较。例如:salALL(1,2,3)等价于sal3,即大于所有。
ANY:和子查询返回的任意一个值比较。例如:salANY(1,2,3)等价于sal1,即大于任意一个就可以。
注:ANY运算符必须与单行比较运算符结合使用,并且返回行只要匹配子查询的任何一个结果即可。
多列子查询
多列子查询和多行子查询相同,只是使用多列子查询的时候会有多列进行匹配。
(4)集合运算
为了合并多个select语句的结果,可以使用集合操作符号union,union all,intersect,minus。
union:该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行
union all:该操作与union相似,但是它不会取消重复行,而且不会排序
intersect:使用该操作符用于取得两个结果集的交集
minus:使用该操作符用于取得两个结果集的差集,它只会显示存在第一个集合中,而不存在第二个集合中的数据
总结为集合运算就是将两个或者多个结果集组合成一个结果集。
intersect 交集 返回两个查询共有的记录
union all 并集 返回各个查询的所有记录,包括重复的记录
union 交集 返回各个查询的所有记录,不包括重复的记录
MINUS 补集 返回第一个查询检查出的记录减去第二个查询检索出来的记录之后剩余的记录
注意:当使用集合操作的时候,查询所返回的列数以及列的类型必须匹配,列名可以不同。
(1)Distinct关键字
在Oracle中,可能出现若干相同的情况,那么可以用Distinct消除重复行
(2)多表查询与单行子查询可以实现相同的功能
查询出销售部(sales)下面的员工姓名,工作,工资
(3)显示高于自己部门平均工资的员工信息
分析:
1.找到所有部门的平均工资
select deptno,avg(sal) from emp group by deptno;
2.找到所有人的工资信息
select ename,sal,deptno from emp;
3.把两个结果集使用多表连接组合组合起来
select * from emp,(select deptno,avg(sal) avgsal from emp group by deptno) damao where emp.deptno=damao.deptno;
4.去掉低于平均工资的那些数据即可:
select * from emp,(select deptno,avg(sal) avgsal from emp group by deptno) damao where emp.deptno=damao.deptno and salavgsal;
(4)emp表介绍
字段 类型 描述
empno NUMBER(4) 表示雇员编号,是唯一编号
ename VAECHAR2(10) 表示雇员姓名
job VARCHAR2(9) 表示工作职位
mgr NUMBER(4) 表示一个雇员的领导编号
hiredate DATE 表示雇佣日期
sal NUMBER(7,2) 表示月薪,工资
comm NUMBER(7,2) 表示奖金,或者称为佣金
deptno NUMBER(2) 部门编号
同时查询2张表数据有很多种方法(下面的a,b为表名,A,B为表的别名):
1,select A.*,B.* from a A,b B;
这样查出来的是a的所有数据在前面几列,b的数据在后面几列。
2,select * from a cross join a
这样查出来的数据是2张表的笛卡尔积。
即a的数据量乘以b的数据量的积
3,如果两张表拥有相同的字段,你可以使用left join或者right join
select * from table1 left join table2 on table1.id=table2.id
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流