Indexar las búsquedas full-text con Sphinx. Tutorial como usar Sphinx

¿Cómo realizar búsquedas full-text en una tabla con miles o millones de registros, sin que el mysql falle y el site siga siendo relevante y no se caiga?
La solución se llama Sphinx.
Es un motor de búsqueda (search engine) que proporciona velocidad, gran eficiencia y proporciona a aplicaciones y webs la función de búsquedas full-text relevantes.
Básicamente lo que hace es indexar todo el contenido de una tabla, o varias tablas, en el disco duro, cuando se realiza una búsqueda el servidor requiere espacio en disco duro y memora RAM para realizar la búsqueda. Al tenerla indexada es capaz de procesar una búsqueda full-text en 6GB de texto en 0.1 segundos, mientras que esto en SQL sería imposible o tardaría muchísimo.

Tremendo descubrimiento…. recomiendo usarlo

Bueno esto es algo de la teoría, la práctica es otra cosa, yo he estado 2 días para entender, implementar y dejarlo funcionando.

Para poder instalarlo necesitareis tener permisos como root en vuestro servidor.
Las librerías necesarias son mysql-devel y los compiladores gcc y g++. En el caso que no vengan instaladas ejecutar los siguientes comandos para descargar los paquetes e instalarlos.

  • $ yum -y install mysql-devel
  • $ yum -y install gcc
  • $ yum -y install g++

En otras versiones de linux para descargar e instalar éstas librerías es apt-get.

Ahora descargamos la última versión de Sphinx

Descomprimimos el .tar.gz
, una vez dentro del directorio de Sphinx:

  • Arrancamos la configuración del programa: $ ./configure , la cual chequea los compiladores que tienes instalados y las librerías necesarias.
  • Construimos los binarios: $ make
  • Instalamos los binarios (por defecto se instalan en /usr/local/bin/): $ make install

Para mas información: http://www.sphinxsearch.com/docs/current.html#installation

Instalar las librerías y el software Sphinx no es el problema. El tema es configurarlo, configurar sphinx.conf

En el archivo de configuración consta de las siguientes partes:

  • El source xxxx :
    Es la conexión a la base de datos que tiene que hacer, especificar una tabla con todos sus campos y asignar los campos de fecha (sql_sttr_timestamp) y un campo identificador denominado (sql_sttr_unit) . xxx es el nombre que le damos a nuestro source.
  • El index xxxx:
    Especificamos que es lo que queremos indexar. xxx será el nombre de nuestro indexar, al cual llamaremos posteriormente por consola para indexar el contenido o lo llamaremos con la API que tiene de PHP.
    source = xxx. Es el source que tiene que usar el index para conectarse a la base de datos e indexar.
    path = especificamos el path donde queremos guardar los archivos físicos de indexación.
  • El indexer
    Es la configuración específica del indexador, se le pueden asignar valores para la cantidad de memoria que puede usar,etc..
  • El searchd
    Es el demonio que se ejecuta para que quede a la escucha de las búsquedas que hacemos y las peticiones que se realizan desde la API. Tiene una serie de parámetros de configuración. Se pueden especificar una serie de path para los logs que genera, pero lo mas importante es asignar el puerto de escucha, por defecto 9312.

Ejemplo de mi sphinx.conf

[code lang=”text”]

source busquedas
{
type = mysql
sql_host = localhost
sql_user = mi_user
sql_pass = xxxxx
sql_db = mi_basededatos
sql_port = 3306

sql_query =
SELECT id, categorias, provincia, titulo, contenido, fecha
FROM busqueda

sql_attr_uint = id
sql_attr_timestamp = fecha

sql_query_info = SELECT * FROM busqueda WHERE id=$id
}

index busquedasx
{
source = busquedas
path = /mi_path/sphinx/busquedas1
docinfo = extern
charset_type = sbcs
}

indexer
{
mem_limit = 32M
}

searchd
{
listen = 127.0.0.1
port = 3312
log = /var/log/sphinx/searchd.log
query_log = /var/log/sphinx/query.log
read_timeout = 5
max_children = 30
pid_file = /var/log/sphinx/searchd.pid
max_matches = 1000
seamless_rotate = 1
preopen_indexes = 0
unlink_old = 1
crash_log_path = /var/log/sphinx/crash
}
[/code]

indexar el contenido

/usr/bin/indexer –config /usr/local/etc/sphinx.conf –all
aparecerá por pantalla:
Sphinx 0.9.8-rc2 (r1234)
Copyright (c) 2001-2008, Andrew Aksyonoff

using config file ‘/usr/local/etc/sphinx.conf’…
indexing index ‘busqueda’…
collected 1807 docs, 1.0 MB
sorted 2.5 Mhits, 100.0% done
total 1807 docs, 1004609 bytes
total 1.456 sec, 689957.88 bytes/sec, 1241.03 docs/sec

Buscar

/usr/bin/search –config /usr/local/etc/sphinx.conf cumpleaños
Sphinx 0.9.8-rc2 (r1234)
Copyright (c) 2001-2008, Andrew Aksyonoff

using config file ‘/usr/local/etc/sphinx.conf’…
index ‘busqueda’: query ‘cumpleaños’: returned 87 matches of 87 total in 0.000 sec

displaying matches:
aquí aparecerá un array con todas los elementos que han coincidido

Lanzar el demonio

/usr/bin/searchd –config /usr/local/etc/sphinx.conf

Un código PHP de ejemplo que integra Sphinx

[code lang=”php”]
<?php
include(‘sphinxapi.php’);

$cl = new SphinxClient();
$cl->SetServer( "localhost", 3312 );
$cl->SetMatchMode( SPH_MATCH_ANY );

// el primer parámetro es la query, es lo que queremos buscar: cumpleaños
// el segundo parámetro es el index que vamos a usar para buscarlo

$result = $cl->Query( ‘cumpleaños’, ‘busqueda’ );

if ( $result === false ) {
echo "fallo en Query: " . $cl->GetLastError() . ".n";
}
else {
if ( $cl->GetLastWarning() ) {
echo "WARNING: " . $cl->GetLastWarning() . "
";
}

if ( ! empty($result["matches"]) ) {
foreach ( $result["matches"] as $doc => $docinfo ) {
echo "$docn";
}

print_r( $result );
}
}

exit;
?>
[/code]

Esto es solo un tutorial detallando cada paso de la instalación e implementación.
Hay otros parámetros que se pueden configurar pero son opcionales.
Recomiendo lean el manual completo: http://www.sphinxsearch.com/docs/current.html.

Otro artículo de Interés:  Utilizar mod_deflate para comprimir contenido Web desede Apache

27 comentarios en «Indexar las búsquedas full-text con Sphinx. Tutorial como usar Sphinx»

  1. Hola
    Tengo un web con sphinx funcionando. El problema es que necesito hacer insert, deletes y updates en tiempo real. Veo que no lo hace a menos que reindexe cada vez que hago un cambio. ¿Cómo debería hacer esto? He estado leyendo y he visto los RT index (que creo que valen para esto), pero no consigo que me funcione.
    Yo hago las actualizaciones en mi bbdd pero hasta que no reindexo, sphinx no se entera de los nuevos insert y updates. Para que se entere de los delete tengo que reiniciar searchd.
    ¿Cómo puedo hacer esto?

    gracias

    Responder
  2. Hola!

    Estoy intentando ordenar los resultados de las búsquedas hechas en sphinx por medio de un campo tipo timestamp incluido en la consulta del índice, poniendo: “$cl->SetSortMode(SPH_SORT_ATTR_ASC, “fechaadicion”);…pero no funciona..¿qué estoy haciendo mal?

    Gracias

    Responder
      • sql_query = SELECT idHotel, nombre, cadena, estrellas, empresario, localizacion, direccion, provincia, telefono, fax, web, rango_precios, longitud, latitud, fechaadicion FROM hoteles

        Responder
        • Me has dicho que fechaadiccion es un campo timestamp,no? tipo: 1196440210, sino tendrías que poner lo siguiente, para convertirlo a timestamp

          SELECT idHotel, nombre, cadena, estrellas, empresario, localizacion, direccion, provincia, telefono, fax, web, rango_precios, longitud, latitud, UNIX_TIMESTAMP(fechaadicion) FROM hoteles

          sql_attr_timestamp = fechaadicion

          Otra cosa:

          Intenta declarar el campo fechaadicion como un atributo

          sql_attr_uint = fechaadicion

          Que setMatchMode estas usando?

          Responder
          • Hola!

            Pues mira, el SetMatchMode que estoy usando es:
            $cl->SetMatchMode(SPH_MATCH_ANY);

            En cuanto al tipo del campo “fechaadicion”, lo declaré en phpmyadmin como “timestamp”, pero veo los datos guardados del siguiente modo:
            2012-04-21 19:38:22

            Entonces..si quiero que me ordene los datos por la fecha de inclusión (fechaadicion), tengo que declarar el campo “fechaadicion” como sql_attr_uint o sql_attr_timestamp, o ambos?

            Muchas gracias por responder

            Responder
            • Prueba el MatchMode: SPH_MATCH_EXTENDED2

              Por otro lado prueba a transformar la sql como te dije antes SELECT idHotel, nombre, cadena, estrellas, empresario, localizacion, direccion, provincia, telefono, fax, web, rango_precios, longitud, latitud, UNIX_TIMESTAMP(fechaadicion) FROM hoteles
              para devolver un integer, el timestamp de la fecha

              luego para el sql_attr_uint o sql_attr_timestamp, prueba ambos. Creo que puede poner ambos el sphinx.conf

          • Hola Pedro,

            muchas gracias por responder. Pues te explico, cómo me dijiste, puse el MatchMode: SPH_MATCH_EXTENDED2.

            En sphinx.conf:
            sql_query_pre = SET NAMES utf8
            sql_query_pre = SET SESSION query_cache_type=OFF

            sql_query =
            SELECT idHotel, nombre, cadena, estrellas, empresario, localizacion, direccion, provincia, telefono, fax, web, rango_precios, longitud, latitud, UNIX_TIMESTAMP(fechaadicion)
            FROM hoteles

            sql_ranged_throttle = 0

            sql_attr_uint = UNIX_TIMESTAMP(fechaadicion)

            sql_query_info = SELECT * FROM hoteles WHERE idHotel=$id

            Y el resultado cuando hago la búsqueda es:

            Fallo en Query: index hotelx: sort-by attribute ‘fechaadicion’ not found.

            Probé a poner “fechaadicion” como sql_attr_uint, sin agregarle el UNIX_TIMESTAMP y daba error tb. Lo mismo ocurre con sql_attr_timestamp.

            De cualquiera de las formas, al intentar indexar, me da un warning y me dice que no encuentra esos atributos, incluso con el “idHotel” pasa lo mismo….¿qué será lo que estoy haciendo mal?

            Responder
  3. Hola, caigo tarde al tema jaja. Muy buena guia, yo lo hice en windows 7 y wamp. Y ya que estamos, el problema del sphinxclient not found se debe a que ponen en el include del php simplemente sphinxapi.php en vez del path completo (‘C:sphinxapisphinxapi.php’). Mi pregunta es como hago para “ejecutar” el php ya que lo abro en wamp y la pagina se encuentra en blanco. Otra pregunta, el port que pongo en setserver en el php es el mismo que pongo en el port de searchd en el sphinx.conf (3312)?
    Muchas gracias por adelantad0!!

    Responder
    • Listo ya lo solucione!! Jaja no funcionaba porque la linea de localhost en el archivo host de los drivers de windows esta comentada. Simplemente se borra el numeral y funciona correctamente. Aviso, esto soluciona el error=10060 que aparece en el command prompt y que hacia que la pagina estuviera en blanco cuando lo abria en localhost. En fin espero haber ayudado a alguien, para mas errores usuales de sphinx-windows les recomiendo http://www.yavarhusain.blogspot.com/, ahi fue donde encontre mi solucion!!

      Responder
  4. Hola Pedro, he estado leyendo tu blog y me he encontrado con cosas muy buenas sobre sphinxs que me han ayudado mucho, y aprovechandome de ti a ver si me podrias ayudar con el siguiente problema: ya tengo implementada la búsqueda con sphinxs en un sistema, el problema que presento es como es que realiza las búsquedas, por ejemplo si yo busco “MIGUEL HERNANDEZ” me encuentra todas las coincidencias pero si escribo “MIGUEL HERNANDE” (sin la z al final) no me trae ninguna coincidencia , y yo quisiera que me presentara un resultado de esta manera:

    MIGUEL HERNANDEZ
    MIGUEL HERNANDES
    (como un tipo like)
    y no lo hace, lo cual me representa un problema bastante fuerte ya que muchas veces como no saben escribir el nombre o el apellido lo escriben a medias para poder localizarlo, y escrito de esa manera Sphinx no encuentra ninguna coincidencia, ya he probado al cambiar los parámetros de forma de búsqueda, por default esta SPH_MATCH_ALL y ya lo cambie por SPH_MATCH_ANY pero esto lo que hace es solo traerme todos los MATCHES por cada palabra que ingreso y en la búsqueda que realizo me trae muchos “MIGUEL” pero ningún “HERNANDE(S/Z)”, espero me halla dado a entender, y gracias anticipadas.

    Responder
  5. Buenas tardes ya tengo configurado sphinx pero quisiera saber si alguien alguna vez ha tenido que hacer algo como…. Mostrar tantos resultados por pagina, ósea que en un combo hayan opciones y según la que elijan, muestre ese numero de resultados por pagina porque no tengo idea por donde empezar. Gracias.

    Responder
  6. Exelente solucion, me he pasado dias buscando alguna forma de realizar consultas a millones de registros.. me he leido todo, pero aun me queda una duda!

    Como muestra los resultados?
    yo tengo un script que tiene como funcion buscar entre muchos miles de registros!

    y necesito ordenar las busquedas por ID ó por Nombre etc..

    eso es flexible? supongamos en en la tabla tenga
    ID, NOMBRE, EDAD, CIUDAD, DESCRIPCION

    y el resultado necesesite ordenarlo con codigos html para que quede:
    NOMBRE——————————-EDAD
    DESCRIPCION (Ciudad)

    la forma en que lanza los resultados donde se edita?
    ó acaso lanza un texto plano?

    Responder
    • Hola Robbin!

      Por un lado tienes toda la indexación de tu base de datos, que es básicamente de lo que hablo en mi artículo y por otro lado tienes que usar la API de Sphinx para obtener los resultados indexados, yo he hecho una breve introducción con un pequeño fragmento de PHP para demostrar como se usa.

      Es en este momento, cuando usas la API, cuando puedes ordenar, filtrar, agrupar,etc… Como utilizar la API de Sphinx no es algo que se pueda explicar en una frase en un comentario te sugiero que le eches un ojo a su docu http://sphinxsearch.com/docs/manual-0.9.9.html#api-reference y vayas analizando como usarla para lo que tu necesitas.

      Si aún tienes más dudas, pregúntame algo en concreto.

      Un saludo!

      Responder
  7. Hola otra vez Pedro,

    estoy viendo que hablan de recompilar sphinx una vez instalado el libstemmer. El problema que yo las pruebas en local las hago bajo windows… ¿Alguna idea de como realizar esta operación?

    Un saludoy gracias de nuevo!

    Responder
  8. Buenas Pedro!!

    muchas gracias por el manual, muy bueno y creo que me va a ser de gran ayuda. Pero tengo un par de dudas a ver si me las podrías responder…

    1.- Estoy buscando en una tabla de empresas donde por cada empresa tengo un campo ‘tags’ donde se intenta describir mediante tags la actividad de la empresa. (Ej. Abanicos, agendas, albumes, alfombras). El problema es que si me escriben alguno de los tags en singular no me encuentra a esta empresa.

    2.- Parece que hay un límite a 20 registros por búsqueda ¿alguna idea de como ampliarlo?

    Un saludo y muchas gracias de antemano! 🙂

    Responder
  9. Gracias por tu manual realize la instalación, configuración, indexación, busqueda y puesta en marcha del “demonio” todo en Windows :p Ahora al momento de querer correr el ejemplo en PHP utilizando xampp me sale el siguiente error: Fatal error: Class ‘SphinxClient’ not found in C:xampphtdocsejemploej1.php on line 3
    Si puedes ayudarme te lo agradecere mucho
    Saludos y Gracias

    Responder

Deja un comentario

Enable Notifications    Ok No thanks