OVH Community, votre nouvel espace communautaire.

[How-to] Sphinx Search sur Debian Lenny


lenono
13/09/2010, 09h39
Bonjour !

Retour de vacances (longues vacances...), donc réponse tardive.

2 solutions :
- tu as un démon searchd qui tourne déjà, donc faut le tuer et le relancer (killall -TERM searchd)
ou
- tu donnes le nom de l'index que tu as créé en paramètre de ta ligne de commande.

Mais il me faudrait un peu plus de détail, copie de .conf (attention les mots de passe !!!), ta distribution, sous quel compte tu as fait ton install...

@+
Arnaud

patou1982
05/08/2010, 18h04
Slt,

J'ai bien suivi ton tuto, install ok, index ok, mais à l'exécution du PHP :

Query failed: no enabled local indexes to search.

J'ai beau cherché, pas trouvé, un coup de main ?

Merci d'avance.

lenono
22/04/2010, 13h48
En parcourant les possibilités de cet outil, je me permets de vous ramener quelques informations :

- Les injections SQL, crainte du webmaster n'ont plus lieu d'être puisque lorsqu'une requête est effectuée, elle l'est directement dans sphinx. Et mysql utilise seulement ensuite l'id, et uniquement l'id retourné par sphinx.

- Les recherches avec des accents :
positionner dans l'index de chaque ressource (pour moi, "index film") le contenu du lien suivant :
http://www.bdfci.info/V4/inc/annexes/charset_table.txt
C'est la charset_table, qui permet d'insensitiver les accents !
Ainsi, une recherche sur arrêt retournera les expressions arrét, arrêt, arret, arrët, ou encore arrèt !

- les apostrophes sont un cas délicat à gérer en Mysql (MATCH (...) AGAINST, même avec l'option IN BOOLEAN MODE).
Là, accent, apostrophe ou pas, ça passe !
Mysql : L'air != l air
sphinx : l'air == l'air

Voilà, bon usage,

Arnaud

lenono
26/01/2010, 16h10
Un petit bout de php.

Sphinx ne retourne que les index, sous forme d'array.
Il nous appartient ensuite de faire la requête mysql pour retrouver les infos souhaitées.

La classe api, est celle forunie dans tar.gz de l'archive téléchargée.
Ici :
Code:
/tmp/sphinx-0.9.9/api/sphinxapi.php
Le bout de code php est le suivant.
Il a pour objet de rechercher des titres de films dans une base de 410.000 titres, et où mes recherches étaient un peu laborieuses.

Code PHP:
include('../../classes/sphinxapi.php');
include(
'../../classes/class.database.php');
require(
'../../conf/fonctions.php');
$debutpage=temps();
$db = new database();
$cl = new SphinxClient();
$cl->SetArrayResult(true);
$cl->SetMatchMode(SPH_MATCH_ALL);
/*
In SPH_SORT_EXTENDED mode, you can specify an SQL-like sort expression with up to 5 attributes (including internal attributes), eg: 
@relevance DESC, price ASC, @id DESC
Both internal attributes (that are computed by the engine on the fly) and user attributes that were configured for this index are allowed. Internal attribute names must start with magic @-symbol; user attribute names can be used as is. In the example above, @relevance and @id are internal attributes and price is user-specified. 
Known internal attributes are: 
@id (match ID)
@weight (match weight)
@rank (match weight)
@relevance (match weight)
@random (return results in random order)
*/
// PARAGRAPHE DE SWITCH DU TRI : 
if(isset($_GET['tri'])){
    
$tri=$_GET['tri'];
}else{
    
$tri='';
}
if(isset(
$_GET['order'])){
    
$order=$_GET['order'];
}else{
    
$order='';
}
switch(
$tri){
    case 
'annee':
        switch(
$order){
            case 
'DESC':
                
$cl->SetSortMode(SPH_SORT_ATTR_DESC,'Film_Annee_Production');
            break;
            default:
            case 
'ASC':
                
$cl->SetSortMode(SPH_SORT_ATTR_ASC,'Film_Annee_Production');
            break;
        }
    break;
    default:
    case 
'titre':
        switch(
$order){
            case 
'DESC':
                
$cl->SetSortMode(SPH_SORT_ATTR_DESC,'titre_ordinal');
            break;
            default:
            case 
'ASC':
                
$cl->SetSortMode(SPH_SORT_ATTR_ASC,'titre_ordinal');
            break;
        }
    break;
}

// PARAGRAPHE LIMITES :
if(isset($_GET['limite'])){
    
$limite=$_GET['limite'];
}else{
    
$limite=0;
}
$cl->SetLimits($limite,100);

$q=$_GET['q'];
$res $cl->Query($q,'film');
if(
$res===false){
    echo 
"Query failed: " $cl->GetLastError() . ".\n";
}else{
    if(
$cl->GetLastWarning()){
        echo 
"WARNING: " $cl->GetLastWarning() . "";
    }
    print 
"Query '$q' retrieved $res[total] of $res[total_found] matches in $res[time] sec.
"
;
    print 
"Query stats:
"
;
    if(
is_array($res["words"])){
            foreach ( 
$res["words"] as $word => $info ){
                print 
"    '$word' found $info[hits] times in $info[docs] documents
"
;
            }
            print 
"
"
;
    }
     if ( 
is_array($res["matches"]) )      {
                
$n 1;
                print 
"Matches:
"
;
                foreach ( 
$res["matches"] as $docinfo ){
                        print 
"$n. doc_id = $docinfo[id], weight = $docinfo[weight]";
                        
$res_sql=$db->query("SELECT Film_titre,Film_Annee_Production from film where film_id=$docinfo[id]");
                        print 
'.$res_sql[0]['Film_titre'];
                        if(
$res_sql[0]['Film_Annee_Production']!=''){
                            print 
' ('.$res_sql[0]['Film_Annee_Production'].')';
                        }
                        print 
"

"
;
                        
$n++;
                }
        }
}
$finpage=temps();
$totalpage=$finpage-$debutpage;
$totalpage=substr($totalpage,0,5);
echo 
'Page générée en '.$totalpage.' secondes, ';
?>
Le résultat est le suivant :
Code:
Query 'tron legacy' retrieved 1 of 1 matches in 0.002 sec.
Query stats:
'tron' found 412 times in 401 documents
'legacy' found 126 times in 126 documents

Matches:
1. doc_id = 15673, weight = 3 Tron l'héritage (2010)
Page générée en 0.006 secondes,
Précisions nécessaires :
- je ne l'ai pas encore mis en prod, car pas mal d'adaptations encore à faire
(résultats visibles sur :
http://www.bdfci.info/V4/inc/annexes/sphinx.php?q=tron legacy&order=ASC&tri=titre&limite=100
parametres :
q : la recherche
order : ASC ou DESC (en majuscules)
tri : titre ou annee)

J'ai 2 champs indexés :
titre et titre_original.
En indiquant indifféremment le titre, le titre original, un mix des 2, je retrouve mon $id.

Quelque soit la limite demandée, pour une requete, sphinx ne retournera que les 1000 premiers résultats.
ex : si $q='', même en mettant début=enregistrement 300.000, sphinx ne retournera rien.
D'un autre coté, personne n'exploite les 1000 premiers résultats de google !
Il y a un gros tunning possible, et mes benchs me montrent une amélioration constante de mes temps de réponse.

Les + :
- installation facile
- tuning assez facile
- forum actif
- documentation complète

Les - :
- documentation uniquement en anglais
- pas de retour de l'enregistrement entier (sauf à utiliser exec de php)
- j'avoue mes limites sur l'utilisation de soundex et libstemmer...

Bon usage,

Arnaud

lenono
26/01/2010, 16h09
La config du fichier sphinx.conf : (/usr/local/etc/sphinx.conf)
Code:
source film
{
	type		= mysql
	sql_host		= localhost
	sql_user		= user
	sql_pass		= password
	sql_db		= mydb
	sql_port		= 3306
	sql_sock		= /var/run/mysqld/mysqld.sock
	sql_query		= SELECT Film_Id,Film_Titre,Film_Titre as titre_ordinal,Film_Annee_Production,Film_Titre_Original FROM film
	sql_query_info		= SELECT Film_Id,Film_Titre,Film_Annee_Production,Film_Titre_Original FROM film WHERE Film_Id=$id
	sql_attr_uint		= Film_Annee_Production
	sql_attr_str2ordinal	= titre_ordinal
}
index film
{
	source				= film
	path				= /home/sphinx/data/film 
	docinfo				= extern
	mlock				= 0
	morphology			= none
	min_word_len		= 1
	min_infix_len 		= 3
	charset_type		= utf-8
	html_strip			= 1
	html_remove_elements= style, script
}
indexer
{
	mem_limit			= 64M
}
searchd
{
	listen				= 9312
	log					= /home/logs/sphinx/searcd.log
	query_log			= /home/logs/sphinx/query.log
	read_timeout		= 5
	client_timeout		= 300
	max_children		= 30
	pid_file			= /home/logs/sphinx/searchd.pid
	max_matches			= 1000
	seamless_rotate		= 1
	preopen_indexes		= 0
	unlink_old			= 1
	mva_updates_pool	= 1M
	max_packet_size		= 8M
	crash_log_path		= /home/logs/sphinx/crash
	max_filters			= 256
	max_filter_values	= 4096
}

# --eof--
sql_query = SELECT Film_Id,Film_Titre,Film_Titre as titre_ordinal,Film_Annee_Production,Film_Titre_Ori ginal FROM film
Permet de dire à sphinx ce que l'on indexe (c'est sa base interne)
sql_query_info = SELECT Film_Id,Film_Titre,Film_Annee_Production,Film_Titr e_Original FROM film WHERE Film_Id=$id
Permet à sphinx de retouner des infos sur un id choisi (pour les tests, en ligne de commande, ou par exec en php)
sql_attr_uint = Film_Annee_Production
sql_attr_str2ordinal = titre_ordinal

Ces champs sont indexés de manière spécifiques pour répondre à des critères de tri, et pouvoir être passé en arguments dans les requêtes (classe) via php.

La doc est très bien fournie est permet ensuite de tuner son moteur.

Installation de la crontab :
Code:
0,10,20,30,40,50 * * * * /usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --rotate film> /dev/null 2>&1  #MAJ Base sphinx (base film full)
Il est nécessaire de remettre à jour la abse sphinx, des mises à jour dans les tables (fréquence selon les mouvements !)

NB : pour chaque table à indexer, il faut refaire un source, et un index.
NB 2 : Pou réindexer toutes les tables, il faut remplacer, dans mon cas, film par l'argument --all

lenono
26/01/2010, 16h07
Bonjour

Cette aide à l'installation vous présente la mise en place et l'usage de sphinxsearch sur un serveur avec un OS debian.

Quelques informations sur sphinx :
http://www.sphinxsearch.com/docs/current.html#about
http://onlamp.com/pub/a/php/2006/02/...-showdown.html
-> Diaporama de Andrew Aksyonoff (Sphinx Technologies) et Peter Zaitsev (MySQL Performance Blog) (du 17 avril 2008, Santa Clara, Californie)
http://assets.en.oreilly.com/1/event...esentation.ppt

Qui utilise SPHINX ?
- Dailymotion (http://www.haute-disponibilite.net/2...e-dailymotion/)
- Craiglist,Wikimapia, et d'autres sur cette page : http://www.sphinxsearch.com/powered.html
Prérequis :
- avoir la main "root" sur le serveur.
- pour ma part j'ai une installation non standard nginx, php 5 (php-fpm), mysql 5, les chemins seront donc certainement différents pour vos installations, mais il n'y a rien de bien compliqué.

La version de sphinx installée ici est la 0.9.9 (r2117) du 2 décembre 2009.
- http://www.sphinxsearch.com/downloads.html
- http://www.sphinxsearch.com/download...x-0.9.9.tar.gz

Je me suis appuyé sur les pages suivantes pour rédiger ce tutorial :
http://blog.bigbabou.org/2009/sphinx-on-debian-lenny/
http://www.ibm.com/developerworks/li...-sphinxsearch/
http://www.god-object.com/2009/10/20...earch-and-php/

I/Installation

Il faut avoir g++.
Est-il installé ?
Code:
$ which g++
si on a :
Code:
/usr/bin/g++
OK, on continue, sinon on l'installe :
Connexion root :
Code:
$ aptitude install g++
Puis installation des librairies Mysql nécessaires :
Code:
$aptitude install libmysql++-dev libmysqlclient15-dev checkinstall
Pour postgresql, il faudra installer :
Code:
$aptitude install libpg-dev libmysqlclient15-dev checkinstall
installation normale d'un paquet.

Installer sphinx :
(toujours root)
Code:
cd /tmp
wget http://sphinxsearch.com/downloads/sphinx-0.9.9-rc2.tar.gz
tar zxvf sphinx-0.9.9-rc2.tar.gz
cd sphinx-0.9.9-rc2/
wget http://snowball.tartarus.org/dist/libstemmer_c.tgz
tar zxvf libstemmer_c.tgz
./configure --with-libstemmer
(pour postgresl : ./configure -with-pgsql)
make
make install
Si vous avez un problème à la configuration, " can't find MySQL includes files ", assurez vous que libmysql++-dev libmysqlclient15-dev soient bien installées, et assurez vous que vous utilisez bien g++ plutot que gcc en passant le paramètre CXX=g++ en paramètre de configuration.

A ce stade, on en profite pour faire un paquet .deb (réutilisable ultérieurement)
Code:
checkinstall
Checkinstall posera quelques questions, répondez y comme cela par exemple :
Code:
0 - Maintainer: [ endeveit{at}gmail.com ]
1 - Summary: [ Sphinx est un moteur de recherche fulltext. ]
2 - Name: [ sphinxsearch-0.9.9 ]
3 - Version: [ r1112 ]
4 - Release: [ 1 ]
5 - License: [ GPL ]
6 - Group: [ web ]
7 - Architecture: [ i386 ]
8 - Source location: [ sphinx-0.9.8-svn-r1112 ]
9 - Alternate source location: [ http://sphinxsearch.com/downloads.html ]
10 - Requires: [ ]
Sauvegardez le fichier .deb

Maintenant vous pouvez terminer l'installation :
Code:
./make install
Si tout s'est bien passé, vous devriez avoir les fichiers suivants tels quels :
Code:
/usr/local/bin/indexer
/usr/local/bin/indextool
/usr/local/bin/search
/usr/local/bin/searchd
/usr/local/bin/spelldump
/usr/local/etc/exemple.sql
/usr/local/etc/sphinx-min.conf.dist
/usr/local/etc/sphinx.conf.dist
Pour tester l'installation :
Code:
/usr/local/bin/search
qui donnera :
Code:
> /usr/local/bin/search
Sphinx 0.9.9-release (r2117)
Copyright (c) 2001-2009, Andrew Aksyonoff

Usage: search [OPTIONS] 

Options are:
-c, --config 	use given config file instead of defaults
-i, --index 	search given index only (default: all indexes)
-a, --any		match any query word (default: match all words)
-b, --boolean		match in boolean mode
-p, --phrase		match exact phrase
-e, --extended		match in extended mode
-f, --filter  	only match if attribute attr value is v
-s, --sortby 	sort matches by 'CLAUSE' in sort_extended mode
-S, --sortexpr 	sort matches by 'EXPR' DESC in sort_expr mode
-o, --offset 	print matches starting from this offset (default: 0)
-l, --limit 	print this many matches (default: 20)
-q, --noinfo		don't print document info from SQL database
-g, --group 	group by attribute named attr
-gs,--groupsort 	sort groups by 
--sort=date		sort by date, descending
--rsort=date		sort by date, ascending
--sort=ts		sort by time segments
--stdin			read query from stdin

This program (CLI search) is for testing and debugging purposes only;
it is NOT intended for production use.
Si c'est bon, on continue.

Créez le fichier de conf :
Code:
cp /usr/local/etc/sphinx.conf.dist /usr/local/etc/sphinx.conf
et éditez le pour modifier dans un premier temps les paramètres de "searchd" (à la fin de sphinx.conf) :
(Personnellement, j'ai créé des PATH spécifiques dans /home/logs/sphinx, mais chacun fait ce qu'il veut. N'oubliez pas de créer les répertoires spécifiques !!!)
Code:
searchd
{
	log					= /home/logs/sphinx/searcd.log
	query_log				= /home/logs/sphinx/query.log
	read_timeout		= 5
	client_timeout		= 300
	max_children		= 30
	pid_file	= /home/logs/sphinx/searchd.pid
	# max amount of matches the daemon ever keeps in RAM, per-index
	# WARNING, THERE'S ALSO PER-QUERY LIMIT, SEE SetLimits() API CALL
	# default is 1000 (just like Google)
	max_matches			= 1000
	# seamless rotate, prevents rotate stalls if precaching huge datasets
	# optional, default is 1
	seamless_rotate		= 1
	# whether to forcibly preopen all indexes on startup
	# optional, default is 0 (do not preopen)
	preopen_indexes		= 0
	# whether to unlink .old index copies on succesful rotation.
	# optional, default is 1 (do unlink)
	unlink_old			= 1
	# instance-wide ondisk_dict defaults (per-index value take precedence)
	# optional, default is 0 (precache all dictionaries in RAM)
	# ondisk_dict_default	= 1
	mva_updates_pool	= 1M
	# max allowed network packet size
	# limits both query packets from clients, and responses from agents
	# optional, default size is 8M
	max_packet_size		= 8M
	# crash log path
	# searchd will (try to) log crashed query to 'crash_log_path.PID' file
	# optional, default is empty (do not create crash logs)
	# crash_log_path		= /var/log/crash
	crash_log_path			= /home/logs/sphinx/crash
	# max allowed per-query filter count
	# optional, default is 256
	max_filters			= 256
	# max allowed per-filter values count
	# optional, default is 4096
	max_filter_values	= 4096
             # socket listen queue length
	# optional, default is 5
	# listen_backlog		= 5
	# per-keyword read buffer size
	# optional, default is 256K
	#
	# read_buffer			= 256K
	# unhinted read size (currently used when reading hits)
	# optional, default is 32K
	#
	# read_unhinted		= 32K
}
Ensuite, pour pouvoir l'utilsier avec PHP, il faut le "daemoniser", créez un nouveau fichier sphinx dans /etc/init.d :
/etc/init.d/sphinx qui contiendra :
Code:
#! /bin/sh
# /etc/init.d/sphinx: start the sphinx search daemon. 
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin 
PIDFILE=/home/logs/sphinx/searchd.pid
BINPATH=/usr/local/bin/searchd 
SPHINX="--config /usr/local/etc/sphinx.conf"
NAME=searchd
DESC="sphinx search daemon"
test -f $BINPATH || exit 0
# Debian/Ubuntu style
# test ! -r /etc/default/sphinx || . /etc/default/sphinx
running()
{
	# No pidfile, probably no daemon present
	#
	if [ ! -f $PIDFILE ]
	then
		return 1
	fi
             pid=`cat $PIDFILE`
 	# No pid, probably no daemon present
	#
	if [ -z "$pid" ]
	then
		return 1
	fi
             if [ ! -d /proc/$pid ]
	then
                         return 1
	fi
             cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1`
	# No syslogd?
	#
	if [ "$cmd" != "$BINPATH" ]
	then
		return 1
	fi
return 0
}
case "$1" in
  start)
	echo -n "Starting sphinx search daemon: searchd"
	start-stop-daemon --start --quiet --chuid www-data:www-data --exec $BINPATH -- $SPHINX
	echo "."
	;;
  stop)
	echo -n "Stopping sphinx search daemon: searchd"
	start-stop-daemon --stop --chuid www-data:www-data --retry TERM/1/TERM/1/TERM/4/KILL --quiet --exec $BINPATH --pidfile $PIDFILE
	#start-stop-daemon --stop --chuid www-data:www-data --retry TERM/1/TERM/1/TERM/4/KILL --pidfile $PIDFILE
	echo "."
	;;
  restart|force-reload)
	echo -n "Restarting sphinx search daemon: searchd"
	start-stop-daemon --stop --chuid www-data:www-data --retry TERM/1/TERM/1/TERM/4/KILL --quiet --exec $BINPATH --pidfile $PIDFILE
	#start-stop-daemon --stop --chuid www-data:www-data --retry TERM/1/TERM/1/TERM/4/KILL --pidfile $PIDFILE
	start-stop-daemon --start --chuid www-data:www-data --quiet --exec $BINPATH -- $SPHINX
	echo "."
	;;
  *)
	echo "Usage: /etc/init.d/shpinx {start|stop|restart|force-reload}"
	exit 1
esac
exit 0
Et testez votre installation :
Code:
> /etc/init.d/sphinx start
Starting sphinx search daemon: searchd[Tue Jan 26 16:09:44.698 2010] [26409] using config file '/usr/local/etc/sphinx.conf'...
[Tue Jan 26 16:09:44.723 2010] [26409] listening on all interfaces, port=9312
Arrêtez le :
Code:
/etc/init.d/sphinx stop
Stopping sphinx search daemon: searchd.
La prochaine étape :
préparation d'une table à indexer et test dans cette table, et intégration dans PHP.

Vos commentaires seront les bienvenus.

@+
Arnaud