<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://www.jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://www.jackxiang.com/post//</link>
<title><![CDATA[[实践OK]基于mysql全文索引的深入理解，Mysql全文搜索match against的用法。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[数据库技术]]></category>
<pubDate>Wed, 18 Jun 2014 13:12:44 +0000</pubDate> 
<guid>http://www.jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	背景：MySQL-Fullltext: 使用 MySQL 实现简单的搜索引擎，搜索下博文啥的，方便自己。<br/>http://blog.csdn.net/zajin/article/details/10970207<br/><br/>零、 Mysql下的Web程序，如何实现全文检索：<br/>使用逻辑搜索修饰符（Boolean search modifiers） <br/>++表示必须 <br/>+表示要有的-表示不能有的 <br/>不带+或者-表示，任意一种<br/>http://blog.csdn.net/froole/article/details/3497907<br/><br/>一、基于mysql全文索引的深入理解<br/>前言：本文简单讲述全文索引的应用实例，MYSQL演示版本5.5.24。<br/>Q:全文索引适用于什么场合？<br/>A:全文索引是目前实现大数据搜索的关键技术。<br/>至于更详细的介绍请自行百度，本文不再阐述。<br/>--------------------------------------------------------------------------------<br/>一、如何设置？<br/>如图点击结尾处的&#123;全文搜索&#125;即可设置全文索引，不同MYSQL版本名字可能不同。<br/>二、设置条件<br/>1.表的存储引擎是MyISAM，默认存储引擎InnoDB不支持全文索引（新版本MYSQL5.6的InnoDB支持全文索引）<br/>2.字段类型：char、varchar和text<br/>三、配置<br/>my.ini配置文件中添加<br/># MySQL全文索引查询关键词最小长度限制<br/>[mysqld]<br/>ft_min_word_len = 1<br/>实践注意：<br/> ft_min_word_len&nbsp;&nbsp;&nbsp;&nbsp; 加入索引的词的最小长度, 缺省是 4, 为了支持中文单字故改为 2 <br/><br/>保存后重启MYSQL，执行SQL语句<br/>SHOW VARIABLES<br/>查看ft_min_word_len是否设置成功，如果没设置成功请确保<br/>1.确认my.ini正确配置，注意不要搞错my.ini的位置<br/>2.确认mysql已经重启，实在不行重启电脑<br/>其他相关配置请自行百度。<br/>注：重新设置配置后，已经设置的索引需要重新设置生成索引<br/>四、SQL语法<br/>首先生成temp表<br/>CREATE TABLE IF NOT EXISTS `temp` (<br/>&nbsp;&nbsp;`id` int(11) NOT NULL AUTO_INCREMENT,<br/>&nbsp;&nbsp;`char` char(50) NOT NULL,<br/>&nbsp;&nbsp;`varchar` varchar(50) NOT NULL,<br/>&nbsp;&nbsp;`text` text NOT NULL,<br/>&nbsp;&nbsp;PRIMARY KEY (`id`),<br/>&nbsp;&nbsp;FULLTEXT KEY `char` (`char`),<br/>&nbsp;&nbsp;FULLTEXT KEY `varchar` (`varchar`),<br/>&nbsp;&nbsp;FULLTEXT KEY `text` (`text`)<br/>) ENGINE=MyISAM&nbsp;&nbsp;DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;<br/>INSERT INTO `temp` (`id`, `char`, `varchar`, `text`) VALUES<br/>(1, &#039;a bc 我 知道 1 23&#039;, &#039;a bc 我 知道 1 23&#039;, &#039;a bc 我 知道 1 23&#039;);<br/>搜索`char`字段 &#039;a&#039; 值<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a&#039;)<br/>但是你会发现查询无结果？！<br/>这时你也许会想：哎呀怎么回事，我明明按照步骤来做的啊，是不是那里漏了或者错了？<br/>你不要着急，做程序是这样的，出错总是有的，静下心来，着急是不能解决问题的。<br/>如果一个关键词在50%的数据出现，那么这个词会被当做无效词。<br/>如果你想去除50%的现在请使用IN BOOLEAN MODE搜索<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a&#039; IN BOOLEAN MODE)<br/>这样就可以查询出结果了，但是我们不推荐使用。<br/>全文索引的搜索模式的介绍自行百度。<br/>我们先加入几条无用数据已解除50%限制<br/>INSERT INTO&nbsp;&nbsp;`temp` (<br/>`id` ,<br/>`char` ,<br/>`varchar` ,<br/>`text`<br/>)<br/>VALUES (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;<br/>);<br/>这时你执行以下SQL语句都可以查询到数据<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;bc&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;我&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;知道&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;1&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;23&#039;);<br/>以下SQL搜索不到数据<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;b&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;c&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;知&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;道&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;2&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;3&#039;);<br/>如果搜索多个词，请用空格或者逗号隔开<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a x&#039;);<br/>SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a,x&#039;);<br/>上面的SQL都可以查询到三条数据<br/>五、分词<br/>看到这里你应该发现我们字段里的值也是分词，不能直接插入原始数据。<br/>全文索引应用流程：<br/>1.接收数据-数据分词-入库<br/>2.接收数据-数据分词-查询<br/>现在有个重要的问题：怎么对数据分词？<br/>数据分词一般我们会使用一些成熟免费的分词系统，当然如果你有能力也可以自己做分词系统，这里我们推荐使用SCWS分词插件。<br/>首先下载<br/>1.php_scws.dll&nbsp;&nbsp;注意对应版本<br/>2.XDB词典文件<br/>3.规则集文件<br/>下载地址<br/>安装scws<br/>1.先建一个文件夹，位置不限，但是最好不要中文路径。<br/>2.解压&#123;规则集文件&#125;，把xdb、三个INI文件全部扔到 D:&#92;scws<br/>3.把php_scws.dll复制到你的PHP目录下的EXT文件夹里面<br/>4.在 php.ini 的末尾加入以下几行：<br/>[scws]<br/>; 注意请检查 php.ini 中的 extension_dir 的设定值是否正确, 否则请将 extension_dir 设为空，<br/>; 再把 php_scws.dll 指定为绝对路径。<br/>extension = php_scws.dll<br/>scws.default.charset = utf8<br/>scws.default.fpath = &quot;D:&#92;scws&quot;<br/>5.重启你的服务器<br/>测试<br/>$str=&quot;测试中文分词&quot;;<br/>$so = scws_new();<br/>$so-&gt;send_text($str);<br/>$temp=$so-&gt;get_result();<br/>$so-&gt;close();<br/>var_dump($temp);<br/>如果安装未成功，请参照官方说明文档<br/>--------------------------------------------------------------------------------<br/>这样我们就可以使用全文索引技术了。<br/><br/>来自：http://www.jb51.net/article/37738.htm<br/><br/>实践如下：<br/>值为1搜索1，值为4，什么也搜索不了。<br/>mysql&gt; show variables like &quot;%ft_min_word_len%&quot;；<br/>+-----------------+-------+<br/>&#124; Variable_name&nbsp;&nbsp; &#124; Value &#124;<br/>+-----------------+-------+<br/>&#124; ft_min_word_len &#124; 4&nbsp;&nbsp;&nbsp;&nbsp; &#124;<br/>+-----------------+-------+<br/>——————————————————————————————————————————<br/>mysql&gt; CREATE DATABASE `jackxiang_search_test` /*!40100 DEFAULT CHARACTER SET utf8 */;&nbsp;&nbsp;&nbsp;&nbsp; <br/>Query OK, 1 row affected (0.01 sec)<br/><br/>mysql&gt; use jackxiang_search_test;<br/>Database changed<br/>mysql&gt; <br/><br/>mysql&gt; CREATE TABLE IF NOT EXISTS `temp` (<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; `id` int(11) NOT NULL AUTO_INCREMENT,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; `char` char(50) NOT NULL,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; `varchar` varchar(50) NOT NULL,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; `text` text NOT NULL,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; PRIMARY KEY (`id`),<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; FULLTEXT KEY `char` (`char`),<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; FULLTEXT KEY `varchar` (`varchar`),<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp; FULLTEXT KEY `text` (`text`)<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; ) ENGINE=MyISAM&nbsp;&nbsp;DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;<br/>Query OK, 0 rows affected (0.08 sec)<br/>mysql&gt; INSERT INTO `temp` (`id`, `char`, `varchar`, `text`) VALUES<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; (1, &#039;a bc 我 知道 1 23&#039;, &#039;a bc 我 知道 1 23&#039;, &#039;a bc 我 知道 1 23&#039;);<br/>Query OK, 1 row affected (0.05 sec)<br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a&#039;);<br/>Empty set (0.06 sec)<br/><br/><br/>mysql&gt; INSERT INTO&nbsp;&nbsp;`temp` (<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; `id` ,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; `char` ,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; `varchar` ,<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; `text`<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; )<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; VALUES (<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; ), (<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; ), (<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; NULL ,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; ), (<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; NULL ,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;<br/>&nbsp;&nbsp;&nbsp;&nbsp;-&gt; );<br/>Query OK, 4 rows affected (0.02 sec)<br/>Records: 4&nbsp;&nbsp;Duplicates: 0&nbsp;&nbsp;Warnings: 0<br/><br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a&#039;);<br/>Empty set (0.00 sec)<br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;bc&#039;);<br/>Empty set (0.00 sec)<br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;我&#039;);<br/>Empty set (0.00 sec)<br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;b&#039;);<br/>Empty set (0.00 sec)<br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;a x&#039;);<br/>Empty set (0.00 sec)<br/><br/>INSERT INTO&nbsp;&nbsp;`temp` (<br/>`id` ,<br/>`char` ,<br/>`varchar` ,<br/>`text`<br/>)<br/>VALUES (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;a,bc,我,向东阳子，让子弹飞，东方时尚,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;<br/>);<br/><br/>INSERT INTO&nbsp;&nbsp;`temp` (<br/>`id` ,<br/>`char` ,<br/>`varchar` ,<br/>`text`<br/>)<br/>VALUES (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;a,bc,我,向东阳子，东方时尚,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;<br/>);<br/><br/>INSERT INTO&nbsp;&nbsp;`temp` (<br/>`id` ,<br/>`char` ,<br/>`varchar` ,<br/>`text`<br/>)<br/>VALUES (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;a,bc,我是向东阳,向东阳子，让子弹飞，东方时尚,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;<br/>);<br/><br/>INSERT INTO&nbsp;&nbsp;`temp` (<br/>`id` ,<br/>`char` ,<br/>`varchar` ,<br/>`text`<br/>)<br/>VALUES (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;,&nbsp;&nbsp;&#039;7&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;a,bc,我是向东阳,向东晓苹，让子弹飞，东方时尚,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;,&nbsp;&nbsp;&#039;a,bc,我,知道,1,23&#039;<br/>), (<br/>NULL ,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;,&nbsp;&nbsp;&#039;x&#039;<br/>);<br/><br/>mysql&gt; SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;向东晓苹&#039;);<br/>+----+----------------------------------------------------------------------+----------------------+----------------------+<br/>&#124; id &#124; char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#124; varchar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#124; text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#124;<br/>+----+----------------------------------------------------------------------+----------------------+----------------------+<br/>&#124; 20 &#124; a,bc,我是向东阳,向东晓苹，让子弹飞，东方时尚,1,23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#124; a,bc,我,知道,1,23&nbsp;&nbsp;&nbsp;&nbsp;&#124; a,bc,我,知道,1,23&nbsp;&nbsp;&nbsp;&nbsp;&#124;<br/>+----+----------------------------------------------------------------------+----------------------+----------------------+<br/>1 row in set (0.00 sec)<br/><br/>因设置四个字符，所以三个字符是搜索不到的：<br/><br/>mysql&gt;&nbsp;&nbsp;SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST (&#039;向东阳&#039;);&nbsp;&nbsp;<br/>Empty set (0.00 sec)<br/><br/>设置这个值多少靠自己的判断，后面就是分词来插入上面的内容了：<br/>my.ini配置文件中添加<br/># MySQL全文索引查询关键词最小长度限制<br/>[mysqld]<br/>ft_min_word_len = 1<br/>SCWS分词插件。<br/><br/><br/>二、<br/>自然语言全文搜索<br/>自然语言全文搜索是MySQL全文搜索的默认搜索方式，实现从一个文本集合中搜索给定的字符串。这里，文本集合指的是指由FULLTEXT索引的一个或者多个列。<br/><br/>建表，并给title，body字段加FULLTEXT索引<br/><br/>CREATE TABLE articles (<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; title VARCHAR(200),<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; body TEXT,<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; FULLTEXT (title,body)<br/><br/>) ENGINE=InnoDB;<br/><br/>导入数据<br/><br/>INSERT INTO articles (title,body) VALUES<br/><br/>&nbsp;&nbsp; (&#039;MySQL Tutorial&#039;,&#039;DBMS stands for DataBase ...&#039;),<br/><br/>&nbsp;&nbsp; (&#039;How To Use MySQL Well&#039;,&#039;After you went through a ...&#039;),<br/><br/>&nbsp;&nbsp; (&#039;Optimizing MySQL&#039;,&#039;In this tutorial we will show ...&#039;),<br/><br/>&nbsp;&nbsp; (&#039;1001 MySQL Tricks&#039;,&#039;1. Never run mysqld as root. 2. ...&#039;),<br/><br/>&nbsp;&nbsp; (&#039;MySQL vs. YourSQL&#039;,&#039;In the following database comparison ...&#039;),<br/><br/>&nbsp;&nbsp; (&#039;MySQL Security&#039;,&#039;When configured properly, MySQL ...&#039;);<br/><br/>例1：<br/><br/>SELECT * FROM articles<br/><br/>WHERE MATCH (title,body)<br/><br/>AGAINST (&#039;database&#039; IN NATURAL LANGUAGE MODE);<br/><br/><br/>可以看到，语句查找到了包含指定内容的行。实际上，返回的行是按与所查找内容的相关度由高到低的顺序排列的。这个相关度的值由WHERE语句中的MATCH (…) AGAINST (…)计算所得，是一个非负浮点数。该值越大表明相应的行与所查找的内容越相关，0值表明不相关。该值基于行中的单词数、行中不重复的单词数、文本集合中总单词数以及含特定单词的行数计算得出。<br/>来自：http://blog.csdn.net/zyz511919766/article/details/12780173<br/>http://www.linuxde.net/2013/08/15062.html<br/>http://hi.baidu.com/logan9999/item/3ea8c5ddabc5b63b48e1ddb9<br/><br/><br/>三、Mysql全文搜索match against的用法：<br/>———————————————————————建立索引—————————————————————————<br/>&nbsp;&nbsp; 全文检索在 MySQL 中就是一个 FULLTEXT 类型索引。FULLTEXT 索引用于 MyISAM 表，可以在 CREATE TABLE 时或之后使用 ALTER TABLE 或 CREATE INDEX 在 CHAR、 VARCHAR 或 TEXT 列上创建<br/>&nbsp;&nbsp; 对于大的数据库，将数据装载到一个没有 FULLTEXT 索引的表中，然后再使用 ALTER TABLE&nbsp;&nbsp; (或 CREATE INDEX) 创建索引，这将是非常快的。将数据装载到一个已经有 FULLTEXT 索引的表中，将是非常慢的。<br/>1.使用Mysql全文检索fulltext的先决条件<br/>&nbsp;&nbsp;&nbsp;&nbsp;表的类型必须是MyISAM<br/>建立全文检索的字段类型必须是char,varchar,text<br/><br/>2.建立全文检索先期配置<br/>由于Mysql的默认配置是索引的词的长度是4,所以要支持中文单字的话,首先更改这个.<br/>*Unix用户要修改my.cnf,一般此文件在/etc/my.cnf,如果没有找到,先查找一下find / -name &#039;my.cnf&#039;<br/>在 [mysqld] 位置内加入:&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_min_word_len&nbsp;&nbsp;&nbsp;&nbsp; = 2 <br/>其它属性还有<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_wordlist_charset = gbk <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_wordlist_file = /home/soft/mysql/share/mysql/wordlist-gbk.txt <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_stopword_file = /home/soft/mysql/share/mysql/stopwords-gbk.txt <br/>稍微解释一下: <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_wordlist_charset 表示词典的字符集, 目前支持良好的有(UTF-8, gbk, gb2312, big5) <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_wordlist_file 是词表文件, 每行包括一个词及其词频(用若干制表符或空格分开,消岐专用) <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_stopword_file 表示过滤掉不索引的词表, 一行一个. <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ft_min_word_len&nbsp;&nbsp;&nbsp;&nbsp; 加入索引的词的最小长度, 缺省是 4, 为了支持中文单字故改为 2 <br/><br/>3.建立全文检索<br/>在建表中用FullText关键字标识字段,已存在的表用 ALTER TABLE (或 CREATE INDEX) 创建索引<br/>CREATE fulltext INDEX index_name ON table_name(colum_name);<br/><br/>4.使用全文检索<br/>&nbsp;&nbsp;&nbsp;&nbsp;在SELECT的WHERE字句中用MATCH函数,索引的关键词用AGAINST标识,IN BOOLEAN MODE是只有含有关键字就行,不用在乎位置,是不是起启位置.<br/>SELECT * FROM articles WHERE MATCH (tags) AGAINST (&#039;旅游&#039; IN BOOLEAN MODE);<br/><br/>5.详细的说明请参数Mysql官方网站<br/>http://dev.mysql.com/doc/refman/5.1/zh/functions.html#fulltext-search<br/>这是Mysql 5.1的,不过4.X也可以做为参考,基本一置.我用的就是Mysql 4.1.<br/>MySQL支持全文索引(Full-Text) 已经很久了，目前，fulltext是一种只适用于MyISAM表的一个索引类型，而且对定义索引列的数据类型也有限制，只能是以下三种的组合char、 varchar、text。fulltext可以在创建表的同时就一起定义好，或者在表创建完成之后，通过语句alter table或create index来追加索引，总之先后的效果是一样的，但是两者的效率却是存在很大差异的，大量的实验证明，对于大数量的表来说，先加载数据再来定义全文索引的 速度要远远优于在一个已经定义好全文索引的表里面插入大量数据的速度。一定会问：这是问什么呢？其实，道理很简单，前者只需要一次性对你的索引列表进行操 作，排序比较都是在内存中完成，然后写入硬盘；后者则要一条一条去硬盘中读取索引表然后再进行比较最后写入，自然这样速度就会很慢。MySQL是 通过match()和against()这两个函数来实现它的全文索引查询的功能。match()中的字段名称要和fulltext中定义的字段一致，如 果采用boolean模式搜索，也允许只包括fulltext中的某个字段，不需要全部列出。against()中定义的是所要搜索的字符串以及要求数据 库通过哪种模式去执行全文索引的搜索查询。下面通过一个例子分别介绍一下fulltext所支持的3中搜索模式。<br/>MySQL全文索引与中文分词总结及一般的关键词搜索流程 <br/>http://www.tzlink.com/info/show.php?aid=4532<br/>mysql 全文检索 中文分词<br/>http://hi.baidu.com/agg230/blog/item/33d3d50eada260e337d1225b.html<br/>支持中文的MySQL 5.1+ 全文检索分词插件<br/>http://hi.baidu.com/start_and_end/blog/item/6d6ab918b7d3800334fa412e.html<br/>家用一下搜索引擎就会发现，分词的情况只是出现在当整词命中为0的情况下。 <br/>而具体怎样分词，大家可以参考一下baidu搜索试验结果： <br/><br/>·如果搜“徐祖宁宁”，结果为“徐祖”+“宁宁”。（搜人名的情况下，它可能有一个百家姓词典，自动将姓后第一个字归前） <br/>·搜“徐宁愿”，结果为“徐宁愿”。（说明“宁愿”归“徐”所有。同上。因为徐是姓。） <br/>·搜“徐祖宁愿”，结果为“徐祖”+“宁愿”。（因为“宁愿”是词，故“徐”只带“祖”。） <br/>·搜“徐祖宁高”，结果为“徐祖宁”。（因为“宁高”不是关键字，所以“宁”归前词所有。而“高”可能因为是单字，为提高前词搜索效率故被省略。）<br/><br/>来自：http://www.jb51.net/article/28679.htm<br/><br/>四、适宜做简单搜索的MySQL数据库全文索引<br/>全文索引在 MySQL 中是一个 FULLTEXT 类型索引。FULLTEXT 索引用于 MyISAM 表，可以在 CREATE TABLE 时或之后使用 ALTER TABLE 或 CREATE INDEX 在 CHAR、VARCHAR 或 TEXT 列上创建。对于大的数据库，将数据装载到一个没有 FULLTEXT 索引的表中，然后再使用 ALTER TABLE (或 CREATE INDEX) 创建索引，这将是非常快的。将数据装载到一个已经有 FULLTEXT 索引的表中，将是非常慢的。<br/>全文搜索通过 MATCH() 函数完成:<br/>mysql&gt; CREATE TABLE articles (<br/>-&gt; id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,<br/>-&gt; title VARCHAR(200),<br/>-&gt; body TEXT,<br/>-&gt; FULLTEXT (title,body)<br/>-&gt; );<br/>Query OK, 0 rows affected (0.00 sec)<br/>mysql&gt; INSERT INTO articles VALUES<br/>-&gt; (NULL,&#039;MySQL Tutorial&#039;, &#039;DBMS stands for DataBase ...&#039;),<br/>-&gt; (NULL,&#039;How To Use MySQL Efficiently&#039;, &#039;After you went through a ...&#039;),<br/>-&gt; (NULL,&#039;Optimising MySQL&#039;,&#039;In this tutorial we will show ...&#039;),<br/>-&gt; (NULL,&#039;1001 MySQL Tricks&#039;,&#039;1. Never run mysqld as root. 2. ...&#039;),<br/>-&gt; (NULL,&#039;MySQL vs. YourSQL&#039;, &#039;In the following database comparison ...&#039;),<br/>-&gt; (NULL,&#039;MySQL Security&#039;, &#039;When configured properly, MySQL ...&#039;);<br/>Query OK, 6 rows affected (0.00 sec)<br/>Records: 6 Duplicates: 0 Warnings: 0<br/>mysql&gt; SELECT * FROM articles<br/>-&gt; WHERE MATCH (title,body) AGAINST (&#039;database&#039;);<br/>+----+-------------------+------------------------------------------+<br/>&#124; id &#124; title &#124; body &#124;<br/>+----+-------------------+------------------------------------------+<br/>&#124; 5 &#124; MySQL vs. YourSQL &#124; In the following database comparison ... &#124;<br/>&#124; 1 &#124; MySQL Tutorial &#124; DBMS stands for DataBase ... &#124;<br/>+----+-------------------+------------------------------------------+<br/>2 rows in set (0.00 sec)<br/>函数 MATCH() 对照一个文本集(包含在一个 FULLTEXT 索引中的一个或多个列的列集)执行一个自然语言搜索一个字符串。搜索字符串做为 AGAINST() 的参数被给定。搜索以忽略字母大小写的方式执行。对于表中的每个记录行，MATCH() 返回一个相关性值。即，在搜索字符串与记录行在 MATCH() 列表中指定的列的文本之间的相似性尺度。<br/>当 MATCH() 被使用在一个 WHERE 子句中时 (参看上面的例子)，返回的记录行被自动地以相关性从高到底的次序排序。相关性值是非负的浮点数字。零相关性意味着不相似。相关性的计算是基于：词在记录行中的数目、在行中唯一词的数目、在集中词的全部数目和包含一个特殊词的文档(记录行)的数目。<br/>它也可以执行一个逻辑模式的搜索。这在下面的章节中被描述。<br/>前面的例子是函数 MATCH() 使用上的一些基本说明。记录行以相似性递减的顺序返回。 下一个示例显示如何检索一个明确的相似性值。如果即没有 WHERE 也没有 ORDER BY 子句，返回行是不排序的。<br/>mysql&gt; SELECT id,MATCH (title,body) AGAINST (&#039;Tutorial&#039;) FROM articles;<br/>+----+-----------------------------------------+<br/>&#124; id &#124; MATCH (title,body) AGAINST (&#039;Tutorial&#039;) &#124;<br/>+----+-----------------------------------------+<br/>&#124; 1 &#124; 0.64840710366884 &#124;<br/>&#124; 2 &#124; 0 &#124;<br/>&#124; 3 &#124; 0.66266459031789 &#124;<br/>&#124; 4 &#124; 0 &#124;<br/>&#124; 5 &#124; 0 &#124;<br/>&#124; 6 &#124; 0 &#124;<br/>+----+-----------------------------------------+<br/>6 rows in set (0.00 sec)<br/>下面的示例更复杂一点。查询返回相似性并依然以相似度递减的次序返回记录行。为了完成这个结果，你应该指定 MATCH() 两次。这不会引起附加的开销，因为 MySQL 优化器会注意到两次同样的 MATCH() 调用，并只调用一次全文搜索代码。<br/>mysql&gt; SELECT id, body, MATCH (title,body) AGAINST<br/>-&gt; (&#039;Security implications of running MySQL as root&#039;) AS score<br/>-&gt; FROM articles WHERE MATCH (title,body) AGAINST<br/>-&gt; (&#039;Security implications of running MySQL as root&#039;);<br/>+----+-------------------------------------+-----------------+<br/>&#124; id &#124; body &#124; score &#124;<br/>+----+-------------------------------------+-----------------+<br/>&#124; 4 &#124; 1. Never run mysqld as root. 2. ... &#124; 1.5055546709332 &#124;<br/>&#124; 6 &#124; When configured properly, MySQL ... &#124; 1.31140957288 &#124;<br/>+----+-------------------------------------+-----------------+<br/>2 rows in set (0.00 sec)<br/>MySQL 使用一个非常简单的剖析器来将文本分隔成词。一个“词”是由文字、数据、“&#039;” 和 “_” 组成的任何字符序列。任何在 stopword 列表上出现的，或太短的(3 个字符或更少的)的 “word” 将被忽略。<br/>在集和查询中的每个合适的词根据其在集与查询中的重要性衡量。这样，一个出现在多个文档中的词将有较低的权重(可能甚至有一个零权重)，因为在这个特定的集中，它有较低的语义值。否则，如果词是较少的，它将得到一个较高的权重。然后，词的权重将被结合用于计算记录行的相似性。<br/>这样一个技术工作可很好地工作与大的集(实际上，它会小心地与之谐调)。 对于非常小的表，词分类不足以充份地反应它们的语义值，有时这个模式可能产生奇怪的结果。<br/>mysql&gt; SELECT * FROM articles WHERE MATCH (title,body) AGAINST (&#039;MySQL&#039;);<br/>Empty set (0.00 sec)<br/>在上面的例子中，搜索词 MySQL 却没有得到任何结果，因为这个词在超过一半的记录行中出现。同样的，它被有效地处理为一个 stopword (即，一个零语义值的词)。这是最理想的行为 -- 一个自然语言的查询不应该从一个 1GB 的表中返回每个次行(second row)。<br/>匹配表中一半记录行的词很少可能找到相关文档。实际上，它可能会发现许多不相关的文档。我们都知道，当我们在互联网上通过搜索引擎试图搜索某些东西时，这会经常发生。因为这个原因，在这个特殊的数据集中，这样的行被设置一个低的语义值。<br/>到 4.0.1 时，MySQL 也可以使用 IN BOOLEAN MODE 修饰语来执行一个逻辑全文搜索。<br/>mysql&gt; SELECT * FROM articles WHERE MATCH (title,body)<br/>-&gt; AGAINST (&#039;+MySQL -YourSQL&#039; IN BOOLEAN MODE);<br/>+----+------------------------------+-------------------------------------+<br/>&#124; id &#124; title &#124; body &#124;<br/>+----+------------------------------+-------------------------------------+<br/>&#124; 1 &#124; MySQL Tutorial &#124; DBMS stands for DataBase ... &#124;<br/>&#124; 2 &#124; How To Use MySQL Efficiently &#124; After you went through a ... &#124;<br/>&#124; 3 &#124; Optimising MySQL &#124; In this tutorial we will show ... &#124;<br/>&#124; 4 &#124; 1001 MySQL Tricks &#124; 1. Never run mysqld as root. 2. ... &#124;<br/>&#124; 6 &#124; MySQL Security &#124; When configured properly, MySQL ... &#124;<br/>+----+------------------------------+-------------------------------------+<br/>这个查询返回所有包含词 MySQL 的记录行(注意： 50% 的阈值没有使用)，但是它没有包含词 YourSQL。注意，一个逻辑模式的搜索不会自动地以相似值的降序排序记录行。你可以从上面的结果出看得出来，最高的相似值(包含 MySQL 两次的那个) 最列在最后，而不是第一位。一个逻辑全文搜索即使在没有一个 FULLTEXT 索引的情况下也可以工作，然而它慢些。<br/>逻辑全文搜索支持下面的操作符：“+” 一个领头的加号表示，该词必须出现在每个返回的记录行中，“-” 一个领头的减号表示，该词必须不出现在每个返回的记录行中。<br/>缺省的 (当既没有加号也没有负号被指定时)词是随意的，但是包含它的记录行将被排列地更高一点。这个模仿没有 IN BOLEAN MODE 修饰词的 MATCH() ... AGAINST() 的行为。<br/>&lt; &gt; 这两个操作符用于改变一个词的相似性值的基值。&lt; 操作符减少基值，&gt; 操作符则增加它。参看下面的示例。<br/>( ) 圆括号用于对子表达式中的词分组。<br/>~一个领头的否定号的作用象一个否定操作符，引起行相似性的词的基值为负的。它对标记一个噪声词很有用。一个包含这样的词的记录将被排列得低一点，但是不会被完全的排除，因为这样可以使用 - 操作符。<br/>* 一个星号是截断操作符。不想其它的操作符，它应该被追加到一个词后，不加在前面。<br/>&quot; 短语，被包围在双引号&quot;中，只匹配包含这个短语(字面上的，就好像被键入的)的记录行。<br/>这里是一些示例：<br/>apple banana<br/>找至少包含上面词中的一个的记录行<br/>1.+apple +juice ... 两个词均在被包含<br/>2.+apple macintosh ... 包含词 “apple”，但是如果同时包含 “macintosh”，它的排列将更高一些<br/>3.+apple -macintosh ... 包含 “apple” 但不包含 “macintosh”<br/>4.+apple +(&gt;pie 5.apple* ... 包含 “apple”，“apples”，“applesauce” 和 “applet”<br/>6.&quot;some words&quot; ... 可以包含 “some words of wisdom”，但不是 “some noise words”<br/>全文的限制<br/>* MATCH() 函数的所有参数必须是从来自于同一张表的列，同时必须是同一个FULLTEXT 索引中的一部分，除非 MATCH() 是 IN BOOLEAN MODE 的。<br/>* MATCH() 列列表必须确切地匹配表的某一 FULLTEXT 索引中定义的列列表，除非 MATCH() 是 IN BOOLEAN MODE 的。<br/>* AGAINST() 的参数必须是一个常量字符串。<br/>微调MySQL全文搜索<br/>不幸地，全文搜索仍然只有很少的用户可调参数，虽然增加一些在 TODO 上排列很高。如果你有一个 MySQL 源码发行(查看章节 2.3 安装一个 MySQL 源码发行)，你可以发挥对全文搜索的更多控制。<br/>注意，全文搜索为最佳的搜索效果，被仔细地调整了。修改默认值的行为，在大多数情况下，只会使搜索结果更糟。不要修改 MySQL 的源代码，除非你知道你在做什么！<br/>* 被索引的词的最小长度由 MySQL 变量 ft_min_word_len 指定。查看章节 4.5.6.4 SHOW VARIABLES。将它改为你所希望的值，并重建你的 FULLTEXT 索引。 (这个变量只从 MySQL 4.0 开始被支持)<br/>* stopword 列表可以从 ft_stopword_file 变量指定的文件中读取。查看章节 4.5.6.4 SHOW VARIABLES。在修改了 stopword 列表后，重建你的 FULLTEXT 索引。(这个变量只从 MySQL 4.0.10 开始被支持)<br/>* 50% 阈值选择由所选择的特殊的衡量模式确定。为了禁止它，修改 `myisam/ftdefs.h&#039; 文件中下面的一行：<br/>#define GWS_IN_USE GWS_PROB<br/>改为：<br/>#define GWS_IN_USE GWS_FREQ<br/>然后重新编译 MySQL。在这种情况下，不需要重建索引。 注意：使用了这个，将严重地减少 MySQL 为 MATCH() 提供足够的相似性值的能力。如果你确实需要搜索这样的公共词，最好使用 IN BOOLEAN MODE 的搜索代替，它不遵守 50% 的阈值。<br/>* 有时，搜索引擎维护员希望更改使用于逻辑全文搜索的操作符。这些由变量 ft_boolean_syntax 定义。然而，这个变量是只读的，它的值在 `myisam/ft_static.c&#039; 中被设置。<br/>对于这些更改，要求你重建你的 FULLTEXT 索引，对于一个 MyISAM 表，最容易的重建索引文件的方式如下面的语句：<br/>mysql&gt; REPAIR TABLE tbl_name QUICK;<br/>全文搜索 TODO * 使所有对 FULLTEXT 索引的操作更快<br/>* 邻近(Proximity)操作符<br/>* 对 &quot;always-index words&quot; 的支持。他们可以是用户希望视为一个词处理的任意字符串，例如 &quot;C++&quot;、&quot;AS/400&quot;、&quot;TCP/IP&quot;，等等<br/>* 支持在 MERGE 表中的全文搜索<br/>* 对多字节字符的支持<br/>* 依照数据的语言建立 stopword 列表<br/>* Stemming (当然，依赖于数据的语言)<br/>* Generic user-suppliable UDF preparser.<br/>* 使模式更加灵活 (通过为 CREATE/ALTER TABLE 中的 FULLTEXT 增加某些可调整参数)<br/><br/>来自：<br/>http://www.php100.com/html/webkaifa/database/Mysql/2008/0709/1090.html<br/><br/>五、有人不想再用oracle的mysql了：<br/>https://linuxtoy.org/archives/mysql-5-6-ga-and-escape.html
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] [实践OK]基于mysql全文索引的深入理解，Mysql全文搜索match against的用法。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>