MySQL 全文检索
MySQL 支持使用 LIKE 运算符和正则表达式进行文本搜索 。但是,当 text 列很大并且表中的行数增加时,使用这些方法有一些限制:
- 性能:MySQL 必须扫描整个表,以根据 LIKE 正则表达式中的语句或模式中的模式查找确切的文本。
- 灵活的搜索:通过 LIKE 运算符和正则表达式搜索,很难有灵活的搜索查询,例如,查找描述中包含 car 但不包含的产品 classic.
- 相关性排名:无法指定结果集中哪一行与搜索项更相关。
由于这些限制,MySQL 扩展了一个非常好的功能,即所谓的全文搜索。从技术上讲,MySQL 根据启用的全文搜索列的单词创建索引,并对此索引执行搜索。MySQL 使用复杂的算法来确定与搜索查询匹配的行。
以下是 MySQL 全文搜索的一些重要功能:
- SQL-LIKE 接口:您使用 SQL-LIKE 语句来使用全文搜索。
- 完全动态索引:只要列的数据发生更改,MySQL 就会自动更新文本列的索引。
- 中等索引大小:存储索引不需要太多内存。
- 最后但并非最不重要的是,基于复杂的搜索查询搜索速度很快。
注意:并非所有存储引擎都支持全文搜索功能。在 MySQL 5.6 或更高版本中,只有 MyISAM 和 InnoDB 存储引擎支持全文搜索。
在表的列中执行全文搜索之前,必须将其数据编入索引。只要列的数据发生变化,MySQL 就会重新创建全文索引。在 MySQL 中,全文索引是一种具有名称 FULLTEXT 的索引。
MySQL 支持 为启用全文搜索的列自动索引和重新索引数据 。MySQL 的 5.6 或更高版本允许你定义一个全文索引的数据类型为一列 CHAR,VARCHAR 或 TEXT 在 MyISAM 中或 InnoDB 的表型。请注意,自 5.6 版以来,MySQL 支持 InnoDB 表中的全文索引。
MySQL 允许你在为现有表创建表或 ALTER TABLE 或 CREATE INDEX 语句时使用 CREATE TABLE 语句定义 FULLTEXT 索引。
使用 CREATE TABLE 语句定义 FULLTEXT 索引
通常,FULLTEXT 使用以下 CREATE TABLE 语句创建新表时,可以为列定义索引:
CREATE TABLE table_name(
column1 data_type,
column2 data_type,
column3 data_type,
…
PRIMARY_KEY(key_column),
FULLTEXT (column1,column2,..)
);
要创建 FULLTEXT 索引,请在 FULLTEXT 关键字后面的括号中放置逗号分隔列的列表。
以下语句创建一个名为 posts 具有 FULLTEXT 包含 post_content 列的索引的新表。
CREATE TABLE posts (
id int(4) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
post_content text,
PRIMARY KEY (id),
FULLTEXT KEY post_content (post_content)
);
为现有表定义 FULLTEXT 索引
如果您已有现有表并想要定义全文索引,则可以使用 ALTER TABLE 语句或 CREATE INDEX 语句。
使用 ALTER TABLE 语句定义 FULLTEXT 索引
以下语法 FULLTEXT 使用以下语句定义索引 ALTER TABLE:
ALTER TABLE table_name
ADD FULLTEXT(column_name1, column_name2,…)
在此语法中,你将使用 table_name 和 ADD FULLTEXT 子句定义 FULLTEXT 一个或多个列的索引。
例如,你可以 FULLTEXT 为示例数据库的表中的 productDescription 和 productLine 列定义索引,如下所示:products
ALTER TABLE products
ADD FULLTEXT(productDescription,productLine);
使用 CREATE INDEX 语句定义 FULLTEXT 索引
您还可以使用 CREATE INDEX 语句为现有表创建 FULLTEXT 索引。请参阅以下语法:
CREATE FULLTEXT INDEX index_name
ON table_name(idx_column_name,...)
以下语句 FULLTEXT 为表的列 addressLine1 和 addressLine2 列创建索引 offices。
CREATE FULLTEXT INDEX address
ON offices(addressLine1,addressLine2);
请注意,对于具有多行的表,将数据加载到 FULLTEXT 首先没有索引的表中然后创建 FULLTEXT 索引比将大量数据加载到具有现有 FULLTEXT 索引的表中更快。
删除全文搜索列
要删除 FULLTEXT 索引,只需使用 ALTER TABLE … DROP INDEX 语句删除索引即可。例如,以下语句删除表中的索引:address FULLTEXT offices
ALTER TABLE offices
DROP INDEX address;
MySQL 自然语言全文搜索简介
在自然语言全文搜索中,MySQL 查找与自由文本自然人类语言查询相关的行或文档,例如,“如何使用 MySQL 自然语言全文搜索”。
相关性是一个正浮点数。当相关性为零时,意味着没有相似性。MySQL 根据各种因素计算相关性,包括文档中的单词数,文档中唯一单词的数量,集合中单词的总数以及包含特定单词的文档(行)数。
要执行自然语言全文搜索,请使用 MATCH() 和 AGAINST() 运行。MATCH() 函数指定要搜索的列,AGAINST() 函数确定要使用的搜索表达式。
MySQL 自然语言全文搜索示例
我们将使用示例数据库中的 products 表进行演示。
+--------------------+
| products |
+--------------------+
| productCode |
| productName |
| productLine |
| productScale |
| productVendor |
| productDescription |
| quantityInStock |
| buyPrice |
| MSRP |
+--------------------+
9 rows in set (0.00 sec)
首先,你需要 使用以下 ALTER TABLE ADD FULLTEXT语句在 products 表的 productLine 列中启用全文搜索:
ALTER TABLE products
ADD FULLTEXT(productline);
其次,你可以搜索其产品系列包含术语的产品 Classic 。你使用 MATCH() 和 AGAINST() 函数作为以下查询:
SELECT productName, productline
FROM products
WHERE MATCH(productline) AGAINST('Classic');
+-------------------------------------+--------------+
| productName | productline |
+-------------------------------------+--------------+
| 1952 Alpine Renault 1300 | Classic Cars |
| 1972 Alfa Romeo GTA | Classic Cars |
| 1962 LanciaA Delta 16V | Classic Cars |
| 1968 Ford Mustang | Classic Cars |
| 2001 Ferrari Enzo | Classic Cars |
| 1969 Corvair Monza | Classic Cars |
| 1968 Dodge Charger | Classic Cars |
| 1969 Ford Falcon | Classic Cars |
| 1970 Plymouth Hemi Cuda | Classic Cars |
| 1969 Dodge Charger | Classic Cars |
...
要搜索其产品系列包含 Classic 或 Vintage 术语的产品,你可以执行以下查询:
SELECT productName, productline
FROM products
WHERE MATCH(productline) AGAINST('Classic,Vintage');
+-------------------------------------------+--------------+
| productName | productline |
+-------------------------------------------+--------------+
| 1937 Lincoln Berline | Vintage Cars |
| 1936 Mercedes-Benz 500K Special Roadster | Vintage Cars |
| 1917 Grand Touring Sedan | Vintage Cars |
| 1911 Ford Town Car | Vintage Cars |
| 1932 Model A Ford J-Coupe | Vintage Cars |
| 1928 Mercedes-Benz SSK | Vintage Cars |
| 1913 Ford Model T Speedster | Vintage Cars |
| 1934 Ford V8 Coupe | Vintage Cars |
| 18th Century Vintage Horse Carriage | Vintage Cars |
| 1903 Ford Model A | Vintage Cars |
| 1917 Maxwell Touring Car | Vintage Cars |
| 1941 Chevrolet Special Deluxe Cabriolet | Vintage Cars |
| 1932 Alfa Romeo 8C2300 Spider Sport | Vintage Cars |
| 1904 Buick Runabout | Vintage Cars |
| 1939 Cadillac Limousine | Vintage Cars |
| 1939 Chevrolet Deluxe Coupe | Vintage Cars |
| 1938 Cadillac V-16 Presidential Limousine | Vintage Cars |
| 1912 Ford Model T Delivery Wagon | Vintage Cars |
| 1937 Horch 930V Limousine | Vintage Cars |
| 1940 Ford Delivery Sedan | Vintage Cars |
| 1936 Mercedes Benz 500k Roadster | Vintage Cars |
| 1936 Chrysler Airflow | Vintage Cars |
| 1928 Ford Phaeton Deluxe | Vintage Cars |
| 1930 Buick Marquette Phaeton | Vintage Cars |
| 1952 Alpine Renault 1300 | Classic Cars |
| 1972 Alfa Romeo GTA | Classic Cars |
...
AGAINST() 函数默认使用 IN NATURAL LANGUAGE MODE 搜索修饰符,因此你可以在查询中省略它。还有其他搜索修饰符,例如,IN BOOLEAN MODE 用于布尔文本搜索。
你可以在查询中明确使用 IN NATURAL LANGUAGE MODE 搜索修饰符,如下所示:
SELECT productName, productline
FROM products
WHERE MATCH(productline)
AGAINST('Classic,Vintage' IN NATURAL LANGUAGE MODE);
默认情况下,MySQL 以不区分大小写的方式执行搜索。但是,你可以指示 MySQL 使用二进制排序规则对索引列执行区分大小写的搜索。
按相关性对结果集进行排序
全文搜索的一个非常重要的特性是 MySQL 如何根据结果集的相关性对结果集中的行进行排名。MATCH() 在 WHERE 子句中使用函数时,MySQL 首先返回更相关的行。
以下示例显示 MySQL 如何按相关性对结果集进行排序。
首先,为表的 productName 列启用全文搜索功能 products。
ALTER TABLE products
ADD FULLTEXT(productName);
其次,搜索名称包含 Ford 和/或 1932 使用以下查询的产品:
SELECT productName, productline
FROM products
WHERE MATCH(productName) AGAINST('1932,Ford');
让我们来看看输出:
+-------------------------------------+------------------+
| productName | productline |
+-------------------------------------+------------------+
| 1932 Model A Ford J-Coupe | Vintage Cars |
| 1932 Alfa Romeo 8C2300 Spider Sport | Vintage Cars |
| 1968 Ford Mustang | Classic Cars |
| 1969 Ford Falcon | Classic Cars |
| 1940 Ford Pickup Truck | Trucks and Buses |
| 1911 Ford Town Car | Vintage Cars |
| 1926 Ford Fire Engine | Trucks and Buses |
| 1913 Ford Model T Speedster | Vintage Cars |
| 1934 Ford V8 Coupe | Vintage Cars |
| 1903 Ford Model A | Vintage Cars |
| 1976 Ford Gran Torino | Classic Cars |
| 1940s Ford truck | Trucks and Buses |
| 1957 Ford Thunderbird | Classic Cars |
| 1912 Ford Model T Delivery Wagon | Vintage Cars |
| 1940 Ford Delivery Sedan | Vintage Cars |
| 1928 Ford Phaeton Deluxe | Vintage Cars |
+-------------------------------------+------------------+
16 rows in set (0.00 sec)
产品其名称中包含两个1932 和 Ford 先返回,然后他们的名字中包含的不仅是产品 Ford 关键字。
使用全文搜索时,你应记住以下几点:
- 在 MySQL 全文搜索引擎定义的搜索词的最小长度为 4。这意味着,如果你搜索其长度小于 4 例如关键字 car,cat 等等,你不会得到任何结果。
- 停用词被忽略。MySQL 定义了 MySQL 源代码分发中的停用词列表 storage/myisam/ft_static.c
在本教程中,已经向你展示了如何使用 MATCH() 和 AGAINST() 函数在 MySQL 中执行自然语言搜索。