Aperçu
La recherche hybride dans Fess combine la recherche traditionnelle par mots-clés (BM25) avec la recherche sémantique (vectorielle), puis fusionne les deux ensembles de résultats grâce au Rank Fusion afin de produire des classements plus précis et plus pertinents. Le Rank Fusion intègre les résultats de plusieurs moteurs de recherche en un classement unique optimisé.
Dans Fess 15.9, la recherche sémantique (chunking de contenu + recherche vectorielle) est fournie comme une fonctionnalité du cœur. Une fois activée, le moteur de recherche sémantique est enregistré automatiquement auprès du Rank Fusion. Voir Recherche sémantique (chunking de contenu + recherche vectorielle) pour sa configuration.
La fonctionnalité Rank Fusion de Fess intègre plusieurs résultats de recherche pour fournir des résultats de recherche plus précis.
Qu’est-ce que le Rank Fusion
Le Rank Fusion est une technique qui combine les résultats de plusieurs algorithmes de recherche ou méthodes de notation (par exemple mots-clés/BM25 et recherche sémantique/vectorielle) pour générer un classement unique optimisé.
Principaux avantages :
Combine les forces de différents algorithmes
Améliore la précision de la recherche
Fournit des résultats de recherche diversifiés
Algorithmes pris en charge
Fess prend en charge l’algorithme RRF (Reciprocal Rank Fusion) pour le Rank Fusion.
RRF (Reciprocal Rank Fusion)
RRF calcule un score en additionnant l’inverse du rang de chaque document dans chaque résultat de recherche. Lorsqu’un document est récupéré par plusieurs moteurs de recherche, ses scores sont cumulés.
Formule
k: Paramètre constant qui contrôle l’influence du rang (par défaut : 20)rank(d): Rang du document d dans chaque résultat de recherche (base 0)Σ: Somme sur tous les moteurs de recherche dans lesquels le document d apparaît
Note
Lorsque Fess effectue la fusion (par défaut), l’algorithme est fixé à RRF et la pondération par moteur de recherche n’est pas prise en charge : la contribution de chaque moteur est additionnée avec le même poids, et le seul paramètre permettant d’ajuster la tendance du classement est rank.fusion.rank_constant. Lorsque la fusion est effectuée côté moteur de recherche, d’autres techniques de combinaison et une pondération par moteur sont disponibles (voir Rank Fusion dans le moteur de recherche).
Configuration
fess_config.properties
Configuration de base
| Propriété | Défaut | Description |
|---|---|---|
rank.fusion.window_size | 200 | Nombre maximum de résultats récupérés depuis chaque moteur de recherche pour la fusion. Doit être >= paging.search.page.max.size × 2 (200 par défaut) ; si une valeur inférieure est définie, elle est automatiquement relevée à ce minimum (un avertissement WARN est alors consigné au démarrage). |
rank.fusion.rank_constant | 20 | La constante k dans la formule RRF. Une valeur plus élevée réduit la différence de score entre les résultats mieux et moins bien classés. |
rank.fusion.threads | -1 | Nombre de threads du pool de threads fixe utilisé pour exécuter plusieurs moteurs de recherche en parallèle. Si 0 ou moins est spécifié, availableProcessors × 3 ÷ 2 + 1 est utilisé automatiquement (le calcul étant effectué en arithmétique entière, la partie décimale est tronquée ; par exemple : 4 cœurs → 7, 5 cœurs → 8). |
rank.fusion.score_field | rf_score | Nom du champ du document résultat utilisé pour stocker le score fusionné. |
Note
Moment de prise en compte des réglages
Les quatre réglages ci-dessus nécessitent tous un redémarrage de Fess pour que leur modification prenne effet. Les valeurs lues depuis fess_config.properties sont mises en cache dans la JVM : modifier le fichier pendant que Fess est en cours d’exécution reste donc sans effet.
À titre indicatif, rank.fusion.window_size n’est lu qu’une seule fois au démarrage, et rank.fusion.threads au moment de la création du pool de threads. Le pool de threads étant créé lorsqu’un moteur de recherche autre que default (le moteur de recherche sémantique, par exemple) est enregistré, aucun pool n’est créé lorsque la recherche sémantique est désactivée.
Propriétés système JVM
Les moteurs de recherche à utiliser sont spécifiés en tant que propriété système JVM. Ajoutez la ligne suivante dans fess.in.sh
Pour fess.in.bat, écrivez plutôt
Ce paramètre se comporte comme suit :
Il est défini en tant qu’option JVM, et non dans
fess_config.properties. Le nom de la clé doit être exactementrank.fusion.searchers. Les formes préfixées couramment employées pour les autres réglages,-Dfess.config.ou-Dfess.system.(par exemple-Dfess.config.rank.fusion.searchers), ne sont pas reconnues.À la place d’une option JVM, vous pouvez également le saisir sur une seule ligne, sous la forme
rank.fusion.searchers=default,semantic_chunk, dans le champ « Propriétés système » de la page « Système > Général » de l’interface d’administration. Notez que la valeur de ce champ n’est appliquée que si aucune propriété système du même nom n’est déjà définie. Une option-Dest donc prioritaire, et modifier une valeur déjà appliquée nécessite un redémarrage de Fess.defaultest le moteur qui effectue la recherche standard par mots-clés ; il est toujours disponible.Le nom d’un moteur de recherche est dérivé du nom de sa classe d’implémentation : on en retire le suffixe
Searcher, puis on convertit le reste en snake_case minuscule (SemanticChunkSearcher→semantic_chunk). Le moteur de recherche sémantique intégré au cœur (Recherche sémantique (chunking de contenu + recherche vectorielle)) est enregistré sous le nomsemantic_chunk.Si ce paramètre n’est pas spécifié, tous les moteurs enregistrés sont utilisés. Si aucun des noms spécifiés ne correspond à un moteur enregistré, seul le moteur
defaultest utilisé. Si vous utilisez le moteur de recherche sémantique intégré au cœur (Recherche sémantique (chunking de contenu + recherche vectorielle)), vous n’avez normalement pas besoin de définir ce paramètre du tout.La fusion des résultats n’est effectuée que lorsque deux moteurs de recherche ou plus sont disponibles. Lorsqu’un seul moteur est disponible, aucune fusion n’est effectuée et les résultats de recherche normaux sont retournés.
Avertissement
Si vous utilisiez auparavant le plugin fess-webapp-semantic-search de Fess 15.7 ou antérieur, il vous a peut-être été indiqué de définir ce paramètre sur -Drank.fusion.searchers=default,semantic. Ce plugin enregistrait son moteur de recherche sous le nom semantic, qui est un moteur de recherche différent du nom du moteur intégré au cœur, semantic_chunk, introduit en 15.9. Si vous reportez ce réglage datant de la 15.7 tel quel dans la 15.9, la liste blanche n’inclut jamais semantic_chunk, de sorte que la recherche sémantique intégrée au cœur (chunking de contenu + recherche vectorielle) ne fonctionne pas du tout — Fess continue de renvoyer silencieusement des résultats de recherche par mots-clés ordinaires (un avertissement est consigné au démarrage, mais l’exclusion par requête elle-même n’est consignée qu’au niveau DEBUG). Si votre configuration spécifie default,semantic, supprimez ce réglage ou ajoutez-y semantic_chunk. Voir « Migration depuis la version 15.7 ou antérieure » dans Recherche sémantique (chunking de contenu + recherche vectorielle) pour plus de détails.
Rank Fusion dans le moteur de recherche
Définir rank.fusion.engine.enabled=true confie la fusion à OpenSearch plutôt qu’à Fess. Les requêtes des moteurs sont combinées en une seule requête de recherche (une requête hybrid), et un pipeline de recherche OpenSearch normalise et combine les scores. La fusion ayant lieu en une seule requête, le nombre total de résultats et le nombre de résultats des facettes portent eux aussi sur l’ensemble de résultats fusionné.
Cette fonctionnalité nécessite le plugin neural-search d’OpenSearch. Il est inclus dans la distribution standard d’OpenSearch et dans l’image ghcr.io/codelibs/fess-opensearch, mais pas dans la distribution minimale.
Les réglages se placent dans fess_config.properties (toute modification nécessite un redémarrage de Fess)
| Propriété | Défaut | Description |
|---|---|---|
rank.fusion.engine.enabled | false | true confie la fusion au moteur de recherche. |
rank.fusion.combination.technique | rrf | Méthode de combinaison des scores : rrf, arithmetic_mean, geometric_mean ou harmonic_mean. Avec rrf, rank.fusion.rank_constant est utilisé comme constante k, ce qui donne la même formule que lorsque Fess effectue la fusion. |
rank.fusion.normalization.technique | min_max | Méthode de normalisation des scores avant leur combinaison : min_max, l2 ou z_score. Non utilisé par rrf. |
rank.fusion.combination.weights | (vide) | Poids de chaque moteur de recherche, sous forme de paires nom:poids séparées par des virgules (par exemple default:0.7,semantic_chunk:0.3). Chaque poids doit être compris entre 0.0 et 1.0, la somme des poids doit valoir 1.0, et chaque moteur participant à la fusion doit être nommé. Si la valeur est vide, les moteurs ont tous le même poids. Une valeur qui ne respecte pas ces règles est signalée par un journal ERROR, et la recherche concernée est fusionnée par Fess. |
rank.fusion.pagination_depth | 1000 | Nombre de résultats que chaque moteur de recherche fournit à la fusion, par shard. Cette valeur borne la profondeur de pagination accessible à un client ainsi que l’ensemble des documents fusionnés : une recherche fusionnée côté moteur de recherche peut paginer au plus ce nombre de résultats. La valeur envoyée au moteur de recherche ne dépasse jamais indexer.max.result.window.size. |
Note
La normalisation z_score ne peut être combinée qu’avec arithmetic_mean. Il s’agit d’une restriction du plugin neural-search. Si elle est combinée avec geometric_mean ou harmonic_mean, Fess refuse cette combinaison, consigne un journal ERROR qui nomme les deux paramètres et fusionne lui-même la recherche concernée.
Dans les cas suivants, la fusion n’est pas effectuée côté moteur de recherche, et c’est Fess qui fusionne les résultats à la place.
Une recherche comportant des paramètres de recherche avancée (
as.*)Une recherche qui spécifie un critère de tri, une recherche par géolocalisation ou une recherche de documents similaires. Celles-ci ignorent entièrement la recherche sémantique, de sorte que les résultats proviennent uniquement de la recherche par mots-clés (voir Recherche sémantique (chunking de contenu + recherche vectorielle)).
Une valeur de
rank.fusion.combination.weightsqui ne respecte pas les règles ci-dessusLa normalisation
z_scorecombinée avecgeometric_meanouharmonic_mean(un journal ERROR nomme les deux paramètres)OpenSearch ne peut pas du tout exécuter de requêtes fusionnées : il ne connaît pas la requête
hybridou le processeur du pipeline de recherche, par exemple parce que le plugin neural-search est absent ou trop ancien. Un journal WARN est consigné pour chacune de ces recherches, et la recherche suivante interroge de nouveau le moteur de recherche : la fusion par le moteur reprend d’elle-même, sans redémarrer Fess, dès que le plugin est installé ou mis à jour.
Tout autre échec d’une requête fusionnée (requête invalide, index fermé, défaillance d’un shard, etc.) n’est signalé que pour la recherche concernée, comme sans fusion côté moteur de recherche, et la recherche suivante est de nouveau fusionnée côté moteur de recherche.
Gardez les points suivants à l’esprit lorsque la fusion est effectuée côté moteur de recherche.
rank.fusion.timeoutne s’applique pas. L’embedding de la requête est calculé de manière synchrone avant l’envoi de la requête de recherche : un fournisseur d’embedding lent ou qui ne répond pas retarde donc la recherche jusqu’au délai d’expiration propre à ce fournisseur (par exemplecontent_chunker.embedding.ollama.timeout). Si le fournisseur effectue de nouvelles tentatives, elles s’ajoutent à ce délai. Par exemple, le fournisseur intégréopensearchrépète une attente decontent_chunker.embedding.opensearch.timeout(60000ms par défaut) jusqu’àcontent_chunker.embedding.opensearch.retry.max(3par défaut) fois : un fournisseur qui ne répond pas peut donc retarder une recherche de 180 secondes par défaut, plus les attentes entre les tentatives.rank.fusion.window_sizeetrank.fusion.threadsne sont utilisés que lorsque Fess effectue la fusion.Une recherche fusionnée peut paginer au plus
rank.fusion.pagination_depthrésultats, car le moteur de recherche ne fusionne que lesrank.fusion.pagination_depthpremiers résultats de chaque moteur, par shard. Le nombre de pages, le lien vers la page suivante et les numéros de page s’arrêtent là, et une page dont la position de départ (start) vautrank.fusion.pagination_depthou plus est refusée avec la même erreur qu’une page au-delà deindex.max_result_windowpour toute autre recherche (dans l’API de recherche v2, HTTP 400 avecinvalid_request). Une page qui commence après le dernier résultat fusionné mais dans cette limite (par exemple depuis un lien périmé) est renvoyée vide. Les recherches qui ne sont pas fusionnées côté moteur de recherche peuvent toujours paginer jusqu’àindex.max_result_window.Le nombre total de résultats est exact tant qu’il reste inférieur à
rank.fusion.pagination_depth. À partir de cette valeur, le moteur de recherche peut compter moins de résultats qu’il n’y en a réellement : le nombre est donc signalé comme une borne inférieure (dans l’API de recherche,record_count_relationvautGREATER_THAN_OR_EQUAL_TO).Augmenter
rank.fusion.pagination_depthpermet de paginer plus loin, mais chaque recherche fusionnée collecte ce nombre de résultats par moteur et par shard : toutes les recherches sont donc ralenties, pas seulement les pages profondes.Le
kde la requête knn du moteur de recherche sémantique (le nombre de voisins par shard) estcontent_chunker.search.knn.k. Une recherche vectorielle renvoie des voisins même lorsque leur similarité est faible : sanscontent_chunker.search.min_score, le nombre total de résultats inclut donc ces résultats vectoriels et, sur un petit index, il peut couvrir la plupart des documents visibles par l’utilisateur. Définissezcontent_chunker.search.min_scorepour le restreindre (voir Recherche sémantique (chunking de contenu + recherche vectorielle)).Le champ
searcherest ajouté aux résultats comme d’habitude, mais pasrf_score.
Intégration avec la recherche hybride
Le Rank Fusion est particulièrement efficace pour la recherche hybride, qui combine la recherche par mots-clés et la recherche sémantique. Pour utiliser la recherche sémantique, configurez la fonctionnalité de chunking de contenu, puis définissez content_chunker.search.enabled=true.
Avertissement
Les réglages content_chunker.*, tels que content_chunker.enabled ou content_chunker.search.enabled, sont des propriétés système et non des réglages de fess_config.properties. Définissez-les dans conf/system.properties, ou fournissez-les en tant qu’option JVM sous la forme -Dfess.system.content_chunker.search.enabled=true. Les écrire dans fess_config.properties reste sans effet. Par ailleurs, content_chunker.search.enabled n’étant évalué qu’au démarrage, un redémarrage de Fess est nécessaire après son activation.
Voir Recherche sémantique (chunking de contenu + recherche vectorielle) pour plus de détails.
Vérification des résultats de fusion
Deux champs ajoutés aux résultats de recherche permettent de vérifier que le Rank Fusion est réellement à l’œuvre.
| Champ | Contenu |
|---|---|
searcher | Tableau des noms des moteurs de recherche ayant récupéré le document (par exemple ["default", "semantic_chunk"]). Lorsque les deux y figurent, le document a été trouvé à la fois par la recherche par mots-clés et par la recherche sémantique. |
rf_score | Score fusionné calculé par RRF. Le nom du champ peut être modifié via rank.fusion.score_field. |
Ces deux valeurs sont ajoutées dynamiquement au moment de la recherche et ne sont pas stockées dans l’index. Elles ne figurent pas non plus par défaut dans la réponse de /api/v2/search : pour les consulter, ajoutez la ligne suivante dans fess_config.properties, puis redémarrez Fess
Note
query.additional.api.response.fields ajoute des entrées à la liste blanche des champs autorisés dans la réponse de l’API de recherche v2. N’y ajoutez pas de champs de contrôle d’accès tels que role ou virtual_host : les informations de contrôle d’accès seraient alors exposées dans la réponse de l’API de recherche.
Impact sur le nombre de résultats
Lorsque Fess exécute le Rank Fusion, le nombre total de résultats retourné n’est pas celui du moteur principal (le moteur default, enregistré en tête de liste) tel quel : il est corrigé comme suit
La correction correspond au nombre de documents figurant parmi les window_size ÷ 2 premiers résultats fusionnés, mais absents des window_size ÷ 2 premiers résultats du moteur principal. Autrement dit, le nombre de résultats augmente du nombre de documents trouvés uniquement par la recherche sémantique. Pour une même requête, le nombre de résultats peut donc varier selon que la recherche hybride est activée ou non.
À noter : lorsque le nombre total de résultats du moteur principal est retourné sous forme de valeur approchée (borne inférieure), cette correction n’est pas appliquée. Les nombres de résultats des facettes (étiquettes, etc.) sont eux aussi repris tels quels des résultats du moteur principal.
Lorsque la fusion est effectuée côté moteur de recherche (voir Rank Fusion dans le moteur de recherche), le nombre total de résultats et les nombres de résultats des facettes portent sur l’union des résultats de la recherche par mots-clés et de la recherche sémantique. Chaque moteur apporte au plus rank.fusion.pagination_depth résultats par shard, et le moteur sémantique est en outre limité par content_chunker.search.knn.k. Pour une même requête, le nombre total de résultats et ceux des facettes diffèrent donc selon rank.fusion.engine.enabled ; sur un petit index, ils tendent à être plus élevés lorsque la fusion est effectuée côté moteur de recherche, car la recherche sémantique apporte ses résultats.
Exemples d’utilisation
Recherche hybride de base
Calculer le score BM25 avec la recherche par mots-clés
Calculer la similarité vectorielle avec la recherche sémantique
Fusionner les deux résultats avec RRF
Générer le classement final
Flux de recherche
Considérations de performance
Utilisation de la mémoire
L’utilisation de la mémoire augmente car plusieurs résultats de recherche sont conservés.
Utilisez
rank.fusion.window_sizepour limiter le nombre maximum de résultats à fusionner. Le moteur principal (le moteurdefaulten tête de liste) récupère jusqu’àwindow_sizerésultats, tandis que chacun des autres moteurs récupèrewindow_size ÷ nombre de moteursrésultats (lenombre de moteurscorrespond au total, moteur principal inclus, et la division est tronquée).Par exemple, avec deux moteurs (
defaultetsemantic_chunk) etwindow_size=200, le moteur principal récupère 200 résultats et le moteur sémantique 100 : au maximum 300 documents sont donc conservés.
Avertissement
rank.fusion.window_size ne peut pas descendre en dessous de paging.search.page.max.size × 2. Lorsque paging.search.page.max.size conserve sa valeur par défaut 100, la borne inférieure vaut 200, soit exactement la valeur par défaut de rank.fusion.window_size. Autrement dit, dans la configuration par défaut, window_size ne peut pas être réduit en dessous de sa valeur par défaut. Si une valeur plus petite est définie, un avertissement WARN est consigné au démarrage et la valeur est relevée à 200. Pour la réduire réellement, il faut d’abord abaisser paging.search.page.max.size, ce qui réduit du même coup le nombre maximum de résultats qu’un client peut demander par page dans l’écran de recherche comme dans l’API.
Temps de traitement
Le temps de réponse augmente car plusieurs recherches sont exécutées.
Utilisez
rank.fusion.threadspour définir le nombre de threads pour l’exécution parallèle.
Note
Lorsque Fess effectue la fusion, les moteurs de recherche autres que le moteur principal sont attendus au plus rank.fusion.timeout millisecondes (par défaut 10000). Un moteur qui n’a pas répondu dans ce délai est écarté de cette recherche, et les résultats sont marqués comme partiels (délai dépassé). Le moteur principal est toujours attendu. Une valeur de 0 ou moins attend sans limite. Ce réglage ne s’applique pas lorsque la fusion est effectuée côté moteur de recherche (voir Rank Fusion dans le moteur de recherche).
Comportement en cas d’échec d’un moteur de recherche
Lorsqu’un moteur de recherche échoue sur une exception, ses résultats sont traités comme vides : un avertissement WARN est consigné, puis la fusion se poursuit avec les seuls résultats des autres moteurs. La requête de recherche elle-même n’échoue pas.
Font toutefois exception les erreurs de syntaxe de requête (InvalidQueryException) et les dépassements de la limite de pagination (ResultOffsetExceededException) : celles-ci sont retournées telles quelles en tant qu’erreurs. Par ailleurs, sur les pages profondes où la fusion n’est pas effectuée (où position de début × 2 est supérieur ou égal à rank.fusion.window_size), une exception levée par le moteur principal est retournée telle quelle en tant qu’erreur de la requête de recherche.
Le moteur de recherche sémantique retourne des résultats vides lorsqu’il ne parvient pas à joindre le fournisseur d’embedding ou que le calcul des embeddings échoue. Là encore, aucune erreur n’est levée : seuls les résultats de la recherche par mots-clés sont retournés.
Dépannage
Les résultats de recherche diffèrent des attentes
Symptôme : Les résultats après Rank Fusion diffèrent des attentes
Vérifications :
Vérifier le champ
searcher(voir « Vérification des résultats de fusion »). Si tous les documents ne contiennent que["default"], le moteur de recherche sémantique ne retourne aucun résultat.Vérifier que la recherche sémantique n’est pas ignorée. Outre les requêtes contenant une syntaxe de recherche telle que des phrases ou des caractères génériques, les recherches triées, la recherche par géolocalisation et la recherche de documents similaires font que le moteur de recherche sémantique ne retourne aucun résultat : seuls les résultats de la recherche par mots-clés sont alors renvoyés. Voir Recherche sémantique (chunking de contenu + recherche vectorielle) pour le détail des conditions d’exclusion.
Vérifier les résultats de chaque type de recherche individuellement
Ajuster la valeur de
rank.fusion.rank_constantSur les pages profondes (où
position de début × 2est supérieur ou égal àrank.fusion.window_size, soit à partir du 101e résultat avec les valeurs par défaut), la fusion n’est pas effectuée et seul le moteur principal est utilisé. Pour obtenir des résultats fusionnés sur davantage de pages, augmentezrank.fusion.window_size. Lorsque la fusion est effectuée côté moteur de recherche, cette limite n’existe pas : toutes les pages sont fusionnées, jusqu’àrank.fusion.pagination_depthrésultats (voir Rank Fusion dans le moteur de recherche).
La recherche est lente
Symptôme : La recherche devient lente lorsque le Rank Fusion est activé
Solutions :
Ajuster
rank.fusion.threadsRéduire
rank.fusion.window_size. Cette valeur ne pouvant pas descendre en dessous de sa borne inférieure (paging.search.page.max.size × 2), les deux réglages suivants doivent être définis ensemble dans la configuration par défautNotez que le nombre maximum de résultats pouvant être demandés par page diminue lui aussi. Un redémarrage est nécessaire après ces modifications.
Lorsque la fusion est effectuée côté moteur de recherche, réduire
rank.fusion.pagination_depth. La profondeur de pagination des résultats fusionnés diminue elle aussi. Un redémarrage est nécessaire après cette modification.
Mémoire insuffisante
Symptôme : Une erreur OutOfMemoryError se produit
Solutions :
Réduire
rank.fusion.window_sizeen suivant la même procédure que dans « La recherche est lente »Augmenter la taille du tas JVM
Référence
Recherche sémantique (chunking de contenu + recherche vectorielle) - Configuration de la recherche sémantique (chunking de contenu)
Apercu du scripting - Aperçu du scripting
Paramètres avancés liés à la recherche - Configuration avancée de la recherche
Vue d’ensemble du mode de recherche IA (RAG) et de l’intégration LLM - Guide d’intégration LLM (Recherche sémantique)