Vendredi 23 novembre 2018

Recherche plein texte dans le blog Jekyll en utilisant Lunr.js

Qu’est-ce que lunr.js ?

Lunr.js est une bibliothèque Javascript qui indexe le contenu fourni au format JSON. L’index peut être utilisé pour effectuer une recherche plein texte. En quoi est-ce différent d’un simple’grep’ ? Il utilise des techniques de recherche modernes telles que la tokenisation, le stemming, l’omission de mots vides, etc. Bien que les algorithmes par défaut pour chacune de ces techniques soient fournis par lunr.js, l’utilisateur peut les remplacer pour répondre à ses besoins spécifiques. Et bien sûr, le nom lunr, n’est qu’un jeu sur solr, qui est un moteur de recherche plein texte, mais fait pour les tâches difficiles. Autres bibliothèques utilisées dans l’exemple :

  • jQuery (optional)
  • underscore.js (optional)

Pourquoi ai-je besoin de rechercher un blog créé par Jekyll ?

Premièrement, parce qu’il n’y a pas de base de données en utilisant Jekyll. Il n’y a donc pas de questions. La recherche n’est donc pas simple. Deuxièmement, parce que j’ai commencé à Jekyll, et je pense qu’un blog sans recherche est bizarre.

Montrez-moi le code

Vous pouvez simplement voir la source de ce fichier et trouver tout le code que j’utilise pour ce site dans search.js.
Voici le récapitulatif :

Créer un index :

Fournir les champs des données à indexer

var index;
createIndex();
function createIndex() {
	index = lunr(function () {
	    this.field('title', {boost: 10})
	    this.field('content')
	    this.field('date')
	    this.ref('url')
  });	
}

Chargement des données à indexer :

Étant un blog Jekyll, il n’y a pas de données JSON pour représenter les articles du blog. Vous devez donc stocker tous les messages de votre blog dans le HTML en charge. Je sais que c’est bizarre, mais pour un blog avec quelques centaines de pages de texte brut ne devrait pas ralentir votre temps de chargement beaucoup. De plus, si vous n’affichez pas tous les messages du blog à la fois, il serait préférable de masquer les données chargées en utilisant CSS. Dans l’exemple ci-dessous, je charge toutes les données du blog dans les éléments “doc_*”, à partir desquels la balise .doc_content est cachée par défaut.

loadData();
function loadData() {
	$('.doc').each(function(doc_index) {
		var doc = {};
		doc.date = $(this).find('.doc_date').text();
		doc.content = $(this).find('.doc_content').text();
		doc.title = $(this).find('.doc_title').text();
		doc.url = $(this).find('.doc_title').attr('href');

		index.add(doc);
		posts.push(doc);
	});
}

Recherche dans l’index :

Bien que la recherche dans l’index soit aussi simple que d’appeler index.search(query), l’objet retour n’est pas un tableau de documents chargés. Au lieu de cela, il renvoie la référence, c’est-à-dire le numéro de référence du document indexé ainsi que le niveau de confiance d’une correspondance. Il faut donc trouver le document correspondant dans la liste des documents chargés.

function getResults(query) {
	var docs = [];
	var results = index.search(query);
	_.each(results, function(result) {
		console.log('Result ref: ' + result.ref);
		var doc = _.find(posts, function(post) {
			return post.url === result.ref;
		});
		if (doc) docs.push(doc);
		
	});
	return docs;
}

Résultat

    11 Jan 2015 » Guava 2: Event Bus
    07 Dec 2014 » Creating a new cloud hosted Java website
    25 Jan 2014 » MongoDB: How $pull works
    25 Jan 2014 » Coolness of IntelliJ
    11 Dec 2013 » MongoDB practices
    11 Nov 2013 » Git Notes
    13 Jul 2013 » Guava I: Table
    12 Jul 2013 » Full text search in Jekyll blog using Lunr.js
    10 Jul 2013 » Java Notes