Búsquedas FULLTEXT en MySQL.

Resumen.

Ya hemos visto una forma de realizar búsquedas en nuestra base de datos con LIKE, y también hemos visto que si no hay algún tipo de coincidencia exacta, no hay resultados para la búsqueda. Ahora, veremos como realizar lo que podríamos llamar una búsqueda “semántica”, es decir, lo mas parecido a como realizan las búsquedas Google, Bing y otros grandes buscadores. Pero no nos quedaremos solo en eso, montaremos LIKE y FULLTEXT en la misma página para así tener el buscador “perfecto”.

Artículo.

Si hay algo que es frustrante para un usuario que entra en una Web es usar el buscador y que no de resultados o bien que de un gran listado inconexo con el criterio de búsqueda.

Si bien las búsquedas con LIKE requieren un cierto tipo de campos en nuestra base de datos, las búsquedas FULLTEXT precisan también estos mismos tipos de campos (CHAR, VARCHAR, o TEXT). También tiene otras particularidades, como son:

1) No da resultados si el criterio de búsqueda no tiene al menos 3 caracteres.
2) Si la consulta da el 50% o mas resultados de la tabla, no mostrará respuesta.
3) Las búsquedas son insensibles a mayúsculas y minúsculas.
4) No precisa una exactitud entre los caracteres buscados y los encontrados, por eso nos gusta llamarlo “búsqueda semántica”, aunque queda muy lejos de considerar sinónimos. Pero si puede encontrar de manera eficaz frases cortas con las mismas palabras aunque su orden sea diferente.
5) Las búsquedas FULLTEXT solo son validas en tablas tipo MyISAM, tipo este que asignaremos cuando creamos la tabla en phpMyAdmin.
6) En las búsquedas FULLTEXT no debemos asignar (a menos que tengamos un buen motivo para ello) orden a los resultados, el típico “ORDER BY”, ya que con este tipo de índice se le asigna un orden por relevancia a los resultados. Por ejemplo, si buscamos entre nuestros clientes los apellidos “González Pérez”, primero nos aparecerán los “González Pérez”, y tras ellos, nos aparecerían los “Pérez González”, por ultimo aparecerían las combinaciones de estos apellidos con otros: González García, Pérez Sánchez, etc. Si buscamos en un texto, por ejemplo, “bucles en PHP”, y tenemos tres artículos que tratan ese tema, primero mostrará el artículo donde más apariciones tiene la búsqueda. Todo esto le confiere a este tipo de búsquedas un enorme potencial que debemos aprovechar al máximo.

Otro detalle fundamental para poder efectuar este tipo de búsquedas es que el campo (o campos) de nuestra tabla donde realizamos las búsquedas deben tener asignado el índice FULLTEXT, lo que se hace en el momento de la creación de la tabla, en phpMyAdmin.

En cuanto al uso de este tipo de búsquedas, no pensemos que es la solución perfecta para todo, por lo que si el objetivo de las búsquedas es algo como nombres de usuario, direcciones de e-mail, números de teléfono o de pedidos, referencias de artículos, probablemente sea más práctico usar LIKE.

Las búsquedas FULLTEXT quedarían mas reservadas para buscar cadenas de palabras, como las típicas que podemos usar para buscar en este sitio Web, por ejemplo: conectarse a base de datos, crear función PHP, obtener fecha en PHP, buscar en base de datos, tipos de bucles PHP, etc.

Otro detalle que debemos tener en cuenta es que en una misma página podemos tener montados de manera simultánea el buscador con LIKE y con FULLTEXT. Para ello nos bastaría con crear un condicional que discrimine sobre el criterio de búsqueda, algo así como este:

<?php
// Condicional para buscar con LIKE o FULLTEXT
$busca = 'una busqueda';

switch($busca){

case strlen($busca) < 2 AND @stristr($busca, '') === TRUE:
// No realizamos busqueda
echo "<b>$busca</b> Sin busqueda 1";
break;

case strlen($busca) >= 2 AND stristr($busca, ' ') === FALSE:
// Busqueda con LIKE
echo "<b>$busca</b> Con LIKE";
break;

case strlen($busca) > 3 AND stristr($busca, ' ') <> FALSE:
// Busqueda con FULLTEXT
echo "<b>$busca</b> Con FULLTEXT";
break;

default:
// No realizamos busqueda
echo "<b>$busca</b> Sin busqueda 2";
break;
}
?>


En el primer “case” determinamos que si el criterio de búsqueda tiene menos de dos caracteres y ningún espacio en blanco, no se realizará ninguna búsqueda, colocaríamos ahí una consulta típica de paginación. Algo así como:

$_pagi_sql = "SELECT * FROM $tb2 ORDER BY id DESC";


En el segundo “case” determinamos que hay dos o mas caracteres y no existen espacios en blanco, en cuyo caso realizamos una búsqueda con LIKE, algo así como esto:

$_pagi_sql = " SELECT * FROM $tb2 WHERE usuario LIKE '%$busca%' ";


En el tercer “case” determinamos que el criterio de búsqueda tiene mas de tres caracteres y existen espacios en blanco (por tanto, mas de una palabra). Este seria el caso de la búsqueda FULLTEXT, y nuestra consulta podría tomar la siguiente forma:

$_pagi_sql = "SELECT * FROM $tb2 WHERE MATCH(articulo) AGAINST('$busca')";


Por ultimo, en “default” colocamos la misma consulta “sin búsqueda” con que iniciamos el condicional.

Como ya dijimos en el artículo dedicado a las búsquedas con LIKE, con solo cambiar la consulta, es decir modificar la variable $_pagi_sql, ya tenemos nuestro buscador FULLTEXT en marcha, lógicamente modificando el nombre de los campos, dado que en la tabla referenciada en ese artículo no tiene mucho sentido este tipo de búsqueda. El condicional con las consultas quedaría de la siguiente manera:

switch($busca){
case strlen($busca) < 2 AND @stristr($busca, '') === TRUE:
// No realizamos busqueda
$_pagi_sql = "SELECT * FROM $tb2 ORDER BY id DESC";
break;

case strlen($busca) >= 2 AND stristr($busca, ' ') === FALSE:
// Busqueda con LIKE
$_pagi_sql = "SELECT * FROM $tb2 WHERE articulo LIKE '%$busca%'";
break;

case strlen($busca) > 3 AND stristr($busca, ' ') <> FALSE:
// Busqueda con FULLTEXT
$_pagi_sql = "SELECT * FROM $tb2 WHERE MATCH(articulo) AGAINST('$busca')";
break;

default:
// No realizamos busqueda
$_pagi_sql = "SELECT * FROM $tb2 ORDER BY id DESC";
break;
}
$_pagi_result = mysqli_query($Conex_BD, $_pagi_sql);
...


En este mismo sitio Web en que estas ahora hemos usado estos criterios para configurar el método de paginado y el uso combinado de las búsquedas LIKE y FULLTEXT, a vuestro criterio queda si el resultado ofrecido está a la altura de lo que esperáis para vuestro sitio Web.

Al igual que con las búsquedas con LIKE, con FULLTEXT también podemos buscar en mas de un campo, lo que haremos de la siguiente forma:

$_pagi_sql = "SELECT * FROM $tb2 WHERE MATCH(articulo) AGAINST('$busca') OR MATCH(fra_clave) AGAINST('$busca')";


Para las búsquedas FULLTEXT precisamos de sentencias, MARCH para marcar el campo de la tabla donde se realizará la búsqueda, y AGAINST para designar la cadena o string a buscar.

Como podéis ver en esta consulta hemos usado el operador lógico OR y no AND, ya que si usásemos este último, solo nos daría resultados si estuviera en los dos campos la cadena buscada. Es decir, este tipo de búsqueda debe estar muy bien planificada para obtener los resultados deseados, ya que la elección inadecuada de campos, o el uso de un operador lógico inadecuado, va a condicionar de forma radical los resultados de nuestras búsquedas.

De lo dicho podemos sacar conclusiones respecto a como realizan las búsquedas los grandes buscadores como Google. Si un dato no está donde se supone que debe estar, el resultado no será el mismo que si está donde debiera, de ahí que unas Web logren posicionamientos mejores que otras aún con los “mismos” contenidos.

Al igual que dijimos con el buscador con LIKE, sobre el código de paginación solo tenemos que modificar la variable $_pagi_sql y ya tenemos nuestro buscador FULLTEXT paginado.

Para ir concluyendo diremos que si bien las búsquedas con LIKE están claramente definidas en cuanto a que resultados darán, las búsquedas con FULLTEXT son bastante mas complejas, y los resultados que vamos a obtener van a estar muy condicionados por el contenido de los campos donde realizamos las búsquedas. En este sentido cabe decir que podemos requerir a “trucos” según la configuración de nuestra tabla.

Imaginemos un blog donde solo tenemos dos campos de texto, uno para el titulo de la publicación y otro para la publicación propiamente dicha. En este caso una consulta como la propuesta anteriormente podría ser perfecta. Pero ¿qué ocurría sin quisiéramos realizar la búsqueda en un blog que contiene además del titulo y el artículo, un resumen, otro con la meta frases clave, otro dedicado a tags y otro mas con referencias, agradecimientos…?

En un caso así nos enfrentaríamos a un consulta un tanto extensa, que la podríamos simplificar de una manera simple a un solo campo, es decir, el contenido de todos esos campos en los que queremos buscar, los guardaríamos en uno solo, sobre el que realizaríamos las búsquedas. Esto lo haríamos de la siguiente manera:

$todo_texto = strip_tags($title.$titulo.$resumen.$articulo.$frases_calve.$tags);


Lo que hemos hecho ha sido unir todos los campos en uno solo, y le hemos aplicado la función strip_tags() para eliminar todas las etiquetas, como estilos CSS, imágenes, link, etc. reduciendo así el contenido de ese campo.

De esta forma nuestra consulta quedaría tan sencilla como:

$_pagi_sql = "SELECT * FROM $tb2 WHERE MATCH(todo_texto) AGAINST('$busca')";


El “problema” de este “truco” es que puede aumentar considerablemente el tamaño de la tabla, pero es una opción que merece tener presente. Aquí la dejo, y es cosa vuestra evaluar si para vuestro caso, esta opción merece ser considerada.

Por ultimo indicar que, en lo relativo a las búsquedas es muy importante que la codificación de la base de datos y de la página sea la misma, que para nuestro idioma, español, lo ideal es UTF-8. Con el uso de diferentes tipos de codificación nos pueden surgir problemas en las búsquedas relacionados con las tildes y la “ñ”.

Y esto es todo, aunque queda mucho más que descubrir sobre este tipo de búsquedas tan tremendamente potentes y que merece la pena explorar.
Tags: FULLTEXT || MATCH || AGAINST || búsqueda || LIKE || MyISAM

Comentarios.

Sin comentarios, publica el tuyo.