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


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
}

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

<?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;
?>

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.

27 opiniones en “Indexar las búsquedas full-text con Sphinx. Tutorial como usar Sphinx”

  1. 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

    1. Buenas,
      Genial!!! pues has hecho LO MÁS DIFÍCIL!!
      A lo mejor ya te lo has descargado, pero en este enlace podrás descargar la última versión estable de sphinx http://www.sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz
      En la carpeta api está el archivo que tienes que incluir sphinxapi.php, prueba a usar los ejemplos que hay en la carpeta, test.php y test2.php a ver si éstos ejemplos te funcionan bien y no te dan errores,ok?!
      Un saludo!

  2. 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! 🙂

    1. Gracias, me alegro que te haya servidor.

      1.- Nunca he tenido el problema de las mayúsculas y minúsculas. Has probado a meter la configuracion de los charset de las tablas?? mira este articulo.. http://www.pedroventura.com/blog_programacion/sysadmin/sphinx-configuracion-busquedas-con-y-sin-acentos-y-caracteres-utf8/ lo pruebas y me cuentas.

      2.- Eso se puede forzar con la API de PHP cuando haces una llamada. http://sphinxsearch.com/docs/manual-0.9.9.html#api-func-setlimits.

      $cl->SetLimits (0,50);

      para por ejemplo forzarlo a 50 resultados.

      Un saludo!

      1. muchas gracias Pedro,

        me funciona perfectamente. Respecto al otro problema era con los plurales y singulares no con mayúsculas y minúsculas.

        Perdona si alomejor pregunto demasiado pero toda la documentación está en inglés y hay cosas que no entiendo bien…

        Un saludo y muchas gracias otra vez!

        1. el tema de los plurales se puede solucionar, pero creo que vas a tener que reinstalar sphinx. Pero bueno tampoco te llevará tanto. Haz backup del archivo de configuración y listo.

          El tema es que hay que instalarlo con el stemmer, que es lo que ha mi se me ha olvidado comentar en el articulo. La wikipedia te explica que es esto de steaming

          Para instalar sphinx con el stemer en español tienes que hacer lo siguiente:

          mkdir -p /usr/local/src/ # o la ubicacion que quieras
          cd /usr/local/src/
          wget http://www.sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz
          tar xzf sphinx-*
          cd sphinx-*
          wget http://snowball.tartarus.org/dist/libstemmer_c.tgz
          tar xzf libstemmer_c.tgz
          ./configure --prefix=/usr/local/ --exec-prefix=/usr/local/ --with-mysql=/usr/local/mysql/ --with-libstemmer
          make && make install
          
          

          Ya me cuentas si te funcionó.

          Un saludo!

  3. 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!

  4. 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?

    1. 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!

  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.

  6. 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.

    1. Cuando compilaste e instalaste Sphinx metiste también con el stemmer??? Es decir cuando compilas tienes que poner el with-libstemmer previamente te descargas la librería de libstemmer.

      mkdir -p /usr/local/src/
      cd /usr/local/src/
      wget http://www.sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz
      tar xzf sphinx-*
      cd sphinx-*
      wget http://snowball.tartarus.org/dist/libstemmer_c.tgz
      tar xzf libstemmer_c.tgz
      ./configure --prefix=/usr/local/ --exec-prefix=/usr/local/ --with-mysql=/usr/local/mysql/ --with-libstemmer
      make && make install
      

      Después échale un ojo a éstos comentarios del foro de sphinx

      http://sphinxsearch.com/forum/view.html?id=302

      http://sphinxsearch.com/forum/view.html?id=6832

        1. Hola Pedro Ventura… disculpa la tardanza en responder … me costo algo de trabajo el lograr que funcionara.. pero con la sugerencia me dedique a investigar y ahora funciona como debe muchas gracias

  7. 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!!

    1. 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!!

  8. 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

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

        1. 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?

          1. 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

          2. 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

          3. 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?

  9. 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

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *