Bleve en pratique : Construire une solution de recherche d'entreprise
Cet article explore en profondeur comment utiliser Bleve pour construire une solution de recherche complète de niveau entreprise. Nous couvrons l'utilisation détaillée des outils CLI Bleve et l'écriture de scripts automatisés, les meilleures pratiques pour l'indexation par lots de données à grande échelle, les stratégies de déploiement en environnement distribué, ainsi qu'un guide complet de surveillance, d'optimisation et de dépannage. À travers des exemples de code concrets et des conceptions architecturales, nous démontrons comment implémenter un système de recherche haute performance et haute disponibilité.
Utilisation des outils CLI Bleve et automatisation
Bleve offre une interface de ligne de commande (CLI) puissante permettant aux développeurs d'interagir avec les index sans écrire de code. Cet outil, construit sur le framework Cobra, fournit des fonctionnalités complètes de gestion d'index, de manipulation de données et d'interrogation, ce qui en fait un outil indispensable pour le développement et les opérations.
Installation et utilisation de base de la CLI
L'installation de l'outil CLI Bleve s'effectue comme suit :
go install github.com/blevesearch/bleve/v2/cmd/bleve@latest
Une fois l'installation terminée, vous pouvez consulter toutes les commandes disponibles avec bleve --help :
$ bleve --help
Bleve est un outil en ligne de commande pour interagir avec un index Bleve.
Usage:
bleve [command]
Available Commands:
bulk charge en masse depuis des fichiers JSON délimités par des nouvelles lignes
check vérifie le contenu de l'index
count compte le nombre de documents dans l'index
create crée un nouvel index
dictionary affiche le dictionnaire de termes pour le champ spécifié dans l'index
dump affiche le contenu de l'index
fields liste les champs de cet index
help Aide sur une commande
index ajoute les fichiers à l'index
mapping affiche le mappage utilisé pour cet index
query interroge l'index
registry liste les composants Bleve compilés dans cet exécutable
scorch outil en ligne de commande pour interagir avec un index scorch
Description détaillée des commandes principales
Création et gestion des index
La création d'un nouvel index est la première étape avec Bleve, et la commande create prend en charge diverses options de configuration :
# Créer un index de base
bleve create monindex.bleve
# Créer un index avec une configuration de mappage personnalisée
bleve create --mapping mappage.json monindex.bleve
# Spécifier le type de stockage et le type d'index
bleve create --store boltdb --index scorch monindex.bleve
Importation de données et traitement par lots
La CLI Bleve propose deux méthodes d'importation de données : l'indexation de fichiers uniques et le traitement par lots.
Indexation de fichiers uniques :
# Indexer un seul fichier JSON
bleve index monindex.bleve donnees.json
# Indexer tous les fichiers d'un répertoire
bleve index monindex.bleve donnees/
# Conserver les noms de fichiers et extensions originaux
bleve index --keepDir --keepExt monindex.bleve donnees/
Traitement par lots (recommandé pour les grands ensembles de données) :
# Importer en masse un fichier NDJSON
bleve bulk --batch 5000 monindex.bleve donnees.ndjson
# Importer en masse plusieurs fichiers
bleve bulk monindex.bleve donnees1.ndjson donnees2.ndjson
# Personnaliser la taille du lot
bleve bulk --batch 10000 monindex.bleve donnees_volumineuses.ndjson
Opérations de recherche et d'interrogation
Les fonctionnalités de requête prennent en charge plusieurs types de requêtes et de nombreuses options :
# Recherche par chaîne de base
bleve query monindex.bleve "terme de recherche"
# Spécifier le type de requête
bleve query --type term monindex.bleve "terme_exact"
bleve query --type prefix monindex.bleve "prefixe_"
# Requête avec limitation de champ
bleve query --field titre monindex.bleve "titre spécifique"
# Options de requête avancées
bleve query --limit 20 --skip 10 --explain --highlight monindex.bleve "requete"
# Trier les résultats
bleve query --sort-by "-score,date" monindex.bleve "requete"
Maintenance et diagnostic de l'index
# Statistiques sur le nombre de documents
bleve count monindex.bleve
# Lister tous les champs
bleve fields monindex.bleve
# Voir la configuration de mappage de l'index
bleve mapping monindex.bleve
# Vérifier l'intégrité de l'index
bleve check monindex.bleve
# Voir le dictionnaire des champs
bleve dictionary monindex.bleve nom_du_champ
Scripts d'automatisation et intégration
Les outils CLI Bleve sont parfaitement adaptés aux processus automatisés. Voici quelques scénarios d'automatisation courants :
Script de construction d'index par lots
#!/bin/bash
# construire_index.sh
NOM_INDEX="monindexderecherche.bleve"
REPERTOIRE_DONNEES="./donnees"
FICHIER_MAPPAGE="./mappage.json"
# Nettoyer l'ancien index
rm -rf $NOM_INDEX
# Créer le nouvel index
bleve create --mapping $FICHIER_MAPPAGE $NOM_INDEX
# Importer les données en masse
for fichier in $REPERTOIRE_DONNEES/*.ndjson; do
echo "Traitement de $fichier..."
bleve bulk --batch 5000 $NOM_INDEX "$fichier"
done
# Vérifier l'index
echo "Statistiques de l'index :"
bleve count $NOM_INDEX
blege fields $NOM_INDEX
Script de mise à jour périodique des données
#!/bin/bash
# mettre_a_jour_index.sh
NOM_INDEX="monindexderecherche.bleve"
REPERTOIRE_MISES_A_JOUR="./misesajour"
# Traiter les fichiers de mise à jour incrémentale
for fichier_maj in $REPERTOIRE_MISES_A_JOUR/miseajour_*.ndjson; do
if [ -f "$fichier_maj" ]; then
echo "Application de la mise à jour : $fichier_maj"
bleve bulk $NOM_INDEX "$fichier_maj"
# Déplacer les fichiers traités
mv "$fichier_maj" "$REPERTOIRE_MISES_A_JOUR/traites/"
fi
done
Script de surveillance et de vérification de santé
#!/bin/bash
# verification_sante.sh
NOM_INDEX="monindexderecherche.bleve"
FICHIER_JOURNAL="./sante.log"
{
echo "=== Vérification de santé $(date) ==="
echo "Nombre de documents : $(bleve count $NOM_INDEX)"
echo "Vérification de l'index : $(bleve check $NOM_INDEX 2>&1)"
echo "Champs : $(bleve fields $NOM_INDEX)"
} >> $FICHIER_JOURNAL
Modèles d'automatisation avancés
Utilisation de Makefile pour gérer le cycle de vie des index
.PHONY: index clean query stats
INDEX := monindex.bleve
DONNEES := donnees/*.ndjson
index: clean
bleve create $(INDEX)
bleve bulk --batch 5000 $(INDEX) $(DONNEES)
clean:
rm -rf $(INDEX)
query:
bleve query $(INDEX) "$(q)"
stats:
bleve count $(INDEX)
bleve fields $(INDEX)
Intégration au pipeline CI/CD
# .github/workflows/index-recherche.yml
name: Construction de l'index de recherche
on:
push:
branches: [ main ]
schedule:
- cron: '0 2 * * *' # Exécution quotidienne à 2h du matin
jobs:
construire-index:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configurer Go
uses: actions/setup-go@v3
with:
go-version: '1.19'
- name: Installer la CLI Bleve
run: go install github.com/blevesearch/bleve/v2/cmd/bleve@latest
- name: Construire l'index de recherche
run: |
bleve create index_recherche.bleve
bleve bulk index_recherche.bleve donnees/*.ndjson
bleve count index_recherche.bleve
- name: Téléverser l'artefact de l'index
uses: actions/upload-artifact@v3
with:
name: index-recherche
path: index_recherche.bleve
Optimisation des performances et meilleures pratiques
Optimisation du traitement par lots
# Ajuster la taille du lot selon la mémoire système
MEMOIRE_GO=$(free -g | awk '/Mem:/ {print $2}')
TAILLE_LOT=$((MEMOIRE_GO * 500))
bleve bulk --batch $TAILLE_LOT monindex.bleve donnees.ndjson
Script de traitement parallèle
#!/bin/bash
# indexation_parallele.sh
NOM_INDEX="monindex.bleve"
FICHIERS_DONNEES=("donnees1.ndjson" "donnees2.ndjson" "donnees3.ndjson")
# Traiter plusieurs fichiers en parallèle
for fichier in "${FICHIERS_DONNEES[@]}"; do
(bleve bulk $NOM_INDEX "$fichier") &
done
# Attendre que toutes les tâches d'arrière-plan soient terminées
wait
echo "Tous les fichiers traités"
Gestion des erreurs et journalisation
Dans un environnement de production, un mécanisme robuste de gestion des erreurs est essentiel :
#!/bin/bash
# indexation_securisee.sh
NOM_INDEX="monindex.bleve"
FICHIER_JOURNAL="./journal_indexation.log"
indexer_fichier() {
local fichier=$1
echo "$(date): Début de l'indexation de $fichier" >> $FICHIER_JOURNAL
if bleve bulk $NOM_INDEX "$fichier" 2>> $FICHIER_JOURNAL; then
echo "$(date): Succès de l'indexation de $fichier" >> $FICHIER_JOURNAL
return 0
else
echo "$(date): Échec de l'indexation de $fichier" >> $FICHIER_JOURNAL
return 1
fi
}
# Traiter tous les fichiers de données
for fichier in donnees/*.ndjson; do
if ! indexer_fichier "$fichier"; then
echo "Erreur critique : Échec de l'indexation de $fichier" >&2
exit 1
fi
done
En exploitant judicieusement ces caractéristiques et ces modèles d'automatisation de la CLI Bleve, vous pouvez construire un système de gestion d'index de recherche efficace et fiable, améliorant considérablement l'efficacité du développement et des opérations.
Meilleures pratiques pour l'indexation par lots de données à grande échelle
Dans les scénarios d'indexation de données à grande échelle, les opérations par lots constituent une technologie clé pour améliorer les performances et l'efficacité. Bleve offre un mécanisme complet d'indexation par lots. Grâce au contrôle approprié de la taille des lots, au traitement concurrent et à la gestion de la mémoire, il est possible d'améliorer considérablement la vitesse de construction des index.
Mécanisme central de l'indexation par lots
L'indexation par lots de Bleve utilise la structure Batch, qui combine plusieurs opérations d'indexation et de suppression, les exécutant en une seule transaction. Ce mécanisme réduit le nombre d'opérations d'E/S disque et les conflits de verrouillage, particulièrement adapté aux scénarios d'importation de données à grande échelle.
// Exemple de création d'index par lots
lot := index.NouveauLot()
// Ajouter des documents en lots
for i, element := range elements {
lot.Indexer(fmt.Sprintf("document-%d", i), element)
// Soumettre le lot tous les 1000 documents
if lot.Taille() >= 1000 {
err := index.Lot(lot)
if err != nil {
log.Printf("Échec de l'indexation par lots : %v", err)
}
lot.Reinitialiser() // Réinitialiser le lot pour continuer
}
}
// Soumettre les documents restants
if lot.Taille() > 0 {
err := index.Lot(lot)
if err != nil {
log.Printf("Échec de la soumission du lot final : %v", err)
}
}
Stratégies d'optimisation de la taille des lots
Le choix de la taille des lots affecte directement les performances d'indexation. La taille par défaut de Bleve est de 1000, mais elle doit être ajustée dynamiquement selon les caractéristiques des données et la configuration matérielle :
Gestion de la mémoire et surveillance des performances
L'indexation par lots à grande échelle nécessite une attention particulière à l'utilisation de la mémoire. Bleve propose des interfaces de surveillance de la mémoire :
// Surveillance mémoire et ajustement adaptatif
func indexationAdaptative(index bleve.Index, elements []interface{}) error {
lot := index.NouveauLot()
tailleLotOptimale := 1000
memoireMaxMo := 512 // Définir la limite de mémoire maximale
for i, element := range elements {
lot.Indexer(fmt.Sprintf("document-%d", i), element)
// Surveiller l'utilisation de la mémoire
if lot.TailleTotaleDocuments() > uint64(memoireMaxMo*1024*1024) {
// Mémoire dépassée, soumettre immédiatement et réduire la taille du lot
if err := index.Lot(lot); err != nil {
return err
}
lot.Reinitialiser()
tailleLotOptimale = max(100, tailleLotOptimale/2) // Réduire la taille du lot
}
if lot.Taille() >= tailleLotOptimale {
if err := index.Lot(lot); err != nil {
return err
}
lot.Reinitialiser()
// Ajuster dynamiquement la taille du lot selon les performances
tailleLotOptimale = min(5000, tailleLotOptimale+100)
}
}
// Soumettre les documents restants
if lot.Taille() > 0 {
return index.Lot(lot)
}
return nil
}
Modèles de traitement concurrent par lots
Pour les ensembles de données ultra-volumineux, un modèle de traitement concurrent par lots peut être adopté pour充分利用 les ressources CPU multicœurs :
// Processeur d'indexation concurrent par lots
type IndexeurConcurrent struct {
index bleve.Index
tailleLot int
workers int
fileAttente chan interface{}
groupeAttente sync.WaitGroup
canalErreurs chan error
}
func NouveauIndexeurConcurrent(index bleve.Index, tailleLot, workers int) *IndexeurConcurrent {
return &IndexeurConcurrent{
index: index,
tailleLot: tailleLot,
workers: workers,
fileAttente: make(chan interface{}, 10000),
canalErreurs: make(chan error, workers),
}
}
func (c *IndexeurConcurrent) Demarrer() {
for i := 0; i < c.workers; i++ {
c.groupeAttente.Add(1)
go c.travailleur(i)
}
}
func (c *IndexeurConcurrent) travailleur(id int) {
defer c.groupeAttente.Done()
lot := c.index.NouveauLot()
compteur := 0
for element := range c.fileAttente {
idDocument := fmt.Sprintf("document-%d-%d", id, compteur)
if err := lot.Indexer(idDocument, element); err != nil {
c.canalErreurs <- fmt.Errorf("travailleur %d : %v", id, err)
return
}
compteur++
if lot.Taille() >= c.tailleLot {
if err := c.index.Lot(lot); err != nil {
c.canalErreurs <- fmt.Errorf("travailleur %d soumission lot : %v", id, err)
return
}
lot.Reinitialiser()
}
}
// Soumettre les documents restants
if lot.Taille() > 0 {
if err := c.index.Lot(lot); err != nil {
c.canalErreurs <- err
}
}
}
Gestion des erreurs et mécanisme de reprise
L'indexation par lots à grande échelle doit inclure une gestion des erreurs robuste et un mécanisme de reprise :
// Fonction de soumission par lots avec reprise
func soumettreAvecReprise(index bleve.Index, lot *bleve.Lot, tentativesMax int) error {
var derniereErreur error
for tentative := 0; tentative < tentativesMax; tentative++ {
if tentative > 0 {
time.Sleep(time.Duration(tentative*tentative) * time.Second) // Recul exponentiel
}
if err := index.Lot(lot); err != nil {
derniereErreur = err
log.Printf("Échec de la soumission par lots tentative %d : %v", tentative+1, err)
continue
}
return nil
}
return fmt.Errorf("Échec de la soumission par lots après %d tentatives : %v", tentativesMax, derniereErreur)
}
// Gestion des erreurs au niveau du document
func indexationSecurisee(lot *bleve.Lot, idDocument string, donnees interface{}) error {
defer func() {
if r := recover(); r != nil {
log.Printf("Panic lors de l'indexation du document %s : %v", idDocument, r)
}
}()
return lot.Indexer(idDocument, donnees)
}
Surveillance des indicateurs de performance
Établir un système complet de surveillance des performances pour suivre en temps réel les indicateurs clés de l'indexation par lots :
| Indicateur de surveillance | Description | Objectif d'optimisation |
|---|---|---|
| Temps de soumission de lot | Durée de soumission d'un lot unique | < 500ms |
| Pic d'utilisation mémoire | Utilisation mémoire pendant le traitement des lots | < 80% de la mémoire système |
| Débit E/S disque | Vitesse d'écriture de l'index sur disque | Correspondre aux performances de stockage |
| Utilisation CPU | Utilisation CPU pendant le traitement de l'index | 70-90% |
| Débit de traitement des documents | Nombre de documents traités par seconde | Maximiser le débit |
// Structure de surveillance des performances
type MetriquesIndexation struct {
Debut time.Time
DocumentsTotaux int64
DocumentsTermines int64
NombreLots int64
DureeTotale time.Duration
DureeLotMax time.Duration
DureeLotMin time.Duration
DureeLotTotale time.Duration
PicMemoire uint64
}
// Surveillance des performances en temps réel
func surveillerPerformances(metriques *MetriquesIndexation, tailleLot int, tempsLot time.Duration) {
metriques.NombreLots++
metriques.DocumentsTermines += int64(tailleLot)
metriques.DureeLotTotale += tempsLot
if tempsLot > metriques.DureeLotMax {
metriques.DureeLotMax = tempsLot
}
if metriques.DureeLotMin == 0 || tempsLot < metriques.DureeLotMin {
metriques.DureeLotMin = tempsLot
}
// Sortie en temps réel des indicateurs de performance
if metriques.NombreLots%10 == 0 {
tempsLotMoyen := time.Duration(int64(metriques.DureeLotTotale) / metriques.NombreLots)
documentsParSec := float64(metriques.DocumentsTermines) / time.Since(metriques.Debut).Seconds()
log.Printf("Indicateurs de performance : %d/%d documents traités, temps moyen de lot : %v, débit : %.1f documents/seconde",
metriques.DocumentsTermines, metriques.DocumentsTotaux, tempsLotMoyen, documentsParSec)
}
}
En appliquant ces meilleures pratiques, vous pouvez construire une solution d'indexation par lots de données à grande échelle efficace et stable, exploitant pleinement les avantages de Bleve en termes de performances dans les scénarios de forte concurrence et de gros volume de données.
Stratégies de déploiement de Bleve en environnement distribué
Lors de la construction d'une solution de recherche d'entreprise, le déploiement distribué est essentiel pour garantir la haute disponibilité, l'évolutivité et la tolérance aux pannes. Bleve, en tant que bibliothèque d'indexation textuelle moderne écrite en Go, ne fournit pas nativement de fonctionnalités distribées. Cependant, grâce à une conception architecturale appropriée et l'utilisation d'outils externes, il est tout à fait possible de construire un système de recherche distribué puissant.