在mysql中进行搜索

版本:mysql 5.5

本文在很大程度上参考了《MySQL必知必会》,所有代码都经过了测试。

一、创建数据库与数据准备

1、创建数据库

-- 创建数据库(这种注释"--"后要有空格) 
/* 
数据库名称:db_search 
使用字符集:utf-8 
*/  
create database db_search DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;  
 
#使用数据库 
show databases; 
use db_search ; 
 
-- 为该数据库创建用户并相关赋予权限 
/* 
用户名:db_search_user 
密码:db_search_passwd 
*/  
grant  insert,update,delete,select on db_search.* to db_search_user@localhost  identified by "db_search_passwd";



2、创建表t_test,并插入数据

-- 创建表t_test 
create table t_test ( 
    id int auto_increment not null primary key comment '自增id', 
    content text not null comment '内容' 
)  comment='测试表' ; 
 
-- 在t_test中插入数据 
insert into t_test(content) 
values 
("Have you ever sat very silently, not with your attention fixed on anything, not making an 
effort to concentrate, but with the mind very quiet, really still? Then you hear everything, 
don’t you? You hear the far off noises as well as those that are nearer and those that are 
very close by, the immediate sounds—which means really that you are listening to 
everything. Your mind is not confined to one narrow little channel. If you can listen in 
this way, listen with ease, without strain, you will find an extraordinary change taking 
place within you, a change which comes without your volition, without your asking; and 
in that change there is great beauty and depth of insight." ), 
("How do you listen? Do you listen with your projections, through your projection, through 
your ambitions, desires, fears, anxieties, through hearing only what you want to hear, 
only what will be satisfactory, what will gratify, what will give comfort, what will for the 
moment alleviate your suffering? " ), 
("Listening is an art not easily come by, but in it there is beauty and great understanding."),  
("You may superficially agree when you hear it said that nationalism, with all its 
emotionalism and vested interest, leads to exploitation and the setting of man against 
man; but to really free your mind from the pettiness of nationalism is another matter."),  
("GUI(Graphical User Interface,图形用户界面)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受。" ), 
("Qt是一个跨平台应用和用户界面开发框架,它包括一个跨平台类库、集成开发工具和跨平台IDE。通过使用Qt,你可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。 "), 
("FLTK(The Fast Light Toolkit),一个轻量级的GUI开发库。FLTK除了具有基本的GUI功能之外,还拥有其他一些特性,如跨平台、内置OpenGL、速度更快、尺寸 更小、协议宽松等。FLTK可以在UNIX/Linux、Windows和Mac OS X平台上运行。" ), 
("wxWidgets是一个C++库,帮助开发人员创建可运行于32位、64位的Windows、Mac OS X、Linux和UNIX上的应用程序,也可以用来创建移动平台上的应用程序,包括Windows Mobile、iPhone SDK和嵌入式GTK+等。 " );



3、其他

-- 显示所有数据 
select * from t_test; 
 
-- 查看版本 
select version (); 
 
-- 查看所有用户 
use mysql ; 
select * from user; 
 
-- 查看某一用户具有的权限 
show grants for db_search_user@localhost ; 
 
-- 查看表信息 
use db_search ; 
describe t_test ;  #表结构 
Show create table t_test; #显示表的创建语句 
show table status like "t_test" ;  #表的详细信息 
 
-- 关于存储引擎 
show engines;  #支持的存储引擎



二、使用通配符和like

通过通配符进行查询和搜索,但是速度上比一般的查询要慢。通过配置可以规定搜索时候是否区分大小写。注意,like针对的是整个列。
“%”表示任意字符出现任意次数。下划线只匹配单个字符,而且就一个字符。
示例:
select content from t_test where content like 'have%';      #开始是“Have”   
select content from t_test where content like '%Have%';     #含有“Have”   
select content from t_test where content like '%listen%';   #含有“listen”   
select content from t_test where content like '%用户界面%';  #含有“用户界面”   
select content from t_test where content like 'GUI%用户界面%。' ; #"GUI"开头,内含“用户界面”,以“。”结尾   
select content from t_test where content like '%';    #查看所有但是不包括 null   
select content from t_test where content like '%listen%' or content like '%用户界面%' ;  #含有“listen”或者“用户界面”   

select content from t_test where content like "_ave%"; 
select content from t_test where content like "%易于接__" ;   #汉字也是一个字符



三、使用正则表达式

1、基础

REGEXP是在列值内进行匹配,并非匹配整个列。
示例:
select content from t_test where content regexp "易于接受";   #含有“易于接受” 
select content from t_test where content regexp "易于接受|listen";  #含有“易于接受”或者“listen” 
select content from t_test where content regexp "you [hear|listen|ever]";   #含有"you hear"或者“you listen”或者“you ever” 
select content from t_test where content not regexp "How do you listen";  #不含“How do you listen” 
select content from t_test where content regexp "[a-z]ow do you listen";  #[a-z ]指a至z的任意一个字符



.匹配任意字符。
查找特殊字符时候必须带有前缀“\\”,例如“\\-”查找“-”,“\\.”查找“.”,“\\f”查找换页符,“\\n”查找换行符号,“\\r”查 找回车符,“\\t”查找制表符,“\\\”查找反斜杠...之所以使用两个“\\”,是因为mysql自己解释一个,正则表达式库自己解释一个。
在括号表达式中(使用[和]),[:character_class:]表示与术语类的所有字符匹配的字符类。标准的类名称是:
alnum
文字数字字符
alpha
文字字符
blank
空白字符
cntrl
控制字符
digit
数字字符
graph
图形字符
lower
小写文字字符
print
图形或空格字符
punct
标点字符
space
空格、制表符、新行、和回车
upper
大写文字字符
xdigit
十六进制数字字符
 
例如:
select content from t_test where content regexp '[[:alnum:]]+';



“|”起到or的作用。
[123]与[1|2|3]作用相同,都是匹配1或2或3。
[^123]匹配除了1、2、3之外的任何字符。
[1-9]表示匹配1到9任一数字。
[a-z]表示匹配a到z任一字母。

2、多次重复匹配

是对匹配的次数进行控制。
*0个或者多个匹配+1个或者多个匹配?0个或者1个匹配{n}n次匹配{n,}不少于n次匹配{n,m}n~m次匹配(m>255) 
示例1:
“\\([0-9] sticks?\\)”表示匹配被扩号包含的第一个字符是0~9中任一数字,空格后为stick或sticks,“?”作用于“s”。
示例2:
“[[:digit:]]{4}”匹配4个相邻的数字。等于“[0-9][0-9][0-9][0-9]”。

 

3、在确定位置进行匹配

^文本开始$文本结尾[[:<:]]单词开头[[:>:]]单词结尾例如“^[0-9\\.]”表示匹配以0-9任一数字或者“.”开始的文本。

四、关于存储引擎

什么是存储引擎?
存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。 在Oracle 和SQL Server等数据库中只有一种存储引擎,所有数据存储管理机制都是一样的。而MySql数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据自己的需要编写自己的存储引擎。  
 mysql中有哪些存储引擎? 
from http://kb.cnblogs.com/page/99810/ 1. MyISAM:   这种引擎是mysql最早提供的。这种引擎又可以分为静态MyISAM、动态MyISAM和压缩MyISAM三种:   静态MyISAM:如果数据表中的各数据列的长度都是预先固定好的,服务器将自动选择这种表类型。因为数据表中每一条记录所占用的空间都是一样的,所以这种表存取和更新的效率非常高。当数据受损时,恢复工作也比较容易做。   动态MyISAM:如果数据表中出现varchar、xxxtext或xxxBLOB字段时,服务器将自动选择这种表类型。相对于静态MyISAM,这种表存储空间比较小,但由于每条记录的长度不一,所以多次修改数据后,数据表中的数据就可能离散的存储在内存中,进而导致执行效率下降。同时,内存中也可能会出现很多碎片。因此,这种类型的表要经常用optimize table 命令或优化工具来进行碎片整理。   压缩MyISAM:以上说到的两种类型的表都可以用myisamchk工具压缩。这种类型的表进一步减小了占用的存储,但是这种表压缩之后不能再被修改。另外,因为是压缩数据,所以这种表在读取的时候要先时行解压缩。 但是,不管是何种MyISAM表,目前它都不支持事务,行级锁和外键约束的功能。   2. MyISAM Merge引擎:这种类型是MyISAM类型的一种变种。合并表是将几个相同的MyISAM表合并为一个虚表。常应用于日志和数据仓库。   3. InnoDB:InnoDB表类型可以看作是对MyISAM的进一步更新产品,它提供了事务、行级锁机制和外键约束的功能。   4. memory(heap):这种类型的数据表只存在于内存中。它使用散列索引,所以数据的存取速度非常快。因为是存在于内存中,所以这种类型常应用于临时表中。   5. archive:这种类型只支持select 和 insert语句,而且不支持索引。常应用于日志记录和聚合分析方面。 当然MySql支持的表类型不止上面几种。

五、全文本搜索

默认的InnoDB并不支持全文搜索,MyISAM支持。使用全文搜索时候,mysql会为指定列的各个词建立索引,进行查询时候会根据文本匹配的良好程度对查询结果进行排序。
MySQL中的全文索引类型FULLTEXT的索引。FULLTEXT 索引仅可用于 MyISAM 表;他们可以从CHAR、 VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或 CREATE INDEX被添加。对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引, 其速度比把资料输入现有FULLTEXT索引的速度更为快。

1、创建使用 MyISAM的表

-- 修改索引 
alter table t_test engine =  MyISAM; 
-- 或者 
drop table t_test; 
create table t_test ( 
    id int auto_increment not null primary key comment '自增id', 
    content text not null comment '内容' 
)  comment='测试表' engine=MyISAM ;



2、添加fulltext索引

-- fulltext 
alter table t_test add fulltext(content ); 
-- 或者 
drop table t_test; 
create table t_test ( 
    id int auto_increment not null primary key comment '自增id', 
    content text not null comment '内容', 
    fulltext (content) 
)  comment='测试表' engine=MyISAM ; 
 
-- 查看索引 
 show indexes from t_test;



 3、基本查询

   使用match()和agaist(),其中match()参数必须是被fulltext索引的所有列名(多个之间用“,”分开)且列名顺序必须和创建索 引时候的一样,against()的参数是要查询的内容。这两个函数会根据搜索内容以及索引对表中相应的列的每一行分等级。等级是根据杭中词的书目、唯一 词的数目、整个索引中词的总数以及包含该词的行的数目计算出来。一般不含搜索词的行等级为0,文本中词考前的行的等级比靠后的等级高。
select * from t_test where Match(content ) Against('but');     #无结果 
select * from t_test where Match(content ) Against('GUI');     #无结果 
select * from t_test where Match(content ) Against('listen');    #有结果 
select * from t_test where Match(content ) Against('用户界面' );  #无结果 
select * from t_test where Match(content ) Against('sounds—which' ); #有结果  
select * from t_test where Match(content ) Against('sounds—which listen' ); #有结果



4、使用查询扩展

    能够找出与搜索词相关的其他行,例如行1含有搜索词,行2没有搜索词,但是行1和行2内容很接近(例如%80的单词相同,又例如两者等级最高的几个词相同),则行2也会显示出来。
select * from t_test where Match(content ) Against('sounds—which' with query expansion); #有结果



 5、布尔查询

    通过布尔表达式指定要匹配的词、不需要匹配的词、指定定词之间的等级高低等并以此影响查询结果。
例如:
select * from t_test where Match(content ) Against('sounds—which'   in boolean mode ); 
select * from t_test where Match(content ) Against('sounds—which' );



 第一个是布尔查询,其实两个语句结果相同、作用一样、但是行为并非相同。
又例如:
select * from t_test where Match(content ) Against('attention');  
select * from t_test where Match(content ) Against('listen'); 
select * from t_test where Match(content ) Against('listen  -attention' in  boolean mode );



第三个查询语句用到了布尔表达式,表示匹配listen、排除attention,比较三个语句的结果即可看出该布尔查询的作用,结果是第二个查询的结果与第一个的差集。
以下是相关的布尔操作符号:
+词必须存在-词必须不存在>包含,且增加等级值<包含,且减少等级值()子表达式~取消一个词的等级值*词尾的通配符""定义一个短语,可以对这个短语进行包含、排除等操作例如:
'+listen  +attention' in  boolean mode 表示必须包含listen和attention
'listen  attention' in  boolean mode 表示listen和attention至少要有一个
'"listen  attention"' in  boolean mode 表示包含短语"listen attention"而不是两个单独的单词
'>listen  <attention"' in  boolean mode 表示匹配这两个单词,且listen增加等级值,attention减少等级值
'+listen  +(<attention)' in  boolean mode 表示匹配listen和attention且减少attention的等级值得
'+liste*' in  boolean mode 表示包含以liste开头的单词

6、使用说明

* 短的单词(3个或以下的字符)一般被忽略并从索引中排除,可以修改这个配置;
* mysql自带一个非用词(stopword,例如in,but...)列表,非用词在索引全文本数据时会被忽略,不过可以覆盖更改这个列表;
*有些词的出现频率太高,则没有搜索的价值,在boolean mode中若一个词汇出现在%50以上的行中则将其作为非用词忽略;
* 若表中行数少于3,返回结果(每个词或者不出现、或者出现在50%的行中);
* 单词中的单引号会被忽略,例如don't-->dont;
* 汉语等语言不具备词分割符(如空格),所以无法恰当的返回搜索结果;

7、如何对中文实现全文搜索

可以通过中文分词技术给中文文本添加词分割符。
例如(插入某种分词后的数据):
insert into t_test(content) 
values 
(" find 命令" ), 
("跨国 采购 、 企业 采购 、 政府 采购 这 三 大 需求 , 已经 快速 催生 采购 管理 队伍 的 成长"), 
("堵车 或 等灯 的 时候 别 跟 的 太近" ), 
("不是 每个 人 都 喜欢 服从 命令 的. 命令 的 英文 是 什么" ), 
("find 这个 命令 很 好用" ), 
("应用程序 是 大家 的 , 你 知道 吗 ?" ), 
("你的 意思 我 当然 知道 了 ,我 不 傻" ), 
("谷歌 开发 了 很多 应用程序" ), 
("谷歌 地球 这款  应用程序 是 谷歌 公司 开发 的 。" ), 
("既然 全文 搜索 有 这样 的 优点 , 下面 我们 来 看看 是否 真的 如此"),  
("describe 命令 用于 查看 特定 表 的 详细 设计 信息" ), 
("是不是 一开始 觉得 有点 令人 气馁 或者 不舒服 ?" );

 以下是几个查询: 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('开发');  #无结果 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('采购');  #无结果 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('应用程序'); #有 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('find');      #有 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('+"应用程序" +"开发"' in boolean mode ); #无



正常情况下: 
insert into t_test(content) 
values 
("find命令" ), 
("跨国采购、企业采购、政府采购这三大需求,已经快速催生采购管理队伍的成长" ), 
("堵车或等灯的时候别跟的太近" ), 
("不是每个人都喜欢服从命令的.命令的英文是什么" ), 
("find这个命令很好用" ), 
("应用程序是大家的,你知道吗 ?" ), 
("你的意思我当然知道了,我不傻" ), 
("谷歌开发了很多应用程序" ), 
("谷歌地球这款应用程序是谷歌公司开发的。" ), 
("既然全文搜索有这样的优点,下面我们来看看是否真的如此" ), 
("describe命令用于查看特定表的详细设计信息" ), 
("是不是一开始觉得有点令人气馁或者不舒服?" );



查询如下:
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('开发');  #无结果 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('采购');  #无结果 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('应用程序'); #无 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('find');      #无 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('+"应用程序" +"开发"' in boolean mode ); #无



 由于建立的数据库采用utf-8编码,所以一个中文字符认为是一个字符,在上述数据中添加几个3字节单词和4字节单词重新插入数据:
insert into t_test(content) 
values 
("命令行" ), 
(" find 命令  命令行" ), 
("跨国 采购 、 企业 采购 、  政府 采购 这 三 大 需求 , 命令行 已经 快速 催生 采购 管理 队伍 的 成长"), 
("堵车 或 等灯 的 时候 别 跟 的 太近" ), 
("不是 每个 人 都 喜欢 服从 命令 的. 命令 的 英文 是 什么" ), 
("find 这个 命令 很 好用" ), 
("应用程序 是 大家 的 , 你 知道 吗 ?" ), 
("你的 意思 我 当然 知道 了 ,我 不 傻" ), 
("谷歌 开发 了 很多 应用程序" ), 
("谷歌 地球 这款  应用程序 是 谷歌 公司 开发 的 。" ), 
("既然 全文搜索 有  命令行 这样 的 优点 , 下面 我们 来 看看 是否 真的 如此"), 
("describe 命令 用于 查看 特定 表 的 详细 设计 信息" ), 
("是不是 一开始 全文搜索 觉得 有点 令人 气馁 或者 不舒服 ?" );



进行查询:
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('应用程序');   #有结果 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('命令行');   #无结果 
SELECT * FROM t_test WHERE MATCH ( content) AGAINST ('全文搜索');  #有结果



  获取每个文本的长度: 
select content,char_length(content ) from t_test;



六、参考文档

1、MySQL必知必会 Ben Forta 著,刘晓霞 钟鸣 译
2、MySQL 5.1 参考手册




你可能感兴趣的:(mysql,like,fulltext)