查问我看笔记功能的实现过程之三-MYSQL8.0全文索引使用​

PHPer 2020-04-08 1180 0 0
MYSQL8.0全文索引使用

概述:

在一堆文字中找到含有关键字的应用。当然也可以用以下语句实现:

SELECT * FROM <表名> WHERE <字段名> like ‘%ABC%’

但是它的效率太低,是全盘扫描。

Mysql 提供了更高效的方法全文索引(FULLTEXT)

重要:

Mysql 5.6之前版本,只有myisam支持全文索引,5.6之后,Innodb和myisam均支持全文索引。

只有char、varchar、text类型字段能创建全文索引。

当大量写入数据时,建议先写入数据,后再建立全文索引,提高效率。

Mysql内置ngram 解析器,可以解析中日韩三国文字。有汉字的一定要启用它。

英文分词用空格,逗号;中文分词用 ngram_token_size 设定,后面有讲解。

全文索引在引用前需要新设定下变量

均在my.ini文件中设定,在 [mysqld]的下面追加

需要将搜索短语长度设定合适

// MyISAM

ft_min_word_len = 4; 默认值

ft_max_word_len = 84; 默认值

// InnoDB

innodb_ft_min_token_size = 3; 默认值

innodb_ft_max_token_size = 84; 默认值

//ngram解析器令牌长度----即aiginst()中字符串切分的最小字符长度

ngram_token_size = 2~10 ; 默认值

一般设定:(以下例子均是假定设置如下)

在 [mysqld]的下面追加:

innodb_ft_min_token_size = 1

ft_min_word_len = 1

ngram_token_size = 1

设定好后需要关闭mysql服务,再重启mysql服务。在全文查询前,需要先将全文索引删除(如果有),再重新建。

创建全文索引

建议建表后新建

ALTER TABLE <表名> add FULLTEXT INDEX <索引名>(字段名1,字段2,,) [ WITH PARSER ngram];

全文索引查询

SELECT <字段表> FROM <表名> WHERE MATCH(字段) AGAINST (‘要搜索的关键词’ 搜索模式);

三种全文搜索模式:

自然语言模式,默认,一般省略不写

IN NATURAL LANGUAGE MODE,

例子1:

SELECT foldID,foldName FROM fold WHERE MATCH(foldName) AGAINST (‘张三’ );...

立即注册

mysql数据库存入报错,好像是内容超出了Text格式的长度

Database Exception – yii\db\Exception

Error Info: Array

(

[0] => HY000

[1] => 1366

[2] => Incorrect string value: '\xE5' for column 'content_no_html' at row 1

)

↵...

立即注册

mysql数据库存入报错之二,好像是内容超出了Text格式的长度

SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'content_no_html' at row 1

The SQL being executed was: UPDATE `w_post` SET `content_no_html`='...

立即注册

实测,mysql8 中文全文索引

不对额,说是双引号的含义和单引号不同,但是结果条数相同的,内容也是一样的
$sql='select * from w_note where match(content_no_html) against("全文")';// 17条 // $sql="select * from w_note where match(content_no_html) against('全文')";// 17条 // $sql='select * from w_n
立即注册

Mysql8全文索引查询实测-match(title) against

mysql8配置文件在[mysqld]后加下面代码 [mysqld] #MyISAM ft_min_word_len = 1 #InnoDB innodb_ft_min_token_size = 1 #ngram ngram_token_size = 1 重启了apache,然后给w_post建立索引 ALTER TABLE `w_post` ADD FULLTEXT(`title`) with parser ngram;
select id,title from w_post where match(title) against ('+笔记 +实现');

返回结果如下,排序前面的是包含笔记和实现的,然后是只包含笔记的,然后是只包含实现的

8d09d21404-qq-jie-tu20200410223735_normal.jpg

select id,title from w_post where match(title) against ('+笔记 +实现' in boolean mode);

返回结果如下,返回包含笔记和实现的。

f7a2de5e0f-qq-jie-tu20200410225227_normal.jpg

select id,title from w_post where match(title) against ('+"笔记" & +"实现"');

fad06cfcad-qq-jie-tu20200410231847_normal.jpg

select id,title from w_post where match(title) against ('+"笔记" & +"实现"' in boolean mode);

52af299999-qq-jie-tu20200410232013_normal.jpg

select id,title from w_post where match(title) against ('"笔记" & "实现"' in boolean mode);

e9542b069b-qq-jie-tu20200410232207_normal.jpg...

立即注册

mysql无组件中文全文索引,兼容各个版本,上亿数据亲测无压力

感觉这个思路好像不错,先切分为单个的汉字,但每个要查询的字段,都要建立一个对应的字段,数据量多了不少。20200410 2341

一直有人找我咨询全文索引问题,特别是sphinx问题。我给大家一个比sphinx更容易上手的方案:

一、原理

mysql较早版本不支持全文索引是因为字节切分问题,数据是二进制存储的,有的字符是2个字节,有的是3个或者4个,mysql无法精确的处理好切割位置。

我这个方案是定义切割字符,预先切割好数据存入数据库。

方案已经稳定使用6年,上过亿级数据,查询无压力和延时

二、直接给大家一个php语言写的案例

/*
表结构:
CREATE TABLE `full_text` (
  `id` int(11) NOT NULL,
  `text` mediumtext NOT NULL,
  `full_index` mediumtext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
ALTER TABLE `full_text` ADD PRIMARY KEY (`id`);
ALTER TABLE `full_text` ADD FULLTEXT KEY `full_index` (`full_index`);
ALTER TABLE `full_text` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
*/
define('FTS',"|");
//text为原文本,full_index为全文索引
//插入数据
$text = "《唐诗三百首》选诗范围相当广泛,收录了77家诗";
$text = toUtf8($text);//UTF8并非必要
$full_index = fullTextSplit($text,true);
$insert_sql = "INSERT INTO `full_text` (`id`, `text`, `full_index`) VALUES (NULL, '".$text."', '".$full_index."')";
echo $insert_sql,"\r\n";
//查询语句
$query_field = 'full_index';//索引字段
$query_single_word = '唐诗';
$query_sql = "SELECT * FROM `full_text` WHERE ".keyword2FullTextSql($query_single_word,$query_field);
echo $query_sql,"\r\n";
$query_multi_word = '唐诗 收录';
$query_sql = "SELECT * FROM `full_text` WHERE ".keyword2FullTextSql($query_multi_word,$query_field);
echo $query_sql,"\r\n";
//索引子串
function fullTextSplit($text,$wrap = false){
	if (!defined('FTS')) define('FTS', '|');
	$cind = 0;
	$new_text = FTS;
	for($i = 0; $i < strlen($text); $i++){
		if(strlen(substr($text, $cind, 1)) > 0){
			if(ord(substr($text, $cind, 1)) < 192){
				if(preg_match("/[a-zA-Z0-9\.]/",substr($text, $cind, 1))){
					$is_numeric = preg_match("/[0-9\.]/",substr($text, $cind, 1));
					if($cind  $is_numeric_next){
						$new_text .= substr($text, $cind, 1).FTS;
					}else{
						$new_text .= substr($text, $cind, 1);
					}					
				}else{
					$new_text .= FTS;
				}
				$cind++;
			}elseif(ord(substr($text, $cind, 1)) < 224) {
				$new_text .= FTS.substr($text, $cind, 2);		
				$cind+=2;
			}else{
				$new_text .= FTS.substr($text, $cind, 3).FTS;		
				$cind+=3;
			}
		}
	}
	$new_text = explode(FTS,$new_text);
	$new_text = arrayFilter($new_text);
	if($wrap){
		return FTS. implode(FTS,$new_text) .FTS;
	}else{
		return implode(FTS,$new_text);
	}
}
//查询sql
function keyword2FullTextSql($keyword,$field){
	$keyword = explode('|',$keyword);
	$keyword = array_unique(array_diff($keyword,array('',NULL,false)));
	$keyword_sql = array();
	if(!empty($keyword)){
		$return = '';
		foreach($keyword as $kw){
			$kw = explode(' ',$kw);
			$kw = array_unique(array_diff($kw,array('',NULL,false)));
			if(!empty($kw)){
				foreach($kw as $key => $val){
					$kw[$key] = '"'.fullTextSplit($val,true).'"';
				}
				$keyword_sql[] = ' MATCH(`'.$field.'`) AGAINST(\'+'.implode(' +',$kw).'\'  IN BOOLEAN MODE)';
			}
		}
	}
	if(!empty($keyword_sql)){
		return '('. implode(" OR ",$keyword_sql) .')';
	}else{
		return false;
	}
}
//转换编码(非必须)
function toUtf8($text,$ignore = false){
	if(is_array($text)){
		foreach($text as $k=>$v){
			$text[$k] = toUtf8($text[$k],$ignore);
		}
		return $text;
	}else{
		$charset = mb_detect_encoding($text,array('UTF-8','ASCII','EUC-CN','CP936','BIG-5','GB2312','GBK'));
		if ($charset != 'UTF-8' && !empty($charset)){
			@$text = mb_convert_encoding($text, "UTF-8", $charset);
		}else{
			@$text = mb_convert_encoding($text, "UTF-8", 'auto');
		}
		if($ignore) $text = iconv('UTF-8','UTF-8//IGNORE',$text);
		return preg_replace ( '/()/i', "\\1UTF-8\\3", $text, 1 );
	}
}
//数组过滤
function arrayFilter($array){
	$array = array_diff($array,array('',NULL,false));
	return $array;
}
\s+.+?content=".+?charset=)(.+?)("\s?\>($text)){>


...

立即注册

Yii2中使用order by locate的写法

orderBy([new Expression("locate(video_type_id, '$type_ids')")]) 这个很关键,原来Yii里是这样用函数的,nice 20200411

Yii

原生写法如下

select * from vd_video order by locate(video_type_id,'3,7,6') desc

Yii中写法如下...

立即注册

Yii2中自带分页类实现分页

Yii2中自带分页类实现分页

Yii2中自带分页类实现分页

1.首先写控制器层

先引用pagination类

use yii\data\Pagination;

写自己的方法:

function actionFenye(){ $data = Field::find(); //Field为model层,在控制器刚开始use了field这个model,这儿可以直接写Field,开头大小写都可以,为了规范,我写的是大写 $pages = new Pagination(['totalCount' =>$data->count(), 'pageSize' => '2']); //实例化分页类,带上参数(总条数,每页显示条数) $model = $data->offset($pages->offset)->limit($pages->limit)->all(); return $this->renderPartial('fenye',[ 'model' => $model, 'pages' => $pages, ]); }...

立即注册

用match查询yi和yii返回结果都是0条,索引用的是ngram

mysql配置 #MyISAM ft_min_word_len = 2 #InnoDB innodb_ft_min_token_size = 2 #ngram ngram_token_size = 2 索引建立的语句 ALTER TABLE `w_post` ADD FULLTEXT(`title`) with parser ngram;

//返回0条

select id,title from w_post where match(title) against ('Yii') or match(content_no_html) against ('Yii');

select id,title from w_post where match(title) against ('yii') or match(content_no_html) against ('yii');...

立即注册

更新于:2020-04-08 21:20:50
相关内容

查问我看笔记功能的实现过程

题外话 Yii 页面提示。 404错误,请求的页面不存在。含义是控制器的方法有,只是数据不存在。 404错误,页面未找到。含义是控制器的方法不存在。 好事多磨 20200405 1018 很尴尬,搞全文索引绕了个大圈子,开始用全文索引的Yii2扩展,各种坑,最后升级mysql5.7到mysql8,结果网站的数据库执行速度慢了0.3-0.5秒。 20200408 2...

代码要用的-增加查问我看笔记功能

查问我看笔记如何达到自己想要的效果

这里测试下多用户写笔记的效果

用超级用户运行composer require提示不要用超级用户运行composer

ActiveForm升阶-增加placeholder-自己在项目里搜到的代码

写着代码,听到了M2M - pretty Boy

提交表单提示:内容只能包含至多2,000个字符。于是改为5000

Yii2组件扩展Select2的优化问题

服务器上composer安装了Yii2的扩展yii-xunsearch支持中文全文索引搜索

关于代码遗漏更改的问题-以后要一起改

查问我看20200406整站代码已经上传到百度云

今天搞全文索引全文搜索

composer 使用composer install –no-scripts 报错了

网上查了下说composer install 的Symfony\Component\Console\Exception\RuntimeException报错要composer update

YII2 composer update 报错解决一例

composer global require "fxp/composer-asset-plugin"后composer update遇到的问题

composer update又出了问题,由于项目文件3年没用过composer安装扩展了,各种问题

查看composer的版本

composer 安装扩展时遇到的问题

mpdf/mpdf扩展又出问题

之前项目代码里有隐性的问题-composer去掉一些扩展引出的问题

删了yii2-swiftmailer后在重新用php composer.phar require --prefer-dist yiisoft/yii2-swiftmailer

深度浪漫-网站设计-url没有完成简洁

查问我看笔记功能的实现过程2

查问我看笔记功能的实现的重点就是全文搜索,如果不用Yii自带的ActiveRecord的话,就要找扩展,先找了个yii-xunsearch,不行太差了,又找了yiisoft/yii2-elasticsearch,看了下使用方法和网上的文章,感觉太复杂了。试试yiisoft/yii2-sphinx yiisoft/yii2-sphinx也坑了,安装很简单,一行代码,但...

yii-xunsearch全文搜索扩展的各种坑-于是果断到YiiFramework官网上找需要的

Yii的几个著名数据库相关的扩展介绍​MongoDB,ElasticSearch,Sphinx

这里把用的linux命令记录下

Sphinx Extension for Yii 2

Mysql全文索引查不到数据的问题

MySQL如何重建索引

mysql8使用自带全文索引(带中文分词)

PHP获取类名及所有函数名

查问我看笔记功能的实现之3

查问我看笔记功能的实现之4

查问我看代码维护记录

/*** htmlCutBegin() html截取前部分,返回的是格式正确的html 20180116* 后面再加上html的dom格式是否正确的检查 20180117 **** //增加类simple_html_dom存在的判断,代码严谨性更高 20210130* //增加了对象 is_countable的判断 20210130* @access* ...

做抽奖的时候,弹窗登录需要的css代码

查问我看帖子增加推荐功能

查问我看搜索时会遇到搜索不到的情况

后台的功能改变,帖子按照浏览次数DESC排序

Yii2 HTMLPurifier_Filter 屏蔽了 target=_blank

增加了把ip_record表的数据移到文件的功能

​本地运行查问我看遇到的问题(用的是phpstudy)

查问我看验证邮箱报错(原因:QQ授权码过期)

查问我看服务器维护记录

解决Apache长时间占用内存大的问题,Apache 内存优化方法 设置MaxRequestsPerChild或MaxConnectionsPerChild不为0
推荐内容

如何注册Spotify,注册中遇到的问题

起因是找阿特拉斯耸耸肩3里片尾的歌曲,后面用谷歌插件 aha music找到了歌曲名字和作曲人:The Beginning Elia Cmiral,然后资料在spotify有,于是就注册,甚至通过远程服务器,在服务器上打开浏览器也...

Spotify无法注册,想了很多办法后无果于是联系客服

Spotify无法注册,想了很多办法后无果于是联系客服

客服回答中国地区现在无法注册 If you still need help, contact Spotify Support.

mysql8使用自带全文索引(带中文分词)

如果之前建立全文索引,要先删除建立的索引,然后用下面的重新建立索引,亲测有效,nice 20200408 1307 ALTER TABLE `w_note` DROP INDEX content ALTER TABLE `w_note` ADD FULLT...

MySQL如何重建索引

总结一下MySQL索引重建的方法:1: DROP INDEX + RECREATE INDEX.2: ALTER TABLE方法3: REPAIR TABLE方法,这种方法对于InnoDB存储引擎的表无效。4: OPTI...

linux Centos8邮件服务器的搭建和使用

echo "content" | mail -s "title" xxx@gmail.com vi /etc/postfix/master.cf 更改配置文件把#smtps inet n - - - - smtpd 注释去掉 保存退出,重启postfix服务,报错 [root@vultrguest ~]# sudo systemctl restart ...

webmin和postfix