Carnet Wiki

Version 5 — Février 2017 Fil

L’indexation de la date dans le plugin Indexer se fait au format UNIX_TIMESTAMP, ce qui n’est pas sans causer quelques soucis.

Je documente ci-dessous ce que j’ai fait, mais si quelqu’un a une meilleure idée on peut essayer d’améliorer ça.

1. Le problème

Sur les 4 installations de Sphinx que j’ai, le champ date est stocké au format unix, à savoir le nombre de secondes écoulé depuis EPOCH (1er janvier 1970).

Cette date est calculée via dans lib/Indexer/Storage/Sphinx.php via date = strtotime($doc->date).

Pour les dates antérieures au 1er janv. 1970 PHP donne un nombre négatif (alors que MySQL va donner ) ; donc ici, on a date = nombre négatif.

Mais le champ sphinx est un entier non signé, donc les nombres négatifs sont représentés en ajoutant le bit 2^32.

2. La solution trouvée pour le moment

*Si on est en 32 bits* il faut donc retrancher 2^32 = 4294967296 à la valeur que nous renvoie sphinx, pour retrouver notre nombre négatif… On le fait pour les nombres > 2992477296, c’est-à-dire postérieurs au 29 octobre 2064.

Ce cutoff est choisi de façon un peu arbitraire, et permet d’avoir la plage de dates suivante :
-  de 0 à 2992477296 = de 1er janv. 1970 à 29 octobre 2064
-  de 2992477297 à 4294967295 = de 22 septembre 1928 13 décembre 1901 au 31 décembre 1969.

Du coup dans le squelette on pourra utiliser la fonction suivante pour trier selon un ordre qui donne une priorité à la date, soit une priorité aboslue (si tri par date), soi une priorité relative (si tri par « pertinence », on veut quand même donner un bonus aux plus récents) :

[(#REM)


Définition de la fonction de score (tri des résultats)


On bidouille la date car le UNIX_TIMESTAMP
        est stupidement impossible avant 1er janvier 1970.


Cf. https://contrib.spip.net/Indexer-date-32bits


]


[(#ENV{tri}|=={date}|ou{[(#RECHERCHE|strlen|=={0})]}?{
        #SET{select,'*, IF (date > 2992477296, date-4294967296, date) as dateu'}
        #SET{tri,dateu}
        #SET{sens_tri,1}
,
        #SET{select,'*, WEIGHT() / (100+SQRT(SQRT(NOW()-(IF (date > 2992477296, date-4294967296, date))))) as poids'}
        #SET{tri,poids}
        #SET{sens_tri,1}
})]

3. Une meilleure solution ?

Si on veut pouvoir encoder une plage de dates plus large, il va falloir soit passer en 64 bits, soit utiliser un format de champ qui permette des nombres négatifs, soit oublier les secondes et diviser la date par 60. À moins d’une autre idée ??