Inicio > PHP, Programación > Sphinx, buscador para tu web

Sphinx, buscador para tu web


Cuando una web comienza a tener gran cantidad de contenido, una de las herramientas más importantes para esta es un buscador.

Si bien inicialmente puede parecer fácil realizar búsquedas en la base de datos, una vez comienzas a implementarlo te das cuenta de que hay cosas que no ha tenido en cuenta.

Comenzaremos haciendo un buscador para una sección de artículos.  Quizás lo más intuitivo sea hacer una consulta SQL tal que así:

SELECT * FROM articulos WHERE titulo = ‘%$criterio%’ OR texto = ‘%$criterio%’

De esta manera, obtendríamos los resultados en los cuales apareciese el criterio de búsqueda en el titulo, en el texto o en ambos. Sin embargo, de esta manera solo encontraríamos los resultados exactos, por lo que si buscamos frases, solo encontraríamos la frase exacta, así que podríamos modificarlo tal que así, suponiendo que tuviésemos dos palabras:

SELECT * FROM articulos WHERE ( titulo = ‘%$criterio1%’ OR texto = ‘%$criterio1%’) AND  ( titulo = ‘%$criterio2%’ OR texto = ‘%$criterio2%’)

De por sí es feo, pero si encima la frase es grande el coste computacional es enorme.

Pero ahí no queda la cosa, si no que también tendremos que tener en cuenta el orden…

Según lo que tenemos arriba, nos mostrará cualquier resultado donde aparezcan las palabras que buscamos, indistintamente de si aparecen en el título o en el texto, de si sale una vez o si salen 20… O lo que es lo mismo, no tendrá puntuación alguna según relevancia.

Para los que uséis MySQL con tablas MyISAM podréis hacer uso del FULL-TEXT INDEX, donde podremos crear un indice con uno más campos de una tabla y realizar búsquedas en este, que se ordenaran según relevancia.

SELECT * FROM articulos WHERE MATCH(titulo, texto) AGAINTS (’$criterio’)

Sin embargo, esto tiene el problema de que está restringido a tablas MyISAM, y que todos los campos tienen el mismo peso (que aparezca en el título o en texto es irrelevante).

Además, hay otro problema característico de nuestro idioma. Las tildes.

Ni con like ni con match podremos hacer que camióncamion se consideren igual, la única solución sería eliminar las tildes antes de la búsqueda y tener una tabla adicional donde guardásemos toda la información sin tildes… lo cual no es muy recomendable evidentemente.

¿Solución? Sphinx

Sphinx es un motor de búsqueda Open Source externo a la BD que permite realizar búsquedas definiendo gran número de parámetros, como es la importancia de cada campo, el ignorar mayúsculas, minúsculas y tildes, o calcular la relevancia de un resultado de forma matemática (sumar fecha, multiplicar número de concordancias…).

El funcionamiento de Sphinx es sencillo, creamos una consulta SQL en la que aparezca la información que deseamos que indexe (titulo y texto en nuestro caso) y el creará sus indices con dicha información. Después, le pedimos que realice una consulta en su BD y nos devolverá el ID de las tablas que contienen dicha información según la relevancia expuesta. Una vez tengamos los indices, solo debemos realizar la consulta  en nuestra MySQL para obtener el resto de los datos.

El motivo por el cual no nos devuelve la información directamente es que él la almacena de forma especial, eliminando ciertas cosas (como html) y por tanto, la información no sería la misma.

Para configurarlo en un servidor Linux, deberemos instalarlo desde los repositorios de la distribución y editar el fichero  /etc/sphinxsearch/sphinx.conf aunque ya sabéis que puede variar según la distro.

Aquí os dejo la información para nuestro ejemplo con comentarios:


#El Source es de donde obtendremos los datos

source articulos {

type                    = mysql

sql_host                = localhost

sql_user                = usuario

sql_pass                = 123456

sql_db                  = pruebabd

sql_port                = 3306

#SQL_QUERY es la consulta que de la cual obtendrá la información. Es obligatorio que haya clave primaria, pues será la que nos #devolverá al realizar la consulta

sql_query               = SELECT titulo, texto, id FROM articulos

}

#El index será los parámetros que se utilizará para guardar y clasificar la información
index index_articulos {
source                  = articulos    #Nombre del source a utilizar
path                    = /var/lib/sphinxsearch/data/articulos  #Donde se guardará la información
docinfo                 = extern
charset_type            = utf-8     #Codificiación que usaremos
min_word_len            = 3         #Tamaño mínimo de las palabras que se tendrán en cuenta
#Esta tabla, que deberéis copiar tal cual, será la encargada de que el sistema ignore las tildes
charset_table = 0..9, A..Z->a..z, a..z, \
U+DD->y, U+FD->y, \
U+D1->n, U+F1->n, \
U+C0->a, U+C1->a, U+C2->a, U+C3->a, U+C4->a, U+C5->a, \
U+E0->a, U+E1->a, U+E2->a, U+E3->a, U+E4->a, U+E5->a, \
U+C8->e, U+C9->e, U+CA->e, U+CB->e, \
U+E8->e, U+E9->e, U+EA->e, U+EB->e, \
U+CC->i, U+CD->i, U+CE->i, U+CF->i, \
U+EC->i, U+ED->i, U+EE->i, U+EF->i, \
U+D2->o, U+D3->o, U+D4->o, U+D5->o, U+D6->o, \
U+F2->o, U+F3->o, U+F4->o, U+F5->o, U+F6->o, \
U+D9->u, U+DA->u, U+DB->u, U+DC->u, \
U+F9->u, U+FA->u, U+FB->u, U+FC->u, U+0027

}

Podemos definir tantos indices y sources como necesitemos, por si deseamos que le buscador realice consultas en distintas tablas.
Igualmente, podemos usar consultas consultas multitabla, siempre que tengamos una clave primaria clara.
Ahora, creamos el indice con sudo indexer –all, cargamos el demonio de búsqueda con sudo searchd y podemos buscar con search criterio

Sin embargo, ¿para que nos sirve buscar desde consola? Pues para hacer pruebas…
Para poder hacerlo desde nuestro PHP usaremos la librería SphinxClient.php, disponible en la web del proyecto.

require_once ‘Sphinx.php’;
$sphinx = new SphinxClient();
$sphinx->SetServer (’localhost’, 3312); //Server donde buscaremos
//Opcional, es para seleccionar el primer elemento que devolverá y cuantos en total
$sphinx->SetLimits(($pagina-1)*20, 20);
$sphinx->SetArrayResult(true); //Indicamos que deberá devolver un array
//Indicamos los algoritmos de búsqueda que se va a usar. Estos tardan más pero ofrecen mejores resultados
$sphinx->SetMatchMode(SPH_MATCH_EXTENDED2);
$sphinx->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
$sphinx->SetFieldWeights(array(’titulo’=>100, ‘texto’ => 30)); //Indicamos la importancia que tendrá cada campo
$resultado = $sphinx->Query($criterio, ‘index_articulos’); //Realizamos la consulta indicando criterio e indice
$totalResultados = $resultado['total_found']; //Numero de resultados encontrados
//Obtenemos todos los IDs de los resultados
foreach ($resultados['matches'] as $resultado)
$ids[] = $resultados['id'];
$ids = implode(’,', $ids); //Los unimos para que queden de la forma “1, 2, 3, 4″
//Creamos la consulta. Obtenemos las filas que tengan esa ID y seleccionamos el orden manualmente.
$sql = “SELECT * FROM articulos  WHERE id IN ($ids) ORDER BY FIELD ($ids)”;
$articulos = consultarBD($sql); //Realizamos la consulta para obtener los artículos
Ahí tenéis un ejemplo básico,  pero el sistema tiene bastantes más opciones, como filtros o los cálculos de relevancia que ya os había comentado. Podéis ver el resto de la documentación aquí.
Espero que os sea de ayuda.
Anuncios
Categorías:PHP, Programación Etiquetas: , , , ,
  1. Roberto
    4 julio, 2013 en 12:20 pm

    Hola miguel Ángel, me interesa mucho usar Sphinx, y necesitaria saber (si puedo contactar contigo para que me asesores) ,,,

    tengo varias dudas, Sphinx se conecta al servidor Mysql??? o PostGreeSQL?? u Oracle??, es digamos otro ‘daemon’ ??’ tiene que estar siempre encendido??

    Estoy muy interesado ,,, y si sabes algo de Nginx

    • 4 julio, 2013 en 12:50 pm

      Es otro servidor que ha de estar siempre encendido.

      Se conecta a casi cualquier otro servidor de bases de datos, siempre y cuando tenga “conector compatible”. La mayoría de los sistemas de bases de datos SQL están soportados, no creo que tengas mucho problema en eso.

      De Nginx no te puedo decir mucho salvo que últimamente estoy escuchando muy buenas cosas de él, pero aún no lo he probado.

      • Roberto
        4 julio, 2013 en 1:16 pm

        De acuerdo Miguel Ángel,,, me pondré a investigarlo.
        Gracias por tus artículos, los encuentro muy muy pero que muy útiles.

  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: