Búsqueda en lenguaje natural

El modo de lenguaje natural es el modo por defecto de MATCH() AGAINST(). Trata la cadena de búsqueda como una frase en lenguaje humano: MySQL divide la frase en palabras individuales, busca cada una en el índice full-text y calcula una puntuación de relevancia basada en la frecuencia de las palabras y su importancia estadística.

Sintaxis

-- Ambas son equivalentes
SELECT * FROM tabla WHERE MATCH(columna) AGAINST('texto de búsqueda');
SELECT * FROM tabla WHERE MATCH(columna) AGAINST('texto de búsqueda' IN NATURAL LANGUAGE MODE);

Preparación

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

Cómo funciona

  1. MySQL divide la cadena de búsqueda en palabras
  2. Elimina las stopwords y las palabras más cortas que el mínimo
  3. Busca cada palabra en el índice full-text
  4. Calcula la relevancia usando el algoritmo TF-IDF
  5. Devuelve las filas ordenadas por relevancia descendente

TF-IDF

La relevancia se calcula con TF-IDF:

ComponenteSignificadoEfecto
TFFrecuencia del términoMás apariciones = más relevante
IDFFrecuencia inversa del documentoPalabras raras = más relevantes

Una palabra que aparece en pocas filas tiene más peso que una que aparece en muchas. Si una palabra aparece en más del 50% de las filas, MySQL la trata como una stopword y la ignora.

Ejemplo básico

SELECT nombre, precio,
    MATCH(nombre, descripcion) AGAINST('portátil ligero') AS relevancia
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('portátil ligero');
nombrerelevancia
MacBook Air M30.8234
Lenovo ThinkPad X10.4521
ASUS ROG Zephyrus0.3876

"portátil" y "ligero" se buscan por separado. El MacBook Air M3 tiene la mayor relevancia porque su descripción menciona "ultraligero" y "portátil".

Buscar en reseñas

SELECT
    p.nombre AS producto,
    r.puntuacion,
    r.comentario,
    MATCH(r.comentario) AGAINST('calidad precio') AS relevancia
FROM resenas r
JOIN productos p ON r.producto_id = p.id
WHERE MATCH(r.comentario) AGAINST('calidad precio')
ORDER BY relevancia DESC;
productopuntuacioncomentariorelevancia
Xiaomi 144Buena relación calidad-precio0.7832
Camiseta algodón básica3Calidad aceptable por el precio0.6543

Regla del 50%

En modo de lenguaje natural, si una palabra aparece en más del 50% de las filas, MySQL la considera demasiado común y la ignora. Con solo 30 productos, esta regla puede ser notable:

-- Si buscamos una palabra muy común en las descripciones
SELECT COUNT(*) AS total,
    SUM(CASE WHEN descripcion LIKE '%de%' THEN 1 ELSE 0 END) AS con_de
FROM productos;
totalcon_de
3025

La palabra "de" aparece en el 83% de las descripciones, así que aunque no fuera una stopword, se ignoraría por la regla del 50%.

Múltiples palabras

Todas las palabras de la búsqueda se tratan como OR. MySQL devuelve filas que contienen al menos una de las palabras:

SELECT nombre
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('gaming pantalla procesador');
nombre
ASUS ROG Zephyrus
Samsung Galaxy S24
Google Pixel 8

Las filas que contienen más palabras de la búsqueda reciben mayor relevancia.

Frases no son exactas

En modo de lenguaje natural, MySQL no busca frases exactas. La búsqueda "cámara de 48MP" busca las palabras "cámara", "de" y "48MP" por separado:

SELECT nombre
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST('cámara de 48MP');

Para buscar frases exactas, usa el modo booleano con comillas dobles.

Limitaciones del modo natural

  • No soporta operadores como +, -, *
  • No permite búsqueda de frases exactas
  • Ignora palabras que aparecen en más del 50% de las filas
  • No funciona bien con tablas muy pequeñas por la regla del 50%
  • No se puede forzar que una palabra sea obligatoria

Limpieza

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

En el siguiente artículo veremos la búsqueda booleana, que ofrece operadores para controlar exactamente qué palabras deben o no aparecer.

Escrito por Eduardo Lázaro