Kamelot Blog

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 11 octobre 2012

jeu
11
oct '12

Petite astuce de développement avec SphinxSearch

--dump-rows <FILE> dumps rows fetched by SQL source(s) into the specified file, in a MySQL compatible syntax. Resulting dumps are the exact representation of data as received by indexer and help to repeat indexing-time issues.

Si vous ajoutez l'option --dump-rows lors de votre indexation, un fichier sera généré avec un dump sql.

Moi ce qui m'intéresse ici c'est l'entête du fichier

# field 0: ressource_title
# field 1: ressource_subtitle
# field 2: ressource_description
# field 3: ressource_category_name
# field 4: ressource_category_description
# sql_attr_timestamp = created # attr 0
# sql_attr_timestamp = online_from # attr 1
# sql_attr_timestamp = online_until # attr 2
# sql_attr_uint = display_counter # attr 3
# sql_attr_uint = vote_counter # attr 4
# sql_attr_uint = parent_id # attr 5
# sql_attr_timestamp = indexing_date # attr 6

Je copie ca dans mon code php ca fait un memento parfait.

Alleï tant qu'à faire une astuce de plus

regardez l'attribut n°6

dans mon sql d'indexation j'ai toujours en dernier lieu

         now() AS indexing_date                                              \

Ca me permet de donner la date de lecture de l'information. L'index pouvant être vu comme un cache. Cette information est parfois importante ou tout du moins utile

mardi 26 juin 2012

mar
26
juin '12

Sphinx : éléments de base.

Plusieurs fois j'ai déjà parlé de sphinx, mais je me rends compte que je n'ai pas une seule présentation "de base".

Je n'ai pas l'intention de refaire ce qui existe déjà mais je voulais présenter le workflow général.

Je trouverai très chouette que si quelqu'un connait elasticSearch, ou solr, ou autre ..., il fasse de même que je puisse le référencer pour comparaison.

SphinxSearch propose un outil d'indexation : indexer

Cet outil va lire 3 des 4 sections du fichier de configuration

  1. Les indexs
  2. Les sources
  3. Les paramètres de l'indexation

Les index sont de 2 types.

  • lié à une source
  • agrégateurs de plusieurs autres indexes (locaux ou distant) ; On les appelle distribués

Une source c'est la définition qui permet d'aller chercher l’information à indexer et une définition de chaque champs.

Ca peut-être une requête SQL sur Mysql ou Posgress

Ou sur un contenu XML.

Le Xml est surtout pensé pour en faire un format d’échange pour en fin de compte pouvoir indexer, tout ce qui peut être transformé en XML.

Même si je ne connais pas très bien lucene et solr, c'est sur le point précédent que ces derniers sont plus fort que sphinx. Ils sont plus adaptés pour indexer des sources hétérogènes, des documents.

Après avoir executé l'indexation on a donc "lu" la source et fabriqués des indexs.

On a un premier niveau pour exploiter ces indexs

Faire une recherche

On peut utiliser search

Celui-ci attaque directement l'index. Sans passer par le service. C'est donc très utile pour tester ses index mais il ne faut en aucun cas envisager une utilisation en production.

En outre, puisqu'il n'utilise pas searchd, il ne permet pas d'utiliser les indexs distribués

On va donc lancer ce service : searchd

Celui-ci va utiliser 2 sections du fichier de configuration.

  1. Les indexs
  2. Les paramètres du service.

Le service va charger en mémoire les indexs et les rendre disponible via une api sur un port donné.

Puisqu'il y a service, il y a client

Jusqu'à présent j'ai vu 3 clients

Il y en a d'autres puisqu'il y a ruby, c++, perl, Haskell, C#, mais aussi des plugins tout prêts pour Yiiframework, Drupal, Symfony, phpBB, MovableType, MediaWiki, Phorum, Thinking Sphinx, Rails,... le tout à trouver sur la page plugin

Avec le client choisi on va pouvoir interroger l'index, servi localement ou sur le réseau par searchd

On récupère alors une liste d'id (uniques) et la valeur des attributs. (pas les textes)

On peut alors faire une jointure avec la source pour retrouver les données dans leur dernier état.

jeudi 29 mars 2012

jeu
29
mar '12

3 petites nouveautés que j'ai repéré dans l'indexer Sphinx : 3° --dump-rows

--dump-rows

Cette option va regénérer un code sql dans une fichier.

Ce code SQL va regénérer une table basée sur nom de la source d'indexation et en y insérant ce qui a été lu par l'indexation.

donc

si j'ai

source  ma_source {
(...)
sql_query = "Select id, nom, prenom, age From ma table_source"
}

ca va donner

Une table rows_ma_source

avec 4 colonnes dans la quelle on voit un insert des valeurs récoltées.

mardi 27 mars 2012

mar
27
mar '12

3 petites nouveautés que j'ai repéré dans l'indexer Sphinx 2.0 : 2° --print-queries

C'est tout simple avec --print-queries on voit directement à l'écran les requêtes SQL qui sont exécutées.

C'est bien pratique pour le debug.

Ca me fait penser à une autre astuce, non spécifique à Sphinx, mais que j'ai commencé à utiliser avec Sphinx.

Dans mes requêtes sql , je met toujours derrière le select un commentaire par exemple

Select /* blablah */ champs1 From  matable

Pourquoi ?

pour la reconnaître facilement dans mytop.

Vous ne connaissez pas mytop ? et vous utilisez mysql ?

Faite donc vite un

sudo apt-get install mytop

et lisez ceci : http://wiki.goldzoneweb.info/mytop

mar
27
mar '12

3 petites nouveautés que j'ai repéré dans l'indexer Sphinx 2.0 : 1° --sighup-each

source : http ://sphinxsearch.com/docs/2.0.4/ref-indexer.html

--sighup-each

Problème en indexant plusieurs indexs avec un seul appel ca me donne

indexer --config sphinx.conf --rotate --quiet  chunk-1 chunk-2 chunk-3 chunk-4 chunk-5 chunk-6

Il fallait attendre que le chunk-6 soit fini pour que le chunk1 indexé depuis un certain temps soit en ligne. Dommage.

du coup j'avais refait

   ./indexer --config sphinx.conf --rotate --quiet chunk-1 && 
   ./indexer --config sphinx.conf --rotate --quiet chunk-2 && 
   ./indexer --config sphinx.conf --rotate --quiet chunk-3 && 
   ./indexer --config sphinx.conf --rotate --quiet chunk-4 && 
   ./indexer --config sphinx.conf --rotate --quiet chunk-5 && 
   ./indexer --config sphinx.conf --rotate --quiet chunk-6 

indigeste mais ca fonctionne mais indigeste quand même

Grâce à --sighup-each on peut resimplifier ca

indexer --sighup-each  --config sphinx.conf --rotate --quiet chunk-1 chunk-2 chunk-3 chunk-4 chunk-5 chunk-6

Donne le même résultat juste avec une option en plus.

dimanche 15 janvier 2012

dim
15
jan '12

Rétrospective SGBD de Décembre


samedi 31 décembre 2011

sam
31
dec '11

Sphinx : Tri par titre en multi index ...

Puisque sphinx ne connaît que des valeurs scalaires pour faire un tri alphabétique, il faut transformer les chaînes de caractères en nombre.

sql_attr_str2ordinal sert à ça.

Sauf que .... ce qu'on stocke c'est un n° d'ordre dans l'index, c'est pas une représentation numérique de la chaîne.

Le nom est bien 2ordinal et pas 2num

Pour confirmation cet extrait de la doc :

9.1.20. sql_attr_str2ordinal
(...)
When indexing ordinals, string values are fetched from database,
temporarily stored, sorted, and then replaced by their respective ordinal 
numbers in the array of sorted strings.
So, the ordinal number is an integer such that sorting by it produces
the same result as if lexicographically sorting by original strings.
by string values lexicographically.

Donc pour les recherches sur plusieurs indexs ça coince.

En effet si ma chaîne est 3eme dans un index, ca ne veut pas dire qu'elle serait avant celle qui est 3ème, 5ème,100ème dans l'autre index.

Bref en multi index, ça foire.

C'est un problème facile à repérer parce que vos résultats arrivent en petites séries de blocs triés. Comme un 45T dont l'aiguille saute :)

C'est bien dommage parce qu'une manière d’accélérer vos indexations et vos recherches c'est de découper les indexs en "portions".

Que faire quand on veut profiter des avantages de ce découpage et des possibilités de trier alphabétiquement ?

Solution depuis Sphinx 1.10

Allez Louya, on a un nouveau type de champs. coûteux mais efficace. sql_field_string

En créant un attribut de ce type, et en l'utilisant dans "sort" sur vos chunk... ca marche.

Et en bonus, vous pouvez en récupérer le contenu. C'est-à-dire que si l'info vous suffit , vous ne devez plus aller la rechercher dans votre source.

Solution avant Sphinx 1.10

Transformez vous même la chaîne en nombre :(

Si vous utilisez une source Mysql, j'ai une solution. Bof bof pour ca. Utiliser la fonction HEX de mysql.

J'ai expliqué cela il y a quelque temps : StrToNum en Mysql ou comment convertir une chaine en nombre ?


Reste encore 2 autres problèmes à régler mais ça sera pour une autre fois.

  • avant de trier il faut "TRIM" tous les espaces blancs. Et ca, Mysql ne le fait pas aussi bien que php. En effet mysql ne retire que les ASCII 32.
  • pour trier il faut une bonne collation. Et ca je n'ai pas encore trouvé comment faire en sorte que sphinx s'en sorte aussi bien que Mysql
le "œ"  est-il bien entre "n" et "p" ?

samedi 18 juin 2011

sam
18
juin '11

Group by avec Sphinx. via SphinxSe

Cette semaine j'ai réussi à faire un truc avec sphinx que je n'ai pas spécialement trouvé bien documenté donc je le raconte ici.

Quand on utilise une table mysql avec le plugin sphinxSE, on doit obligatoirement commencer par les colonnes

  • id
  • weight
  • query
  • group_id
CREATE TABLE t1
(
    id          INTEGER UNSIGNED NOT NULL,
    weight      INTEGER NOT NULL,
    query       VARCHAR(3072) NOT NULL,
    group_id    INTEGER,
    INDEX(query)
) ENGINE=SPHINX CONNECTION="sphinx://localhost:9312/test";

mais on peut lui ajouter des colonnes

on a les colonnes qui représentent les attributs scalaires mais aussi des colonnes "virtuelles"

  • _sph_groupby,
  • _sph_count
  • _sph_distinct

c'est à dire

CREATE TABLE t1
(
    id          INTEGER UNSIGNED NOT NULL,
    weight      INTEGER NOT NULL,
    query       VARCHAR(3072) NOT NULL,
    group_id    INTEGER,
     _sph_groupby INTEGER NOT NULL,
     _sph_count INTEGER NOT NULL,
     _sph_distinct INTEGER NOT NULL,
 
    INDEX(query)
) ENGINE=SPHINX CONNECTION="sphinx://localhost:9312/test";

Si vous utilisez un

WHERE query='test;groupby=attr:nomdunattributscalaire;';

_sph_groupby contiendra la valeur et _sph_count le nombre de matches

Pour donner une "idée" de la vitesse.

J'ai fait une recherche avec un terme courant avec un group by sur un critère qui peut contenir un chiffre de 0 à 9. Dans une collection de plus de 45M rows. Il y a entre 50.000 et 160.000 matches pour chaque ligne de mon group by Et il me donnait le résultat en 300ms

Avec un terme moins répandu et 500x moins de résultats j'avais un temps de réponse de 15ms

lundi 2 mai 2011

lun
02
mai '11

Vous utilisez Sphinxsearch ? Dites leur

Si vous avez déployé Sphinx en production, dites leur.

Il suffit de remplir le questionnaire et rejoindre la longue liste.

mardi 5 avril 2011

mar
05
avr '11

Sphinx : sql_attr_multi ou attribut à valeurs multiple

L'attribut Multi-valued attribute (MVA) de sphinx est une petite merveille que j'ai enfin appréhendé.

Un exemple

des étudiants

Je pars sur un exemple fictif.

Si j'ai des fiches étudiants à indexer. Je peux ajouter des attribut pour les filtrer.

  • date de naissance
  • genre (m=1/f=2)
  • Année (1,2,3,4,5,6)
  • Section (latin-grec=1, électricité=2,...)

Dans tous ces attributs, pour une ressource donnée (pour un étudiant), je n'ai qu'une valeur possible.

pour n'avoir que les garçons j'aurais

filter=genre,1;

pour n'avoir que les sections math (code 4) et sciences (code 9) j'aurais

filter=section,4,9

Si je mets

filter=genre,1;filter=section,4,9

j'aurais les garçons d'une de ces sections.

Complétons l'exemple

Maintenant selon la section j'ai jusqu'à 15 tranches horaires en cours à options (à la carte).

Comme ces cours à option ont des durées variables, l'étudiant doit remplir ses 15 périodes.

En composant avec les 40 options proposées, il peut se retrouver avec 15 cours d'une période ou 3 de 5 périodes ou 2 de 5h + 5 de une ...

Je veux chercher (ca tombe bien j'ai sphinx)

Comment indexer cela si dans ma recherche je veux pouvoir trouver les étudiants qui ont pris une option de type "langue"

Imaginant que dans la liste j'en ai 4 :

  • anglais (code 15),
  • néerlandais (code 18),
  • allemand (code 19)
  • et espagnol (code 21).

Ce qui ne marchera pas (sans les MVA)

Avec sphinx on en peut pas passer plusieurs filtres et dire matcher ce qui passe au moins un de ces filtres

Avec sphinx tous les filtres seront appliqués

Donc je ne peux pas créer 15 attributs (un par tranche) et dire

 filter=attribut_1,15,18,19,21;filter=attribut_2,15,18,19,21;filter=attribut_3,15,18,19,21;....

Parce qu'il faudrait que TOUS les attributs soient matchant pour la liste et donc ne me donnerai que ceux qui ont pris les 4 options et que celles là

Je ne peux pas non plus créer 40 attributs (un par option).

filter=attribut_15,1;filter=attribut_18,1;filter=attribut_19,1;filter=attribut_21,1;

ne me donnerai que ceux qui ont pris les 4 options

Avec les MVA

C'est là que les MVA entrent en jeux.

On va avoir 1 attribut "options" et pour chaque ressource l'attribut va contenir plusieurs valeurs

Lors de la recherche on passe dans la query

 filter=attribut_options,15,18,19,21;

Sphinx va matcher toutes les ressources qui ont au moins une de ces valeurs parmis celles qui lui sont attribuées

Indexation avec des attributs MVA

Maintenant qu'on a la façon de "chercher" il faut encore voir comment indexer cela.

Un petit coup d'oeil sur la doc.

Sphinx

sql_attr_multi = ATTR-TYPE ATTR-NAME 'from' SOURCE-TYPE \
	[;QUERY] \
	[;RANGE-QUERY]
where ATTR-TYPE is 'uint' or 'timestamp' SOURCE-TYPE is 'field', 'query', or 'ranged-query' QUERY is SQL query used to fetch all ( docid, attrvalue ) pairs RANGE-QUERY is SQL query used to fetch min and max ID values, similar to 'sql_query_range'

Si j'ai bloqué tout un temps c'est parce que c'était trop simple.

J'utilise sql_query pour ma source d'indexation.

Il suffit de produire un champs avec des valeurs séparée par des virgules.

puis on met

sql_attr_multi = unit lenomduchamps from field

Et nous y voilà.

Il y a aussi moyen de demander une sous-requete avec FROM query ou ranged-query

sql_attr_multi = uint tag from query; SELECT id, tag FROM tags

Rien compris à mon exemple d'étudiant ?

En voici un autre.

J'ai une liste d'enregistrements, ces enregistrements sont qualifiés par des tags.

C'est à dire qu'on est pas dans un classement par catégories dans un arbre tout simple.

Chaque enregistrement peut être associés à plusieurs tags.

Admettons que j'aie les tag grand, beau, bleu, jaune, ....

J'ai besoin de trouver tous les grands et bleus de ma base

  id name
    ---
   5 bleu
   11 grand

je vais faire une MVA pour pouvoir faire une recherche filter:tag_id,5,11

lundi 14 février 2011

lun
14
fév '11

Paramètre commentaire de SphinxClient::query

Je fait pas mal de tests sur sphinx pour le moment.

En lisant PHP: SphinxClient::query - Manual

[php]
public array SphinxClient::query ( string $query [, string $index = "*" [, string $comment = "" ]] )

Mon attention a été attirée par le 3ème paramètre. (supporté par sphinx depuis la Version 0.9.8 du 14 juillet 2008)

En fait ce paramètre accepte une chaine de caractère qui se retrouve dans le query.log

[php]
$result = $hSphinx->query('leMotQueJeCherche', '*', 'mon commentaire');

Ce paramètre existe aussi en SphinxSE mais ce n'est pas documenté,

Il suffit d'ajouter ';comment=mon test' dans la chaine query,

query='leMotQueJeCherche;comment=mon commentaire';

Et voila dans le query.log

[query.log] [Mon Feb 14 14:54:00.216 2011] 0.091 sec [any/0/rel 14094 (5000,99)] [*] [ios=0 kb=0.0 ioms=0.0 cpums=91.5] [mon commentaire] leMotQueJeCherche

Ce qui est très pratique avec un tail -f et un grep pour ne voir que les rêquetes faisant partie du test,

Lire la suite...

mercredi 6 octobre 2010

mer
06
oct '10

3 façons plus avancées de configurer votre serveur Sphinx

J'avais présenté un simple index et une Approche avec Main + delta. Voici maintenant 3 techniques un peu plus avancées.

Indexes Multiples

Vous aurez besoin de cette configuration si vous disposez de plusieurs source (même hétérogène) et que vous voudrez mettre en place une recherche sur l'ensemble.

Ceci est également utile si vous faite du sharding avec votre base de données. Lorsque vous générez votre index, vous pouvez réunir vos informations en utilisant un index distribués et donc avoir une recherche unique.

Cette technique permet de faire une recherche sur une partie ou sur plusieurs ou sur toutes.

La pierre d’achoppement de cette technique est de garantir que les ids toute source confondue soient uniques

Avantages:

Recherche simple entre plusieurs sources de données, même sur des serveurs différents.

Inconvénients:

  • Nécessite souvent d'une astuce pour garantir l'unicité des identifiants d'index pour éviter les chevauchements de données.
  • Peut nécessiter un script spécial pour générer un fichier de configuration Sphinx

Services Multiples

Note: Depuis la version 1.10-beta Sphinx supporte le multithreading par lui-même, ce qui devrait résoudre les problèmes de performance dont nous parlons dans cette approche, la rendant potentiellement caduque.

Pour utiliser la pleine puissance d'un CPU multi-core il est logique d'exécuter plusieurs instances du Sphinx.

Pour cela, vous devez appliquer une structure d'indexs multiples où chaque index est responsable uniquement d'une partie des données.

Par exemple, pour utiliser un processeur à quatre cœurs, une des options est de couvrir les données avec 4 index où chaque index est utilisé par un processus distinct searchd. Ensuite, chaque instance Sphinx va utiliser l'un des cœurs de processeurs.

Il faudra donc adapter le sql de collecte des informations pour répartir les données sur autant de fichier d'index que désiré.

Avec quelque chose du style

[sql] 
where (id Mod 1) =0

On a ensuite besoin d'un sphinx master qui s'occupe de répondre au query et de l'assemblage des résultats

Ce master qui prendra en charge la requête peut aussi prendre en charge un des index partiels.

Une autre façon de mettre cela en œuvre consiste à utiliser les agents de Sphinx accédant à l'instance de Sphinx. De cette façon, vous obtiendrez de multi-traitement dont nous avons besoin ici.

Avantages:

  • grands performances de recherche sur les systèmes multi-cpu
  • Bonne technique de scaling selon votre site / projet et sa progression

Inconvénients:

  • Pas facile à mettre en œuvre
  • Peut nécessiter un script spécial pour générer un fichier de configuration Sphinx

Astuce: Mettre les différents index sur des disques physiques distincts peut donner encore plus de performance en vitesse de lecture de données

Serveurs Multiples

Un cluster Sphinx est un ensemble de plusieurs serveurs avec la configuration décrite juste avant.

Dans cette configuration, chaque serveur possède son master Sphinx par exemple et l'un des serveurs est choisi en tant que collecteur. Il revient à ce dernier la tâche de distribuer les requêtes entre tous les serveurs utilisant chacun l'index qu'ils hébergent.

Utiliser un cluster Sphinx va faire grimper le trafic réseau au point que votre réseau puisse devenir le goulot d'étranglement.

Cette configuration permet de mettre une recherche rapide pour de très grandes quantités de données, et de manière très scalaire mais elle n'est vraiment pas simple à mettre en œuvre - vous aurez besoin d'élaborer un cadre solide pour la distribution des données entre toutes les instances dans le cluster.

Avantages:

  • Très haute performance
  • Configuration très évolutive

Inconvénients:

  • Pas facile à mettre en œuvre
  • Requiert un script spécial pour générer des fichiers de configuration Sphinx
  • Requiert plusieurs serveurs
  • La vitesse de recherche dépend de la vitesse du réseau

Je n'ai pas pondu tout ceci.

Ces 2 posts sont fortement inspiré de five ways to configure sphinx search engine

Comme pour la première partie, j'ai l'intention de compléter ces 2 posts avec des exemples de configuration.

mer
06
oct '10

2 façons simples de configurer votre serveur Sphinx

Si vous avez déjà utilisé Sphinx vous avez essayé une des 5 config que je vais présenter. Chacune correspond à un type de projet. Voyons les 2 premières en détail.

Avant de commencer il y a quelques questions à se poser

  • Combien de données doivent être cherchables ?
  • A quelle vitesse gonfle votre liste de données ?
  • Quelle est votre capacité système (nombre de CPUs, mémoire, réseau)?
  • Combien de "recherche" votre système doit-il encaisser ?

Dans chaque solution seront reprises les avantages et inconvénients.

Lire la suite...

vendredi 10 septembre 2010

ven
10
sep '10

StrToNum ou comment convertir une chaine en nombre ?

Dans Sphinx, les filtres doivent être scalaires. J'avais donc un problème pour obtenir une version numérique d'un code pays.

ASCII(str) transforme le premier caractère de votre chaine en nombre.

Mais comment faire pour avoir un nombre différent pour 2 chaines ayant le même premier caractère ?

J'étais parti dans un délire :

  ASCII(code)-65 + (ASCII(substr(code,1,0)-65+26)  ...

Puis j'ai un peu regratté la doc et j'ai trouvé HEX()

HEX(N_or_S)




Si N_OR_S est une chaîne de caractères, cette fonction retournera une chaîne de caractères hexadécimale de N_OR_S où chaque caractère de N_OR_S est converti en 2 chiffres hexadécimaux.

edit: Je n'ai par contre pas encore trouvé d'équivalent PHP. En PHP on a bin2hex. pour obtenir la même chose.

SELECT HEX('hello'),HEX('ZZ'),HEX('0A'),HEX(0xA);
HEX('hello')  HEX('ZZ')  HEX('0A')  HEX(0xA)
------------  ---------  ---------  --------
68656C6C6F    5A5A       3041       0A      

HEX('php')  HEX('PHP')  HEX('Php')
----------  ----------  ----------
706870      504850      506870    

HEX('aa')  HEX('ab')  HEX('AA')  HEX('AB')  HEX('ZZ')
---------  ---------  ---------  ---------  ---------
6161       6162       4141       4142       5A5A     

Edit (2010-09-30)

Visiblement mon blog est très lu : je dit une grosse connerie et personne le remarque.

Mon objectif présenté ici est de transformer une chaîne en nombre et la solution que je présente ne donne pas le résultat escompté.

En effet HEX('ZZ') -> 5A5A reste une chaine (0x5A5A est un nombre)

Donc pour finaliser le travail il faut reconvertir le hex en dec

avec CONV(leresultat, 16, 10) en mysql et avec hexdec() en php (et pas hex2dec )

samedi 4 septembre 2010

sam
04
sep '10

Sphinx : j'en dit un peu plus sur ce moteur de recherche

Je parlais il y a 2 jours de sphinx en expédiant une explication en 2 secondes.

Le lendemain, je vois sur Planet Mysql que Shlomi Noach publiait un article pour remettre les pendules à l'heure sur ce qu'est sphinx

Je vais donc en dire un peu plus.

Sphinx est un moteur d'indexation/recherche open-source sous GPLv2.

On utilise indexer pour scanner ce qu'il faut indexer, cela génère des fichiers que searchd rend consultables.

Pour attaquer searchd, on a search en ligne de commande.

Mais on a aussi

  • SphinxSE: un engine mysql, il sera inclus directement dans les prochaines versions de mariaDb
  • SphinxAPI: que l'on peut utiliser en php avec un package pecl dedié mais aussi avec les apis officielles Php, Python, Java, Ruby, pur C, fournies avec sphinx, ou bien encore Riddle pour Ruby, Sphinx::Search pour perl, C++ Sphinx client, Haskell Sphinx client, C# .NET client, ...
  • SphinxQL: une syntaxe sql adaptée

Recherche

Pour la recherche elle même on a les syntaxes avancées sur le texte ...

  • et, ou , mais pas,
"hello world" @title "example program"~5 @body python -(php|perl) @* code
  • les quorum (je donne 7 mots et je veux qu'il y en aie au moins 4 dans chaque résultats)
  • la pertinence (ce mot là a plus de poids dans le titre, celui ci partout, ... )
  • la distance dans le texte : ces 2 mots là doivent être séparés par moins de n mots
  • Des remplacements
    • de caractères pour les problèmes de charset
    • les remplacements magiques (si je cherche email, je trouve aussi les contenus avec le mot courriel) sur base de vos listes (voir exemple en bas)
    • Morphologie linguistique, stemming (gestion des pluriels),
    • listes de mots interdits
    • listes de dictionnaires personnels pour la correction magique
  • ...

.. Les critères de filtre et tri annexe

  • groupes (avec decompte par groupe)
  • temporels
  • géographiques
  • ...

J'en passe bien sur.

Le service searchd est consultable via réseau (donc si vous utilisez SphinxSE il n'est pas embarqué dans la DB il peut/ils peuvent être ailleurs) avec ssl et tout le brol.

Indexation

La première chose à distinguer c'est qu'il n'est pas limité à mysql ni même à des bases de données. On peut indexer tout ce qui peut être parsé, moyennant une conversion vers un fichier xml.

On peut indexer des sources hétérogènes les mélanger comme on peut indexer partiellement une source monolithique.

On peut indexer "sur le coté" pendant que l'index précédent reste actif et swapper à la fin (très difficile à faire : il faut ajouter un --rotate)

On peut indexer par petit morceaux et exploiter les partitions ou les merger

On peut répartir les indexs sur plusieurs serveurs

Brefs il y a moyen de distribuer la recherche et l'indexation.

Il y a des techniques de RealTime indexing mais c'est dans la 1.10-beta

Lire la suite...

mercredi 1 septembre 2010

mer
01
sep '10

Nombre de résultats d'une recherche SphinxSe

Logo Sphinx Sphinx est un moteur de recherche full-text

On peut l'interroger au travers de son api, SphinxQL, en ligne de commande ou avec l'engine MySql SphinxSE

J'utilise MySqlSE;

SELECT * from INFORMATION_SCHEMA.ENGINES;

ENGINE SUPPORT COMMENT                     TRANSACTIONS  XA      SAVEPOINTS
------ ------- --------------------------- ------------  ------  ----------
...
SPHINX YES     Sphinx storage engine 0.9.9 NO            NO      NO        

La question du jour était : Y a-t-il un moyen de connaître le nombre total de résultats quand on utilise un limit ?

En Mysql simple, il y a SQL_CALC_FOUND_ROWS

mysql> SELECT SQL_CALC_FOUND_ROWS * 
    -> FROM tbl_name
    -> WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();

Le second SELECT retourne un nombre indiquant combien de lignes le premier SELECT aurait retourné s'il n'avait pas été écrit avec une clause LIMIT.

Mais avec avec SPHINX

En testant sur ma table tbl_name_sphinx qui contient 2410 rows.

select SQL_CALC_FOUND_ROWS * from tbl_name_sphinx WHERE query='' LIMIT 10;
SELECT FOUND_ROWS();
Résultat
FOUND_ROWS()
------------
          20

20 parce que c'est la valeur par défaut du limit de sphinx

# limit - amount of matches to retrieve from result set, default is 20; (ref)

En effet si je force ce limit à 10

select SQL_CALC_FOUND_ROWS *
 from tbl_name_sphinx 
 WHERE query=';limit=10';

SELECT FOUND_ROWS();
Résultat

FOUND_ROWS() -> 10

Pourquoi ? parce que c'est sphinx qui fait la vraie recherche et remonte son résultat à MySql

Donc quand je fait

select SQL_CALC_FOUND_ROWS * 
 from tbl_name_sphinx 
 WHERE query=';limit=1000' 
 LIMIT 10;

Je reçois 10 résultats sur 2410 réels et sur les 1000 que sphinx a remonté

Donc

SELECT FOUND_ROWS(); -> affiche 1000 et pas 2410.

Donc je vais monter mon limit à 1000000.

Gloups, je viens de demander à Sphinx de me préparer en résultat de 100K rows, tout renvoyer à mysql dans une table temporaire qui me retournera uniquement les 10 premiers.... Fameux gaspillage

Quand on sait que sphinx ne me retourne que les id et que donc il faut faire un join avec la table de données, ca fait mal.

la solution

SHOW ENGINE SPHINX STATUS;

On oublie le 'SQL_CALC_FOUND_ROWS'

Et on remplace FOUND_ROWS() par SHOW ENGINE SPHINX STATUS;

On remet le limit 10 au niveau de sphinx;

select  * 
 from tbl_name_sphinx 
 WHERE query=';limit=10';

SHOW ENGINE SPHINX STATUS;

Type    Name    Status                                           
------  ------  -------------------------------------------------
SPHINX  stats   total: 1000, total found: 2410, time: 0, words: 0

Bingo j'ai mon info, planquée dans une "chaine" mais je l'ai.

re bingo

 SHOW STATUS LIKE 'sphinx_%';

Mais je préfère INFORMATION_SCHEMA.

SELECT *
 from information_schema.GLOBAL_STATUS
 WHERE VARIABLE_NAME like 'SPHINX%';
VARIABLE_NAME       VARIABLE_VALUE
------------------  --------------
SPHINX_ERROR        208409        
SPHINX_TIME         0             
SPHINX_TOTAL        1000          
SPHINX_TOTAL_FOUND  2410          
SPHINX_WORD_COUNT   0             
SPHINX_WORDS                      

Et je suis un heureux.

Si vous êtes intéressés par Sphinx, voici un bon article pour l'installer.

Si vous vous êtes déjà intéressé à Zend_Search_Lucene, (bien décrit ici) il me semble avoir que celui-ci peut utiliser Sphinx comme backend. je corrigerai si je retrouve la source.

dimanche 18 avril 2010

dim
18
avr '10

Timestamp VS Datetime

Jeudi en buvant un verre avec un ami, il me demande la différence entre un Datetime et un Timestamp.

J'ai répondu mais je me doutais que je n'étais pas exhaustif.

J'ai donc un peu relu. Ca fait toujours du bien.

1° la taille

  • Datetime -> 8 bytes
  • alors que timestamp c'est 4 bytes

Si on a pas besoin de stocker une date et une heure, on a d'autres possibilités.

  • Date ou Time c'est 3 Bytes
  • Year C'est 1 byte

2° Les dates représentables

  • Date et DateTime -> Année 1000 à 9999
  • Year -> Année 1901 à 2155
  • Timestamp -> Année 1970 à 2036[1]

3° "default" magiques

Timestamp peut être mis à jour automatiquement à la date serveur lors d'une création ou mise à jour de l'enregistrement.

4° Particularité supplémentaire pour mysql

Les valeurs ``zéro``

  • DATETIME '0000-00-00 00:00:00'
  • DATE '0000-00-00'
  • TIMESTAMP 00000000000000 (la longueur dépend de la taille de l'affichage)
  • TIME '00:00:00'
  • YEAR 0000

Cela peut-être désactivé avec certains modes.


Affichage et format

Bien que les valeurs TIMESTAMP soient stockées avec une précision d'une seconde, la seule fonction qui travaille directement avec ces valeurs est la fonction UNIX_TIMESTAMP(). Les autres fonctions opèrent sur des valeurs lues et formatées.

Notes

[1] En fait c'est 2037 mais pas jusqu'au 31 décembre.

mardi 4 mars 2008

mar
04
mar '08

Belgian MySQL Users meeting

Le 18 mars prochain, au Cafe Sport à Leuven se tiendra le prochain meeting du MySQL Belgian User Group Geert envisage d'aborder les points suivants

  • revue rapide de ce qui s'est passé dernièrement avec MySQL
  • Avenir de certaines activités en Belgique
  • Bonnes pratiques, en ce qui concerne l'installation, l'assistance, et quelques points sur les performances.

c'est là que ca se passe.

mercredi 30 janvier 2008

mer
30
jan '08

Plus jamais de crash de réplication avec mySQL 5 ?

Version originale

par peter

Comme vous le savez peut-être, même si vous êtes seulement des tables Innodb votre réplication n'est pas complètement sécurisée en cas de crash. Si le slave MySQL se plante ou est éteint, il est probable que les logs de relais en court de synchronisation (ils ne sont pas synchronisés sur le disque), deviennent obsolète et la synchronisation est perdue

Pour les séries MySQL 4.0 et 4.1 série il y avait un gros hack si vous utilisez uniquement des tables Innodb.

La suite

jeudi 24 janvier 2008

jeu
24
jan '08

SELECT WEEK( 1er Janvier);

SELECT WEEK('2008-01-01'); // 0;
SELECT WEEK('2008-01-07'); // 1;
SELECT WEEK('2008-02-03'); // 4;
SELECT WEEK('2008-12-31'); // 52;

WEEK ne compte que les semaines complètes.

Certains vont dire, mais non la première semaine c'est la 0.

Non, non, en voici la preuve

SELECT DAYOFWEEK('2008-01-01'), # 3
       DAYOFWEEK('2007-01-01'), # 2
       DAYOFWEEK('2006-01-01'), # 1 <- ICI l'année commence le premier jour de la semaine
       DAYOFWEEK('2005-01-01'), # 7
       DAYOFWEEK('2004-01-01'), # 6
       DAYOFWEEK('2003-01-01'), # 5
       DAYOFWEEK('2002-01-01'); # 4 

Du coup

SELECT WEEK('2008-01-01'), # 0
       WEEK('2007-01-01'), # 0
       WEEK('2006-01-01'), # 1 <-on est bien la première semaine complète de l'année
       WEEK('2005-01-01'), # 0
       WEEK('2004-01-01'), # 0
       WEEK('2003-01-01'); # 0 

et du coup

SELECT WEEK('2008-12-31'), # 52
       WEEK('2007-12-31'), # 52
       WEEK('2006-12-31'), # 53
       WEEK('2005-12-31'), # 52
       WEEK('2004-12-31'), # 52
       WEEK('2003-12-31'); # 52 

En fait maintenant il y a une deuxième paramètre.

WEEK(date ,mode)

Voici ce que dit le manuel.

Avec deux arguments, la fonction WEEK() vous permet de spécifier si les semaines commencent le Dimanche ou le Lundi et la valeur retournée sera dans l'intervalle 0-53 ou bien 1-52. Lorsque l'argument mode est omis, la valeur de la variable default_week_format (ou 0 en MySQL 4.0 ou plus ancien) est utilisée.

Voici un tableau explicatif sur le fonctionnement du second argument : Valeur Signification

  • 0 : La semaine commence le Dimanche;l'intervalle de valeur de retour va de 0 à !2; la semaine 1 est la première semaine de l'année
  • 1 : La semaine commence le Lundi;l'intervalle de valeur de retour va de 0 à !2; la semaine 1 est la première semaine de l'année qui a plus de trois jours
  • 2 : La semaine commence le Dimanche;l'intervalle de valeur de retour va de 1 à !2; la semaine 1 est la première semaine de l'année
  • 3 : La semaine commence le Lundi;l'intervalle de valeur de retour va de 1 à !2; la semaine 1 est la première semaine de l'année qui a plus de trois jours
  • 4 : La semaine commence le Dimanche;l'intervalle de valeur de retour va de 0 à !2; la semaine 1 est la première semaine de l'année qui a plus de trois jours
  • 5 : La semaine commence le Lundi;l'intervalle de valeur de retour va de 0 à !2; la semaine 1 est la première semaine de l'année
  • 6 : La semaine commence le Dimanche;l'intervalle de valeur de retour va de 1 à !2; la semaine 1 est la première semaine de l'année qui a plus de trois jours
  • 7 : La semaine commence le Lundi;l'intervalle de valeur de retour va de 1 à !2; la semaine 1 est la première semaine de l'année

Le mode 3 est disponible depuis MySQL 4.0.5. Le mode 4 est disponible depuis MySQL 4.0.17.

mercredi 16 janvier 2008

mer
16
jan '08

REPLACE reset les valeurs non spécifiées

# Je crée une table
DROP TABLE IF EXISTS `testReplace`;
CREATE TABLE `testReplace` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `a` INT(11) DEFAULT '1',
  `b` INT(11) DEFAULT '2',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
 
#J'y ajoute 2 records /lignes/tuples
INSERT INTO `testReplace` 
	(`a`, `b`)
	VALUES
	(1, 1),(2,2);
SELECT * FROM  `testReplace`;
 id | a | b
============
  1 | 1 | 1
  2 | 2 | 2
#Je remplace la première valeur de la première ligne 
REPLACE INTO `testReplace` 
	SET `id`=1, a=3;
# que vaut b ? 
  SELECT * FROM  `testReplace`;
 id | a | b
============
  1 | 3 | 2
  2 | 2 | 2

B a repris sa valeur par défaut

En pratique cela veut dire que si on fait un replace et qu'on ne précise pas toutes les colonnes les colonnes non-spécifiées prennent la valeur par défaut alors qu'on peut s'attendre à un "non" changement.

Il est donc faux de croire que REPLACE c'est un exist(id) ? UPDATE : INSERT

C'est plutôt

  • exist(id) ? DELETE
  • suivi d'un INSERT

Il faut donc utiliser une autre méthode.

INSERT INTO table (id,a) VALUES (1,3)
  ON DUPLICATE KEY UPDATE a=3;

lundi 13 août 2007

lun
13
aoû '07

23 octobre Conférence MySQL 2007 à Paris

  • Découvrir comment tirer au mieux parti de MySQL
  • Bénéficier de conseils d'experts sur l'optimisation des performances
  • Assimiler les meilleures pratiques MySQL
  • Découvrir les nouvelles fonctionnalités et services pour mieux planifier vos déploiements de MySQL
  • Mieux comprendre comment sélectionner la solution de haute disponibilité pour MySQL la mieux adaptée à vos besoins
  • Poser toutes vos questions aux experts MySQL, et avoir l'opportunité de faire part de votre feedback et de vos commentaires
  • Nouer des relations avec l'équipe de MySQL AB
  • Découvrir comment vous pouvez bénéficier des solutions de nos partenaires

Agenda :

  1. Introduction : Bertrand Matthelié, Directeur Marketing EMEA
  2. La roadmap MySQL, nouveautés & fonctionnalités à venir : Robin Schumacher, Directeur Product Management
  3. Optimisation des performances: Session 1, meilleures pratiques : Stéphane Varoqui, Consultant
  4. MySQL pour les applications en ligne : Serge Frezefond Ingénieur Avant-Vente
  5. Optimisation des performances: Session 2, études de cas Stéphane Varoqui
  6. MySQL pour Datawarehouse & BI : Serge Frezefond
  7. Présentation Client: Skyblog et Crédit Mutuel
  8. Stratégies de Haute Disponibilité avec MySQL : Max Mether, Formateur
  9. Rendre la gestion de données d'abonnés flexible grâce à MySQL Cluster Carrier Grade : Christophe Thivend, Alcatel-Lucent
  10. Définition d'une stratégie de moteurs de stockage : Kaj Arnö, VP Community; Stéphane Varoqui, Serge Frezefond
  11. Conclusion et Questions/Réponses

MySQL AB :: Conférences Européennes MySQL 2007

Prix 199€, (159€ avant le 31 Août 2007)

lun
13
aoû '07

Quoi de neuf avec MySQL 5.1

Êtes-vous prêt pour passer à MySQL 5.1 ? Vous devriez. C'est vrai qu'il y a eu un grand écart de temps entre l'alpha et la beta, mais là c'est vraiment près de GA. Vraiment. Et puis, vous devrez vous habituer à lui. il y a pas mal de nouveautés attrayante. Laissez moi vous donner un aperçu.

Lire la suite...

dimanche 5 août 2007

dim
05
aoû '07

Jay Pipes veut voir ce qu'on connait de Mysql

Jay PipesPar un petit sondage assez rapide, expliqué ici

3 participants tirés au sort recevront 2 livres Apress chacun

Photo par duncandavidson

vendredi 3 août 2007

ven
03
aoû '07

Mysql-Proxy

LogoOn sait faire pas mal de choses intéressantes avec mysql-proxy mais celle qui me plait le plus c'est de pouvoir rediriger les écritures sur master et les lectures sur le slave.

Mais je vais comment trouver le temps de tester tout ca.

Planet Mysql

Tags