先来看看对一个字段作全文索引,做为一个数据库系统须要作哪些工做?html
假设一个文章表里面包含几个字段:文章id、文章做者、文章标题、文章内容mysql
好比,咱们对文章内容这个字段artilce_content创建全文索引,这样方便对文章里面的内容使用关键词搜索。算法
数据库系统首先须要从文章内容(这个字段内容)中提取关键词,由于只有提取了关键词,才好创建相似索引目录—相似于新华字典那样的笔画页码对应关系,当你搜索一个词语”beijing”的时候,就直接去索引中查找,而后就能够定位到数据行的具体位置了,不须要扫描文章表不少行。sql
这就像,若是我想去新华字典中查找一个汉字,我直接按照笔画或者按照拼音来查找(这个就是新华字典的索引),避免把新华字典从头翻到尾部,这样的效率多低。没错,若是没有索引,数据库系统就是须要这样子遍历扫描整个表才能获得数据的。数据库
ps:机器实际上是死的,你写的代码让他作什么就作什么。而人有眼睛,能够经过眼睛来看,好比大致翻看一下新华字典,也许眼睛就看到我须要的汉字了呢。服务器
数据库系统中的关于那个索引结构大致能够这样理解:this
关键词 包含此关键词的文档列表(也能够理解成行)搜索引擎
beijing 1,2,3…插件
索引就是方便快速查找,根据这个索引结构,搜索的时候就能够快速定位到数据位置了。htm
mysql对一个字段作全文索引的时候,他从文章内容中提取关键词,
mysql的全文检索解析器在提取关键词默认是按照空格来识别单词的。也就是中文”我喜欢打篮球” 这一串文字中没有空格,那么mysql不会把这个当成好几个单词的。
若是故意进行空格分开,mysql就容易识别处理关键词,好比变成”我 喜欢 打 篮球”
像上面这样子,mysql可能会把篮球当成关键词提取出来进入索引中去。为何只是可能?有空格只是保证mysql识别成单词,但会不会创建成索引,其实我不是很清楚。由于没看过mysql源码,不是很清楚。
由于对文章表的”文章内容”字段创建了成了全文索引,那么每次往表中新加入一行数据,数据库系统都会去提取文章新行数据中的文章内容字段,看有没有关键词,继续往索引表里面加单词或者更新数据。好比原来的索引文件有个单词”beijing”,如今新加入的文章内容中提取到有beijing这个词语,那要更新索引表了,意思是记录下新加的文档哪里存在beijing这个词语。
beijing 8,9,10
新加入的文档id为20,恰好其中文章内容被提取到了词语beijing
那么索引就要更新成以下形式:
beijing 8,9,20
这样解释是方便理解,理解就好。
大致是这样子的模式。具体实现会跟这个存在差别的。把复杂的问题解释得通俗化,简单化是而容易理解,是我进行总结的目的。
ps:mysql的一个表的全部字段的索引数据都在一张一个”表名称.MYI”文件中。
理解了上面的实现原理,
如今也好理解一句话了,这是从mysql手册中中的一句话:
对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,而后建立索引, 其速度比把资料输入现有FULLTEXT索引的速度更为快。
我是这么理解,好比,把100行数据同时插入文章表中,而文章内容字段是创建成全文索引,那么新插入的数据在入库的同时,要提取关键词(对文章内容字段),而后更新索引,速度固然会慢下来。关键问题就是在插入数据的时候就会去分词和更新索引。整个insert 操做就会延长时间了。
上面已经创建文章内容字段为全文索引,如今mysql是怎么进行全文查询的呢?
select id,title FROM 文章表 WHERE MATCH(article_content) AGAINST ('search keyword')
match()中指定字段名称。表示against()中出现的字符串要去哪一个字段中匹配。这里能够指定多个字段
against()中的字符串,难道不是单个词语,mysql会自动对受到的字符串进行分词吗?
AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
+号表示,MYSQL这个单词必须出如今每一行的开头位置?
‘’里面是单词,多个单词之间须要使用空格分开吗?
来看看对英文进行分词有什么自然优点
英文的特色,每一个英文单词就是一个词语,单词与单词之间有很是明显的分割符号—空格
好比
my name is wangxiaoming
this city is beijing…..
citye 和beijing能够当作是两个关键词,用来搜索
mysql内部对要提取关键词的时候,哪些能够做为关键词来创建索引呢?
它能够以空格来分割开来。把city 和 beijing都当成是两个关键词来创建索引(理解成新华字典中的笔画与页数的目录结构)。
总结一下
英文:除了少数特殊字符和标点几乎都是以空格分隔的,因此要对一段英文进行分词(也就是从中提取关键词),这样子比较容易。按照空格、逗号等特别的符号来识别便可。
来看看,中文分词为何就比较麻烦
因为中文比较特殊,像”理发师” 理发能够是一个关键词,理发师也能够是一个关键词。关键词之间并无明显的分割符号,咱们看到紧挨着的。这就须要mysql去提取哪些是关键词。是把”理”发做为关键词来索引,仍是”理发”或者”理发师”都算关键词,无法识别。
通常百度这些搜索引擎是怎么提取关键词,他们有个专门的关键词库的,也就是中文关键词词库。这样就知道把什么当成是关键词。显然,mysql是又国外人作的一个软件,它不会单独给你去作一个关键词库。
计算机怎么知道哪一个算是词语呢?好比输入一串文字 ”我来自北京,我很喜欢运动、听音乐…,喜欢听周华健的歌曲”
在这一句话中,北京算不算关键词呢。”周华健”算不算关键词呢?
像咱们常见的中文切词,我了解到有几种分词算法:
一、 就是根据词库来进行对比的。
二、 二元分词法
三、 统计法
对比:二元分词方法和统计方法是不依赖于词典的,而最大匹配法分词方法是依赖于词典的,词典的内容决定分词结构的好坏。
如今总结一下:MySQL不会断中文字:MySQL内建的字依据是空白、逗号和点来断词语。
mysql手册中原文以下:
FULLTEXT分析程序会经过寻找某些分隔符来肯定单词的起始位置和结束位置,例如' ' (间隔符号)、 , (逗号)以及 . (句号 )。假如单词没有被分隔符分开,(例如在中文里 ), 则 FULLTEXT 分析程序不能肯定一个词的起始位置和结束位置。为了可以在这样的语言中向FULLTEXT 索引添加单词或其它编入索引的术语,你必须对它们进行预处理,使其被一些诸如"之类的任意分隔符分隔开。
…………………
诸如汉语和日语这样的表意语言没有自定界符。所以, FULLTEXT分析程序不能肯定在这些或其它的这类语言中词的起始和结束的位置。其隐含操做及该问题的一些工做区在12.7节,“全文搜索功能”有详细论述。
==================================结束
中文与西方文字如英文的一个重要区别在于,西方文字以单词为单位,单词与单词之间以空格分隔。而中文以字为单位,词由一个或多个字组成,词与词之间没有空格分隔。当试图在一个含有中文字符的字段中使用全文搜索时,不会获得正确的结果,缘由在于中文中没有像英文空格那样对词定界,不能以空格做为分割,(因而不方便)对中文词语进行索引。
如今概括一下,mysql不能很好地支持中文全文索引的解决办法
一、针对对myql全文检索解析器内建机制特色,白痴解决方法是,存中文字时自行塞入空白断字。
这样就适应了mysql的切词机制了。不过这样子作比较别扭。由于哪有把”我是中国人”古意分开成”我 是 中国人”这样的形式呢。
显示文章内容的时候就比较别扭,不能显示成”我 是 中国人”给用户看,须要须要本身再次处理。
二、使用切词插件。mysql应该是意识到单靠本身来提供分词,永远没法知足世界上各类各样语言的特殊需求。因而从5.1版本开始,Mysql全文检索的解析器以插件的方式提供。让你们能够以插件的形式挂到mysql下面去(实际上就是做为mysql的一个存储引擎,好比sphinx就是插件挂上去)
挂载到mysql中的插件所完成是一个什么样的角色呢?
使用插件,就是能够按照你本身的方式去分词
当数据量很大的时候,比较成熟的作法是使用专门的全文索引系统,用这些专业的全文索引系统来分词,以mysql数据库中的数据做为数据源,来分词创建索引结构。查询的时候,先从全文索引系统中查询,获取文档编号,而后根据文档编号去mysql中查询数据。对于全文搜索插件sphinx-for-chinese,曾经在公司的服务器上配置过,经过那次配置加深了对它的理解。中途遇到一些问题,一直想以文字的形式总结出来,以备忘。有时间会上一篇关于它的操做总结出来。
我的理解不正确之处,欢迎指正!
本文未完待补充