Spotlight trop lent ?

Retour sur Spotlight, et sur quelques découvertes intéressantes...

Ils existent de tres nombreux attributs Spotlight (
liste complète). J'ai rencontré un problème de performance avec l'un d'eux: kMDItemFSCreationDate.

Cet attribut correspond à la date de •création• du fichier, tous fichiers sur le disque possèdent donc cet attribut.

Seulement cet attribut ne semble pas indexé comme la plupart des attributs Spotlight. Lorsque vous faites une requete sur cet attribut le temps de réalisation de la requête augmente dramatiquement.
Si par exemple on cherche tous les emails (fichier de type emlx) crée par Mail depuis 10 jours (cf "Spotlight déraille") :

$: time mdfind  -onlyin ~/Library/Mail/ "kMDItemContentType == 'com.apple.mail.emlx' &&  kMDItemFSCreationDate > 275824405"

Le temps d'exécution de cette requêtes est d'environ 1 min et 30 secondes pour a peine 1 Go d'email ! Spotlight est normalement beaucoup plus rapide. De plus on entend le disque "gratter" et les ventilateurs de la machine s'emballent...

Il existe un autre attribut, proche mais différent kMDItemContentCreationDate qui lui est indexé correctement. Il correspond à la date de création du *contenu* du fichier pas à la création du fichier lui même. Par exemple, si j'achète un nouveau Mac, que je configure Mail pour récupérer mes emails, Mail va me créeer des fichiers avec une date "ajourd'hui" mais le *contenu* de mes emails ne date pas d'ajourd'hui... Ainsi la date de création du *contenu* est pour un message email, la date de son envoi (ou de sa réception).

Il y'a certes une différence majeur de sémantique de la date de création et les 2 attributs ne sont pas interchangeables, mais si vous pouvez utiliser cet attribut
kMDItemContentCreationDate les performances de Spotlight sont alors au rendez vous :

$: time mdfind  -onlyin ~/Library/Mail/ "kMDItemContentType == 'com.apple.mail.emlx' &&  kMDItemContentCreationDate > 275824405"

Le temps d'exécution de cette requêtes est systématiquement sous la barre des 2 secondes ! impressionant !
|

Spotlight déraille

Spotlight est une techno extrêmement utile pour les utilisateurs (je ne peux plus m'em passer pour retrouver des emails ou des documents que j'utilise rarement), mais aussi pour les développeurs ! Je m'en sers beaucoup en ce moment, et j'ai trouvé quelques perles....

Du nom de son projet d'origine (matador), probablement à cause des "metadatas", OS X nous offre différentes APIs pour faire des requêtes Spotlight dont ma préférée : MDQueryRef que l'on programme en Core Foundation.

Mais il est aussi possible de faire des requetes via la ligne de commande (pour réaliser des scripts par exemple). Malheureusement la commande
mdfind semble ne pas bien supporter l'ensemble de la syntaxe des requêtes Spotlight decrite ici

$: mdfind  "kMDItemFSCreationDate >  $time.today(-10)"

Cette commande est censé nous retourner tous les fichiers indexés donc le contenu à été crée il y a 10 jours.
Spotlight propose dans son API diverses variables comme $time.now , $time.this_week etc... auxquelles ont peut ajouter "(UN_NOMBRE)" pour effectuer des calculs temporels.

Sauf qu'en ligne de commande ces variables ne sont pas prise en compte, ne génerent pas d'erreur, mais terminent la requête immédiatement !

La solution est de calculer soit meme la date et de la convertir en nombre de seconde depuis... le 01/01/2001... et oui pas depuis 1970 comme (tous?) les unix...

$: mdfind  "kMDItemFSCreationDate > 275824405"

275824405 correspond au nombre de secondes depuis le 01/01/2001 jusqu'à il y a 10 jours (à la date de création de ce post...)

Il semble que depuis 10.6 (Snow Leopard), meme les APIs plus bas niveau (MDQueryRef) ne convertissent plus ces variables en date. A nous donc de faire le travail...

|

L'art du pontage...

La sortie de Leopard, m'a permis de tester une technologie made in Apple dont j'ai toujours rêvé... l'AppleScript sans coder en AppleScript !
Si vous êtes un développeur comme moi, complètement dérouté par AppleScript (mais ou est donc la "doc" AppleScript ? Pourquoi y'a t il 36 mots clé pour faire la meme chose ?), mais pourtant persuadé de son potentiel (c'est bien souvent le seul moyen d'interagir avec les iApps tels iTunes, iPhoto ou Mail...) alors jetez un coup d'oeil au Scripting Bridge for Cocoa.

Ce framework est un petite merveille, car il vous permet en quelque sorte de faire de l'AppleScript en Objective-C. Mieux encore, il n'est pas reservé au langage le plus mystérieux inventé par Apple, mais peut aussi être utilisé pour mélanger du Ruby ou du Python et de l'Objective-C (et donc piloter iTunes ou Mail à partir de Python!).

Non seulement vous allez coder dans un langage familier (Objective-C), mais en plus vous allez gagner en performance par rapport à AppleScript (car le runtime compile des AppleEvents de manière optimisée, et surtout les transmets à l'application cible groupés et "juste quand il faut"). Apple promet un gain entre x50 et x100. J'ai pu vérifier ces chiffres par moi meme !

Ce framework est fournit avec 2 petits binaires qui permet de générer des classes Objective-C à partir du "dictionnaire" (le fameu fichier sdef XML ou le fichier scriptingsuite) :

Dans le terminal: sdef /Applications/iTunes.app | sdp -fh --basename iTunes
sdef est un binaire qui lit (et convertit si nécessaire) le dictionnaire AppleScript de l'application cible (ici iTunes) et l'exporte en XML.
sdp lit ce dictionnaire AppleScript et génere les headers (en-têtes) d'une classe dont le prefixe sera "iTunes".

Vous obtenez un .h Objective-C qui déclare (@interface) toutes les classes présente dans le dictionaire AppleScript. Vous obtiendrez par exemple les classes iTunesApplication, iTunesTrack, iTunesPlaylist, iTunesArtwork etc... rien que leur noms doit vous mettre l'eau a la bouche :)

Voici par exemple à quoi ressemble l'interface de la classe iTunesArtwork :

// a piece of art within a track
@interface iTunesArtwork : iTunesItem

@property (copy) NSImage *data; // data for this artwork, in the form of a picture
@property (readonly) BOOL downloaded; // was this artwork downloaded by iTunes?
@property (copy, readonly) NSNumber *format; // the data format for this piece of artwork
@property NSInteger kind; // kind or purpose of this piece of artwork

@end

Alors oui ca déroute encore finalement car c'est de l'Objective-C 2.0 ... mais ca c'est une autre histoire, ca reste quand même lisible pour les maniaques du vieil ObjC...
Je n'ai absolument pas ajouté de commentaire. sdp ajoute les commentaires lui-meme, en fonction du "dictionnaire" AppleScript. C'est très fort, on dirait que cela a été écrit par un ingénieur chez Apple :-D

La prochaine fois je tenterai d'expliquer comment on utilise ces classes dans un monde Objective-C "ponté".
|