MATCH AGAINST

MATCH() AGAINST() es la sintaxis para realizar búsquedas full-text en MySQL. MATCH() especifica las columnas donde buscar y AGAINST() especifica el texto a buscar y el modo de búsqueda. Devuelve una puntuación de relevancia que indica qué tan bien coincide cada fila con la búsqueda.

Sintaxis

SELECT columnas
FROM tabla
WHERE MATCH(columna1, columna2) AGAINST('texto de búsqueda' modo);

Los modos disponibles son:

ModoDescripción
Sin especificarLenguaje natural
IN NATURAL LANGUAGE MODELenguaje natural
IN BOOLEAN MODEModo booleano con operadores
WITH QUERY EXPANSIONExpansión de consulta

Preparación

Para los ejemplos de esta sección, creamos los índices full-text:

CREATE FULLTEXT INDEX ft_productos ON productos (nombre, descripcion);
CREATE FULLTEXT INDEX ft_resenas ON resenas (comentario);

Búsqueda básica

SELECT nombre, precio
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('smartphone cámara');
nombreprecio
iPhone 15 Pro1299.99
Samsung Galaxy S24899.99
Google Pixel 8699.00
Xiaomi 14599.99

MySQL busca las palabras "smartphone" y "cámara" en las columnas nombre y descripcion, y devuelve las filas que contienen al menos una de ellas, ordenadas por relevancia.

Puntuación de relevancia

MATCH() AGAINST() en el SELECT devuelve un número decimal que indica la relevancia:

SELECT
    nombre,
    MATCH(nombre, descripcion) AGAINST('smartphone cámara') AS relevancia
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('smartphone cámara')
ORDER BY relevancia DESC;
nombrerelevancia
iPhone 15 Pro0.6842
Samsung Galaxy S240.4521
Google Pixel 80.3218
Xiaomi 140.2987

Un valor mayor indica mayor relevancia. El cálculo considera la frecuencia de las palabras, su rareza en el conjunto de datos y la longitud del documento.

MATCH en WHERE y SELECT

Puedes usar MATCH() AGAINST() tanto en WHERE como en SELECT. MySQL optimiza esto para evaluar la expresión solo una vez:

SELECT
    nombre,
    precio,
    MATCH(nombre, descripcion) AGAINST('gaming') AS relevancia
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('gaming')
ORDER BY relevancia DESC;
nombrerelevancia
ASUS ROG Zephyrus0.7234

Combinar con otras condiciones

-- Full-text con filtro de precio
SELECT nombre, precio
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('portátil')
  AND precio < 1500;
nombreprecio
MacBook Air M31399.00
-- Full-text con JOIN
SELECT
    p.nombre AS producto,
    r.comentario,
    r.puntuacion,
    MATCH(r.comentario) AGAINST('bueno') AS relevancia
FROM resenas r
JOIN productos p ON r.producto_id = p.id
WHERE MATCH(r.comentario) AGAINST('bueno')
ORDER BY relevancia DESC;

MATCH con ORDER BY

Si usas MATCH() AGAINST() solo en el SELECT sin WHERE, MySQL no filtra pero puedes ordenar por relevancia:

SELECT
    nombre,
    MATCH(nombre, descripcion) AGAINST('cocina') AS relevancia
FROM productos
ORDER BY relevancia DESC
LIMIT 5;
nombrerelevancia
Robot de cocina0.8456
Sartén antiadherente 28cm0.3124
iPhone 15 Pro0.0000
Samsung Galaxy S240.0000
Google Pixel 80.0000

Sin WHERE, todas las filas se devuelven, pero las que contienen el término tienen relevancia mayor que cero.

Limitaciones de MATCH AGAINST

  • Las columnas en MATCH() deben coincidir exactamente con las de un índice FULLTEXT
  • No puedes mezclar columnas de diferentes tablas en un solo MATCH()
  • La puntuación de relevancia no es comparable entre diferentes consultas
  • Las palabras más cortas que innodb_ft_min_token_size se ignoran

Limpieza

DROP INDEX ft_productos ON productos;
DROP INDEX ft_resenas ON resenas;

En el siguiente artículo profundizaremos en la búsqueda en lenguaje natural, el modo por defecto de las búsquedas full-text.

Escrito por Eduardo Lázaro