Vendredi 23 novembre 2018

Exemple de recherche en texte intégral à l’aide de lunr.js

Lunr est un simple moteur de recherche plein texte qui peut fonctionner à l’intérieur d’un navigateur Web en utilisant Javascript.

Je l’ai ensuite importé dans la tâche, et j’ai configuré les noms des champs :

var lunr = require('lunr');
searchIndex = lunr(function () {
    this.field('title', { boost: 10 });
    this.field('body');
    this.ref('href');
});

Ceci a défini les champs pour le titre, le corps et l’hyperlien, et a défini l’hyperlien comme référence. La variable searchIndex représente l’index Lunr. Ensuite, j’ai fait une boucle à travers les messages, et j’ai passé les détails appropriés pour être ajouté à l’index :

for (post in post_items) {
    var doc = {
        'title': post_items[post].meta.title,
        'body': post_items[post].post.rawcontent,
        'href': post_items[post].path
    };
    store[doc.href] = {
        'title': doc.title
    };
    searchIndex.add(doc);
}

A ce stade, post_items représente un tableau d’objets, chaque objet représentant un billet de blog. Notez que le champ corps est défini à la valeur de l’attribut post.rawcontent de l’élément, qui représente le Markdown brut plutôt que le HTML compilé. Je stocke ensuite le titre dans l’objet store, de sorte qu’on puisse y accéder en utilisant le champ href comme clé. Je fais ensuite la même chose lors de la génération des pages :

// Add them to the index
var doc = {
    'title': data.meta.title,
    'body': data.post.rawcontent,
    'href': permalink + '/'
};
store[doc.href] = {
    'title': data.meta.title
};
searchIndex.add(doc);

Notez que c’est déjà à l’intérieur de la boucle qui génère les pages, donc je ne l’inclus pas. Nous écrivons ensuite l’index dans un fichier :

// Write index
grunt.file.write(options.www.dest + '/lunr.json', JSON.stringify({
    index: searchIndex.toJSON(),
    store: store
}));

Cela prend soin de générer notre index, mais nous avons besoin d’implémenter du code côté client pour gérer la recherche. Nous devons également inclure Lunr.js du côté client (je recommande d’utiliser Bower pour ce faire), à côté de jQuery. Si vous incluez les deux, le code suivant devrait faire l’affaire :

$(document).ready(function () {
'use strict';
// Set up search
var index, store;
 $.getJSON('/lunr.json', function (response) {
    // Create index
    index = lunr.Index.load(response.index);
    // Create store
    store = response.store;
    // Handle search
    $('input#search').on('keyup', function () {
        // Get query
        var query = $(this).val();
        // Search for it
        var result = index.search(query);
        // Output it
        var resultdiv = $('ul.searchresults');
        if (result.length === 0) {
            // Hide results
            resultdiv.hide();
        } else {
            // Show results
            resultdiv.empty();
            for (var item in result) {
                var ref = result[item].ref;
                var searchitem = '<li><a href="' + ref + '">' + store[ref].title + '</a></li>';
                resultdiv.append(searchitem);
            }
            resultdiv.show();
        }
    });
 });
});

Cela devrait être facile à comprendre. Au chargement, nous récupérons et analysons le fichier lunr.json à partir du serveur, et chargeons l’index. Nous avons ensuite mis en place un gestionnaire d’événement pour l’événement keyup sur une entrée avec l’ID de recherche. Nous obtenons la valeur de l’entrée, et interrogeons notre index, et nous bouclons nos résultats et les affichons. J’ai été satisfait de la simplicité de la mise en œuvre de la recherche avec Lunr.js, et cela fonctionne bien. C’est aussi beaucoup plus rapide que n’importe quelle solution côté serveur puisque l’index est généré pendant le processus de construction, et est chargé avec le reste du site, donc le seul facteur dans la vitesse de la réponse est la vitesse à laquelle votre navigateur exécute JavaScript. Vous pourriez probablement aussi l’utiliser avec une application Node.js en générant l’index dynamiquement, bien que vous voudriez probablement le mettre en cache dans une certaine mesure.