Esta es una de las cosas que más deseaba hacer cuando comencé a programar y realmente creía que era bien difícil, pero no, es extremadamente fácil y lo puedes hacer en solo minutos.
Introducción:
En nuestro ejemplo, tendremos una tabla en la Base de Datos del tipo MyISAM, ya que este motor soporta Funciones de búsqueda de texto completo (Full-Text). La tabla en si seria en donde guardaríamos las noticias de nuestro sitio web y la búsqueda la vamos a hacer en los campos Titulo y Cuerpo de la Noticia, por lo tanto nos centraremos en ellos solamente.
Además, como es lógico, nos auxiliaremos de un formulario HTML donde introduciremos las consultas enviadas a la Base de Datos. Lo validaremos, para en caso de que no se genere ningún resultado, mostrar un mensaje al usuario y también advertir en caso de que se haya enviado vacío.
Otra de las cosas que debo destacar, es que los resultados de las búsquedas se ordenarán de forma tal, que los primeros serán los que mayor cantidad de coincidencias tengan con la cadena pasada a la consulta.
Bueno, creo que ya es hora de entrar en materia y ver el código, que como bien dice WordPress: Code is Poetry…
La Base de Datos:
Como ya dijimos, nuestra tabla cuenta con un par de campos, título y cuerpo de la noticia, mas el ID claro. Lo que haremos en si es crear un campo FULL-TEXT con los campos en los cuales nos interesa realizar las búsquedas:
CREATE TABLE `noticias` (
`noticia_ID` int(11) NOT NULL auto_increment,
`noticiaTitulo` varchar(200) NOT NULL,
`noticiaNoticia` text NOT NULL,
PRIMARY KEY (`noticia_ID`),
FULLTEXT KEY `buscador` (`noticiaTitulo`,`noticiaNoticia`)
) ENGINE=MyISAM;
El formulario HTML:
Todo lo vamos a hacer en una misma página: buscar.php
<h1><a href="<?php echo $_SERVER['PHP_SELF']; ?>">Buscador - By RogerTM</a></h1>
<form name="buscar" action="<?php $_SERVER['PHP_SELF'] ?>" method="get">
Buscar: <input type="text" size="50" value="<?php echo $_GET['frase']; ?>" name="frase" />
<input type="submit" name="buscar" value="Buscar" />
</form>
Esto no creo que necesite explicación, solo que el value de la caja de texto es la frase enviada por $_GET[], osea, que se mostrará la frase que buscamos una vez hecha la consulta.
El código PHP:
<?php
// conectar al servidor
$server_link = mysql_connect("localhost", "root", "*****");
if(!$server_link){
die("Falló la Conexión ". mysql_error());
}
// seleccionamos la base de datos
$db_selected = mysql_select_db("database", $server_link);
if(!$db_selected){
die("No se pudo seleccionar la Base de Datos ". mysql_error());
}
// varificamos que el formulario halla sido enviado
if(isset($_GET['buscar']) && $_GET['buscar'] == 'Buscar'){
$frase = addslashes($_GET['frase']);
// hacemos la consulta de busqueda
// ver explicación mas abajo
$sqlBuscar = mysql_query("SELECT noticiaTitulo, noticiaNoticia,
MATCH (noticiaTitulo, noticiaNoticia)
AGAINST ('$frase' IN BOOLEAN MODE) AS coincidencias
FROM noticias
WHERE MATCH (noticiaTitulo, noticiaNoticia)
AGAINST ('$frase' IN BOOLEAN MODE)
ORDER BY coincidencias DESC", $server_link)
or die(mysql_error());
$totalRows = mysql_num_rows($sqlBuscar);
// Enviamos un mensaje
// indicando la cantidad de resultados ($totalRows)
// para la frase busada ($frase)
if(!empty($totalRows)){
echo stripslashes("<p>Su búsqueda arrojó <strong>$totalRows</strong> resultados para <strong>$frase</strong></p>");
// mostramos los resultados
while($row = mysql_fetch_array($sqlBuscar)){
echo "<strong><a href='#'>$row[noticiaTitulo]</a>:</strong> <em>Coincidencias: ". round($row['coincidencias']) ."</em><br />";
echo "<p>".substr(strip_tags($row['noticiaNoticia']), 0, 255)."...</p>";
}
}// si se ha enviado vacio el formulario
// mostramos un mensaje del tipo Oops...!
elseif(empty($_GET['frase'])){
echo "Debe introducir una palabra o frase.";
}
// si no hay resultados
// otro mensaje del tipo Oops...!
elseif($totalRows == 0){
echo stripslashes("Su busqueda no arrojo resultados para <strong>$frase</strong>");
}
}
?>
NOTA: Obsérvese el uso de la función strip_tags, en este caso nos sirve para eliminar etiquetas HTML no deseadas y evitar se muestren imágenes u objetos embebidos en el código.
La consulta de búsqueda:
La función MATCH() realiza una búsqueda de lenguaje natural para cadenas contra una colección de textos. Una colección es un conjunto de una o más columnas incluídas en un índice FULLTEXT. La cadena de búsqueda se da como argumento para AGAINST(). Para cada registro en la tabla MATCH() retorna un valor de relevancia, esto es, una medida de similaridad entre la cadena de búsqueda y el texto en el registro en las columnas mencionadas en la lista MATCH().
[...]
Para búsquedas FULL-TEXT en lenguaje natural, se requiere que las columnas nombradas en la función MATCH() sean las mismas columnas incluídas en algún índice FULLTEXT en su tabla. Para la consulta precedente, tenga en cuenta que las columnas nombradas en la función MATCH() (noticiaTitulo y noticiaNoticia) son las mismas que las nombradas en la definición del índice FULLTEXT de la tabla noticias.
[...]
La consulta retorna los valores de relevancia y también ordena los registros en orden decrecente de relevancia. Para conseguir este resultado, debe especificar MATCH() dos veces: una vez en la lista SELECT y otra en la cláusula WHERE. Esto hace que no haya sobrecarga adicional, ya que el optimizador de MySQL se da cuenta que hay dos llamadas MATCH() son idénticas e invoca la búsqueda FULL-TEXT sólo una vez.
Tomado del Manual de MySQL.
Concluyendo:
Como ves ha sido fácil y rápido, solo espero como siempre, que mis ejemplos sirvan a quienes se inician en la programación usando PHP.
Cualquier comentario, duda o sugerencia, no dudes en hacérmelos saber. Yo también aprendo mucho de las opiniones de los lectores que pasan por aquí.
E insisto, no dejes de leer en el Manual de MySQL el capitulo referente a las Funciones de búsqueda de texto completo (Full-Text). Aquí tienes una explicación detallada sobre las búsquedas booleanas, las búsquedas con expansión de consulta, sus limitaciones, como afinarlas y las cosas que quedan aun por hacer en este tipo de consultas.
Nota: Edito el post, pues me faltaba ponerle las funciones addslashes() y stripslashes() en las cadenas de entrada y salida respectivamente.