MySQL - 全文搜索



MySQL 的全文搜索允许我们搜索存储在数据库中的文本数据。在对表的列执行全文搜索之前,我们必须在这些列上创建全文索引。

FTS(全文搜索)提供了匹配搜索字符串值的能力,这些值通过大型文本内容(如博客、文章等)进行搜索。

要在 MySQL 表上执行全文搜索,我们在 SQL SELECT 语句的 WHERE 子句中使用 MATCH() 和 AGAINST() 函数。

停用词是在句子中常用的词(例如“on”、“the”、“or”、“it”),在搜索过程中会被忽略。

在 MySQL 上执行全文搜索的基本语法如下:

SELECT column_name(s) FROM table_name 
WHERE MATCH(col1, col2, ...) 
AGAINST(expression [search_modifier])

这里,

  • MATCH() 函数包含一个或多个用逗号分隔的要搜索的列。
  • AGAINST() 函数包含用于全文搜索的搜索字符串。

MySQL 全文搜索的关键点

以下是关于 MySQL 中全文搜索的一些关键点:

  • InnoDB 或 MyISAM 表都使用全文索引。对于 InnoDB 表,全文搜索的单词最小长度为三个字符,对于 MyISAM 表,则为四个字符。
  • 可以在基于文本的列(CHAR、VARCHAR 或 TEXT 列)上创建全文索引。
  • 可以在使用 CREATE TABLE 语句创建表时定义 FULLTEXT 索引,也可以稍后使用 ALTER TABLE 或 CREATE INDEX 语句定义。
  • 如果没有 FULLTEXT 索引,将大型数据集加载到表中的速度比加载到具有现有 FULLTEXT 索引的表中的速度更快。因此,建议在加载数据后创建索引。

全文搜索的类型

全文搜索有三种类型。下面将详细介绍:

  • 自然语言全文搜索:允许用户以自然的语言输入搜索查询,无需任何特殊字符或运算符。搜索引擎将检查用户输入的查询,并根据用户的意图返回相关结果。
  • 布尔全文搜索:允许我们使用布尔模式以及布尔运算符(如 +、-、>、<、()、~、*、"")执行非常复杂的查询的全文搜索。
  • 查询扩展搜索:基于自动相关反馈或盲查询扩展,扩展用户的查询以扩大全文搜索的搜索结果。

创建 MySQL FULLTEXT 索引

在 MySQL 中,我们可以在创建新表时或在现有表上定义特定列上的全文索引。这可以通过三种方式完成:

  • 使用 FULLTEXT 关键字

  • 使用 ALTER TABLE 语句

  • 使用 CREATE INDEX 语句

使用 FULLTEXT 关键字

要在创建新表时在列上定义全文索引,我们在 CREATE TABLE 查询中该列内使用 FULLTEXT 关键字。以下是语法:

CREATE TABLE table_name(  
   column1 data_type,  
   column2 data_type,
   ...,
   FULLTEXT (column1, column2, ...)  
);
示例

让我们首先创建一个名为FILMS的表,并在 NAME 和 DIRECTOR 列上定义全文索引,使用以下查询:

CREATE TABLE FILMS (
   ID int auto_increment not null primary key,
   NAME varchar(50),
   DIRECTOR TEXT,
   FULLTEXT (NAME, DIRECTOR)
);

现在,让我们使用以下查询将值插入此表:

INSERT INTO FILMS (NAME, DIRECTOR) VALUES 
('RRR', 'Directed by Rajamouli'),
('Bahubali', 'Directed by Rajamouli'),
('Avatar', 'Directed by James cameron'),
('Robot', 'Directed by Shankar');

表将被创建为:

ID NAME DIRECTOR
1 RRR 由 Rajamouli 执导
2 巴霍巴利王 由 Rajamouli 执导
3 阿凡达 由 James Cameron 执导
4 机器人 由 Shankar 执导

在这里,我们使用 MATCH 和 AGAINST 函数获取 FILMS 表中 NAME 或 DIRECTOR 列与字符串“Rajamouli”匹配的所有行,如下所示:

SELECT * FROM FILMS 
WHERE MATCH (NAME, DIRECTOR) 
AGAINST ('Rajamouli');
输出

从下面的输出中可以看到,全文搜索已针对字符串“Rajamouli”执行,并返回包含此字符串的行。

ID NAME DIRECTOR
1 RRR 由 Rajamouli 执导
2 巴霍巴利王 由 Rajamouli 执导

使用 ALTER TABLE 语句

在 MySQL 中,我们可以使用 ALTER TABLE 语句在现有表的特定列上创建全文索引。以下是语法:

ALTER TABLE table_name    
ADD FULLTEXT (column1, column2,...)
示例

在此示例中,我们在之前创建的 FILMS 表的 NAME 和 DIRECTOR 列上定义了一个名为 FULLTEXT 的全文索引:

ALTER TABLE FILMS ADD FULLTEXT (NAME, DIRECTOR);

现在,让我们检索 FILMS 表中 NAME 或 DIRECTOR 列与字符串“Shankar”匹配的所有行。

SELECT * FROM FILMS 
WHERE MATCH (NAME, DIRECTOR) 
AGAINST ('Shankar');
输出

以下是输出:

ID NAME DIRECTOR
4 机器人 由 Shankar 执导

使用 CREATE INDEX 语句

在 MySQL 中,我们也可以使用 CREATE INDEX 语句为现有表创建全文索引。以下是语法:

CREATE FULLTEXT INDEX index_name  
ON table_name (index_column1, index_column2,...)
示例

我们正在为 FILMS 表的 NAME 和 DIRECTOR 列创建名为 INDEX_FULLTEXT 的全文索引:

CREATE FULLTEXT INDEX INDEX_FULLTEXT ON FILMS (NAME, DIRECTOR);

现在,让我们检索 FILMS 表中 NAME 或 DIRECTOR 列与以下查询中所示的字符串值匹配的所有行:

SELECT * FROM FILMS 
WHERE MATCH(NAME, DIRECTOR) 
AGAINST ('James Cameron');
输出

以下是输出:

ID NAME DIRECTOR
3 阿凡达 由 James Cameron 执导

删除 MySQL FULLTEXT 索引

在 MySQL 中,我们可以使用 ALTER TABLE DROP INDEX 语句从表中删除或丢弃全文索引。

语法

以下是语法:

ALTER TABLE table_name DROP INDEX index_name; 
示例

在以下查询中,我们将删除之前创建的全文索引:

ALTER TABLE FILMS DROP INDEX INDEX_FULLTEXT;
验证

让我们通过执行以下查询来验证索引是否已删除:

SELECT * FROM FILMS 
WHERE MATCH(NAME, DIRECTOR) 
AGAINST ('James Cameron');

正如我们在输出中看到的,NAME 和 DIRECTOR 列上的全文索引已被删除。

ERROR 1191 (HY000): Can't find FULLTEXT index matching the column list

使用客户端程序进行全文搜索

除了使用 MySQL 查询执行全文搜索外,我们还可以使用客户端程序执行全文搜索。

语法

要在 PHP 程序中对 MySQL 数据库执行全文搜索,我们需要使用 mysqli 函数 query() 执行 CREATE TABLE 语句,如下所示:

$sql = "CREATE TABLE FILMS (ID int auto_increment not null primary key, NAME varchar(50), DIRECTOR TEXT, FULLTEXT (NAME, DIRECTOR) )";
$mysqli->query($sql);

要在 JavaScript 程序中对 MySQL 数据库执行全文搜索,我们需要使用 mysql2 库的 query() 函数执行 CREATE TABLE 语句,如下所示:

sql = "CREATE TABLE FILMS (ID int auto_increment not null primary key, NAME varchar(50), DIRECTOR TEXT, FULLTEXT (NAME, DIRECTOR) )";
con.query(sql);

要在 Java 程序中对 MySQL 数据库执行全文搜索,我们需要使用 JDBC 函数 execute() 执行 CREATE TABLE 语句,如下所示:

String sql = "CREATE TABLE FILMS (ID int auto_increment not null primary key, NAME varchar(50), DIRECTOR TEXT, FULLTEXT (NAME, DIRECTOR) )";
statement.execute(sql);

要在 Python 程序中对 MySQL 数据库执行全文搜索,我们需要使用 MySQL Connector/Pythonexecute() 函数执行 CREATE TABLE 语句,如下所示:

fulltext_search_query = "SELECT * FROM FILMS WHERE MATCH (NAME, DIRECTOR) AGAINST ('Rajamouli')"
cursorObj.execute(fulltext_search_query)

示例

以下是程序:

$dbhost = 'localhost';
$dbuser = 'root';
$dbpass = 'password';
$dbname = 'TUTORIALS';
$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
if ($mysqli->connect_errno) {
    printf("Connect failed: %s
", $mysqli->connect_error); exit(); } // printf('Connected successfully.
'); //creating a table films that stores fulltext. $sql = "CREATE TABLE FILMS (ID int auto_increment not null primary key, NAME varchar(50), DIRECTOR TEXT, FULLTEXT (NAME, DIRECTOR) )"; $result = $mysqli->query($sql); if ($result) { printf("Table created successfully...!\n"); } //insert data $q = "INSERT INTO FILMS (NAME, DIRECTOR) VALUES ('RRR', 'The film RRR is directed by Rajamouli'), ('Bahubali', 'The film Bahubali is directed by Rajamouli'), ('Avatar', 'The film Avatar is directed by James cameron'), ('Robot', 'The film Robot is directed by Shankar')"; if ($res = $mysqli->query($q)) { printf("Data inserted successfully...!\n"); } //now display the table records $s = "SELECT * FROM FILMS WHERE MATCH (NAME, DIRECTOR) AGAINST ('Rajamouli')"; if ($r = $mysqli->query($s)) { printf("Table Records: \n"); while ($row = $r->fetch_assoc()) { printf(" ID: %d, Name: %s, Director: %s", $row["ID"], $row["NAME"], $row["DIRECTOR"]); printf("\n"); } } else { printf('Failed'); } $mysqli->close();

输出

获得的输出如下所示:

Table created successfully...!
Data inserted successfully...!
Table Records:
 ID: 1, Name: RRR, Director: The film RRR is directed by Rajamouli
 ID: 2, Name: Bahubali, Director: The film Bahubali is directed by Rajamouli  
var mysql = require("mysql2");
var con = mysql.createConnection({
  host: "localhost",
  user: "root",
  password: "password",
}); //Connecting to MySQL

con.connect(function (err) {
  if (err) throw err;
  //   console.log("Connected successfully...!");
  //   console.log("--------------------------");
  sql = "USE TUTORIALS";
  con.query(sql);

  sql = "CREATE TABLE FILMS (ID int auto_increment not null primary key, NAME varchar(50), DIRECTOR TEXT, FULLTEXT (NAME, DIRECTOR) )";
  con.query(sql);

  //insert data into created table
  sql = `INSERT INTO FILMS (NAME, DIRECTOR)
  VALUES ('RRR', 'The film RRR is directed by Rajamouli'),
  ('Bahubali', 'The film Bahubali is directed by Rajamouli'),
  ('Avatar', 'The film Avatar is directed by James cameron'),
  ('Robot', 'The film Robot is directed by Shankar')`;
  con.query(sql);

  //display the table details!...
  sql = `SELECT * FROM FILMS WHERE MATCH (NAME, DIRECTOR) AGAINST ('Rajamouli')`;
  con.query(sql, function (err, result) {
    if (err) throw err;
    console.log(result);
  });
});  

输出

获得的输出如下所示:

[
  {
    ID: 1,
    NAME: 'RRR',
    DIRECTOR: 'The film RRR is directed by Rajamouli'
  },
  {
    ID: 2,
    NAME: 'Bahubali',
    DIRECTOR: 'The film Bahubali is directed by Rajamouli'
  }
]   
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class FulltextSearch {
   public static void main(String[] args) {
      String url = "jdbc:mysql://127.0.0.1:3306/TUTORIALS";
      String username = "root";
      String password = "password";
      try {
         Class.forName("com.mysql.cj.jdbc.Driver");
         Connection connection = DriverManager.getConnection(url, username, password);
         Statement statement = connection.createStatement();
         System.out.println("Connected successfully...!");

         //creating a table that takes fulltext column...!
         String sql = "CREATE TABLE FILMS (ID int auto_increment not null primary key, NAME varchar(50), DIRECTOR TEXT, FULLTEXT (NAME, DIRECTOR) )";
         statement.execute(sql);
         System.out.println("Table created successfully...!");

         //inserting data to the tables
         String insert = "INSERT INTO FILMS (NAME, DIRECTOR) VALUES ('RRR', 'The film RRR is directed by Rajamouli'), ('Bahubali', 'The film Bahubali is directed by Rajamouli')," +
                 "('Avatar', 'The film Avatar is directed by James cameron'), ('Robot', 'The film Robot is directed by Shankar')";
         statement.execute(insert);
         System.out.println("Data inserted successfully...!");

         //displaying the table records...!
         ResultSet resultSet = statement.executeQuery("SELECT * FROM FILMS WHERE MATCH (NAME, DIRECTOR) AGAINST ('Rajamouli')");
         while (resultSet.next()){
            System.out.println(resultSet.getString(1)+" "+resultSet.getString(2)+ " "+resultSet.getString(3));
         }
         connection.close();
      } catch (Exception e) {
         System.out.println(e);
      }
   }
}      

输出

获得的输出如下所示:

Connected successfully...!
Table created successfully...!
Data inserted successfully...!
1 RRR The film RRR is directed by Rajamouli
2 Bahubali The film Bahubali is directed by Rajamouli  
import mysql.connector
# Establishing the connection
connection = mysql.connector.connect(
    host='localhost',
    user='root',
    password='password',
    database='tut'
)
# Creating a cursor object
cursorObj = connection.cursor()
fulltext_search_query = f"SELECT * FROM FILMS WHERE MATCH (NAME, DIRECTOR) AGAINST ('Rajamouli');"
cursorObj.execute(fulltext_search_query)
# Fetching all the results
results = cursorObj.fetchall()
# Display the result
print("Full-text search results:")
for row in results:
    print(row)
cursorObj.close()
connection.close()         

输出

获得的输出如下所示:

Full-text search results:
(1, 'RRR', 'The film RRR is directed by Rajamouli')
(2, 'Bahubali', 'The film Bahubali is directed by Rajamouli')
广告