Tech Blog.

Thoughts, stories, ideas.

Finja – Votre recherche amicale ninja

5. June 2016

Imaginez que vous obtenez un login sur un ordinateur Unix fonctionnant sur du matériel ésotérique. Sur cet ordinateur, vous trouverez un projet C++/C/Java à 10 emplacements, avec de nombreux langages et formats de fichiers spécifiques aux applications.
Vous ne devez pas copier le code source sur votre ordinateur, car il appartient au client. Vous pouvez adapter le code source et le compiler sur l’ordinateur. Vous ne devez rien installer.

Comment trouvez-vous votre chemin par ici ? Vous pouvez essayer grep, mais vous mourrez de vieillesse avant d’avoir trouvé tous les endroits où apparaît le symbole qui vous intéresse. Vous avez peut-être de la chance et GNU-Idutils est installé, mais bien sûr le symbole n’apparaît pas dans les fichiers avant les Idutils et n’est pas indexé.

Mais heureusement vous trouverez Python 2.6 sur votre ordinateur et vous pouvez utiliser l’aide d’un ninja.

Et oui, ces choses nous arrivent.

Finja

Finja

Finja est un indexeur qui ne nécessite que Python 2.6+ (3.4+). Contrairement à la plupart des grandes alternatives à Finja, Finja est générique. Il ne sait pas ce qu’il indexe. Finja obtient une bonne qualité grâce à plusieurs passages où le texte est décomposé en jetons de différentes manières. Il est donc plus lent et l’index est plus gros que les indexeurs spécialisés, mais il indexe votre matériel et n’omet aucun fichier inconnu.

Utiliser Finja

J’appelle finja -i dans le répertoire où j’écris cet article.

 $> finja -i
    Makefile: indexed 87/147 (0.592) new: 38 UTF-8
    finja-blog.html: indexed 4370/10492 (0.417) new: 1126 UTF-8
    finja-blog.rst: indexed 487/1517 (0.321) new: 73 UTF-8
    Indexing done

Il a trouvé 87 jetons uniques dans le Makefile. En fait, il a trouvé 147 jetons dans toutes les exécutions, dans la première exécution il utilise par exemple des espaces comme séparateurs, dans une deuxième exécution il utilise des signes de ponctuation du langage naturel comme séparateurs et dans la troisième exécution il utilise des séparateurs Finja qui sont utilisés dans des langages de programmation communs. Ainsi, 0,592 montre l’effort supplémentaire à travers les descentes (1,0 serait parfait, des ratios plus bas sont pires). Il a trouvé 38 nouveaux jetons et a reconnu UTF-8 comme l’encodage du fichier. Oui, Finja peut voir le codage. Pour plus d’efficacité, Finja suppose simplement que le fichier est encodé en UTF-8. Le codage n’est détecté que lorsqu’une erreur de décodage se produit.

Maintenant, je veux trouver des ninjas.

$> finja ninja
.:
finja-blog.html:    7:<title>Finja - Your friendly finding ninja</title>
finja-blog.html:  696:<div class="document"
finja-blog.html:  697:<h1 class="title">Finja - Your friendly finding ninja</h1>
finja-blog.rst:    1:Finja - Your friendly finding ninja
finja-blog.rst:   16:a ninja.

Je ne suis pas intéressé par les résultats du fichier HTML.

  $> finja -p html ninja
    .:
    finja-blog.rst:    1:Finja - Your friendly finding ninja
    finja-blog.rst:   16:a ninja.

Dans l’ordre, nous trouvons donc dans l’ordre : ””. Ninja deux fois sur les lignes 1 et 16. Mais attendez, ce n’est pas courant.

 $> finja -u
    finja-blog.rst: indexed 939/2897 (0.324) new: 111 UTF-8

Avec finja -u, seuls les fichiers qui ont été modifiés sont réindexés.

$> finja -p html ninja
    .:
    finja-blog.rst:    1:Finja - Your friendly finding ninja
    finja-blog.rst:   16:a ninja.
    finja-blog.rst:   61:   $> finja ninja
    finja-blog.rst:   63:   finja-blog.html:    7:<title>Finja - Your friendly
    finja-blog.rst:   65:   id="finja-your-friendly-finding-ninja">
    finja-blog.rst:   66:   finja-blog.html:  697:<h1 class="title">Finja - Your
    finja-blog.rst:   67:   finja-blog.rst:    1:Finja - Your friendly finding ninja
    finja-blog.rst:   68:   finja-blog.rst:   16:a ninja.
    finja-blog.rst:   74:   $> finja -p html ninja
    finja-blog.rst:   76:   finja-blog.rst:    1:Finja - Your friendly finding ninja
    finja-blog.rst:   77:   finja-blog.rst:   16:a ninja.

“Yo dawg, I hear you like searching ninjas, we put ninjas in your search, so you can search ninjas while you search.” Hmm, le résultat est quelque peu récursif, mais nous avons prouvé que l’index a été mis à jour.

Nous pouvons également effectuer des recherches dans des sous-répertoires:

 $> cd dir/
    $> finja -u -p html punctuation
    ..:
    finja-blog.rst:   51:second pass it uses punctuation marks from natural

SQLite peut être votre ami

Bien sûr, nous avons rapidement trouvé des problèmes de performance avec un projet de 10 mloc. Il s’avère que l’optimiseur de requêtes de SQLite est stupide, stupide est le bon mot, il n’est pas mauvais, mais pas aussi sophistiqué que nous sommes habitués à de PostgreSQL. Par défaut, aucune analyse d’histogramme n’est effectuée et les tables sont donc fusionnées dans un mauvais ordre. Cependant, si vous compilez SQLite avec SQLITE_ENABLE_STAT4, qui permet l’analyse des histogrammes, les tables sont toujours fusionnées dans un mauvais ordre. Je ne blâme pas SQLite, ce n’est pas PostgreSQL. Nous avons donc optimisé les demandes en Finja.

SELECT
        COUNT(id) count
    FROM
        finja
    WHERE
        token_id = ?

Tout d’abord, nous vérifions la fréquence d’apparition d’un jeton dans l’index, c’est-à-dire une analyse manuelle de l’histogramme, pour ainsi dire. Ensuite, nous fusionnons d’abord l’index avec le jeton le plus rare.

def search_term_cardinality(term_id):
        db         = get_db(create = False)
        con        = db[0]

        curs = con.cursor()
        res = curs.execute(_token_cardinality, [term_id]).fetchall()
        return res[0][0]

    def order_search_terms(search):
        res = sorted(search, key=search_term_cardinality)
        return res

Ceci est bien sûr basé sur l’hypothèse que les jetons sont répartis sur plusieurs fichiers et lignes. S’il y a un fichier dans lequel le jeton se répète un million de fois sur la même ligne, nous prendrons une mauvaise décision. Mais dans la plupart des cas, c’est beaucoup mieux que de laisser SQLite décider.

Conclusion

Veuillez installer Finja, l’utiliser et si vous trouvez un problème, veuillez ouvrir un ticket sur Github.

Je vous remercie beaucoup.