Il y a six mois, j'ai expliqué pourquoi nous avions remplacé ClickHouse par Apache Doris en tant que moteur OLAP pour notre système de gestion de données. À l’époque, nous avions du mal avec la génération automatique d’instructions SQL. Au fil des jours, nous avons fait des progrès suffisamment importants pour être des références pour vous, alors me revoilà.
Nous avons adopté des modèles de langage étendus (LLM) pour renforcer nos services OLAP basés sur Doris.
Notre motivation était d'épargner à notre personnel interne la courbe d'apprentissage abrupte de l'écriture SQL. Ainsi, nous avons utilisé le LLM comme intermédiaire. Il transforme les questions en langage naturel en instructions SQL et envoie les SQL au moteur OLAP pour exécution.
Comme toute expérience liée à l’IA, nous avons rencontré quelques frictions :
LLM ne comprend pas les jargons de données, comme les « champs », les « lignes », les « colonnes » et les « tableaux ». Au lieu de cela, ils peuvent parfaitement traduire des termes commerciaux tels que « revenu d'entreprise » et « DAU », qui correspondent essentiellement à l'objet des champs/lignes/colonnes. Cela signifie que cela ne peut fonctionner correctement que si les analystes utilisent exactement le bon mot pour faire référence à la mesure dont ils ont besoin lors de la saisie de leurs questions.
Le LLM que nous utilisons est lent à inférence. Il faut plus de 10 secondes pour répondre. Comme il facture des frais par jeton, la rentabilité devient un problème.
Bien que le LLM soit formé sur une vaste collection d’ensembles de données publiques, il est sous-informé des connaissances de niche. Dans notre cas, le LLM est très peu familier avec les chansons indépendantes, donc même si les chansons sont incluses dans notre base de données, le LLM ne sera pas en mesure de les identifier correctement.
Parfois, nos questions de saisie nécessitent des informations juridiques, politiques, financières et réglementaires adéquates et récentes, qu'il est difficile d'inclure dans un ensemble de données de formation ou une base de connaissances. Nous devons connecter le LLM à des bases d'informations plus larges afin d'effectuer des tâches plus diversifiées.
Nous résolvons ces problèmes un par un.
Pour le problème n°1, nous introduisons une couche sémantique entre le LLM et le moteur OLAP. Cette couche traduit les termes métier dans les champs de données correspondants. Il peut identifier les conditions de filtrage des données à partir des différentes formulations en langage naturel, les relier aux métriques impliquées, puis générer des instructions SQL.
En plus de cela, la couche sémantique peut optimiser la logique de calcul. Lorsque les analystes saisissent une question qui implique une requête complexe, par exemple une jointure multi-tables, la couche sémantique peut la diviser en plusieurs requêtes mono-tables pour réduire la distorsion sémantique.
Pour augmenter la rentabilité de l'utilisation de LLM, nous évaluons la complexité de calcul de tous les scénarios, tels que le calcul de métriques, la récupération d'enregistrements détaillés et la segmentation des utilisateurs. Ensuite, nous créons des règles et consacrons l’étape d’analyse LLM aux tâches compliquées uniquement. Cela signifie que pour les tâches de calcul simples, l'analyse sera ignorée.
Par exemple, lorsqu'un analyste saisit « dites-moi les revenus des principales plateformes musicales », le LLM identifie que cette question n'implique que plusieurs métriques ou dimensions, il ne l'analysera donc pas davantage mais l'enverra directement pour la génération et l'exécution SQL. Cela peut considérablement réduire le temps de réponse aux requêtes et réduire les dépenses liées aux API.
Pour doter le LLM de connaissances de niche, nous avons ajouté un Schema Mapper en amont du LLM. Le Schema Mapper mappe la question d'entrée à une base de connaissances externe, puis le LLM effectuera l'analyse.
Nous testons et optimisons constamment le Schema Mapper. Nous catégorisons et évaluons le contenu dans la base de connaissances externe, et effectuons différents niveaux de cartographie (cartographie de texte intégral et cartographie floue) pour permettre une meilleure analyse sémantique.
Nous avons utilisé des plugins pour connecter le LLM à davantage de champs d'informations, et nous avons différentes méthodes d'intégration pour différents types de plugins :
Intégration de fichiers locaux : Ceci est particulièrement utile lorsque nous devons « enseigner » au LLM les dernières politiques réglementaires, qui sont souvent des fichiers texte. Premièrement, le système vectorise le fichier texte local, exécute des recherches sémantiques pour trouver des termes correspondants ou similaires dans le fichier local, extrait le contenu pertinent et le place dans la fenêtre d'analyse LLM pour générer une sortie.
Plugins tiers : La Marketplace regorge de plugins tiers conçus pour toutes sortes de secteurs. Avec eux, le LLM est capable d'aborder des sujets très variés. Chaque plugin a ses propres invites et fonctions d'appel. Une fois que la question d’entrée atteint une invite, le plugin concerné sera appelé.
Une fois que nous avons terminé les quatre optimisations ci-dessus, le framework SuperSonic voit le jour.
Maintenant, laissez-moi vous expliquer ce cadre :
Un analyste saisit une question.
Le Schema Mapper mappe la question à une base de connaissances externe.
S'il existe des champs correspondants dans la base de connaissances externe, la question ne sera pas analysée par le LLM. Au lieu de cela, une formule de calcul de métrique déclenchera le moteur OLAP pour lancer l’interrogation. S'il n'y a pas de champ correspondant, la question entrera dans le LLM.
Sur la base des règles prédéfinies, le LLM évalue le niveau de complexité de la question. S'il s'agit d'une requête simple, elle ira directement au moteur OLAP ; s'il s'agit d'une requête compliquée, elle sera sémantiquement analysée et convertie en instruction DSL.
Au niveau de la couche sémantique, l'instruction DSL sera divisée en fonction de son scénario de requête. Par exemple, s'il s'agit d'une requête de jointure multi-tables, cette couche générera plusieurs instructions SQL de requête sur une seule table.
Exemple:
Pour savoir si une certaine chanson peut être interprétée dans des émissions de variétés, le système récupère l'entrepôt de données OLAP pour obtenir des détails sur la chanson et lui présente les résultats du plug-in tiers Commercial Use Query.
Quant à la partie OLAP de ce framework, après plusieurs cycles d'évolution architecturale, voici à quoi ressemble notre pipeline OLAP actuel.
Les données brutes sont triées en balises et métriques définies sur mesure par les analystes. Les balises et les métriques sont sous gestion unifiée afin d'éviter des définitions incohérentes. Ensuite, ils sont combinés en divers jeux de balises et de métriques pour diverses requêtes.
Nous avons tiré pour vous deux points principaux à retenir de notre expérience en optimisation architecturale.
1. Rationalisez les liens
Avant d'adopter Apache Doris, nous avions ClickHouse pour accélérer le calcul des balises et des métriques, et Elasticsearch pour traiter les données dimensionnelles. Cela représente deux moteurs analytiques et nous oblige à adapter les instructions de requête aux deux. C'était très exigeant.
Ainsi, nous avons remplacé ClickHouse par Apache Doris et utilisé la fonctionnalité Elasticsearch Catalog pour connecter les données Elasticsearch à Doris. De cette façon, nous faisons de Doris notre passerelle de requêtes unifiée.
2. Divisez les tables plates
Dans les premières versions de notre architecture OLAP, nous avions l'habitude de placer les données dans des tableaux plats, ce qui rendait les choses délicates. D’une part, les tables plates absorbaient toute la latence d’écriture en amont, ce qui s’ajoutait à une perte considérable d’actualité des données. D’autre part, 50 % des données d’un tableau plat étaient des données dimensionnelles, rarement mises à jour. Chaque nouvelle table plate était accompagnée de données dimensionnelles volumineuses qui consommaient beaucoup d'espace de stockage.
Par conséquent, nous divisons les tableaux plats en tableaux métriques et tableaux de dimensions. Comme ils sont mis à jour à des rythmes différents, nous les plaçons dans différents modèles de données.
Tableaux de métriques : nous organisons les données métriques dans le modèle Aggregate Key d'Apache Doris, ce qui signifie que les nouvelles données seront fusionnées avec les anciennes données via SUM, MAX, MIN, etc.
Tables de dimension : ces tables sont dans le modèle Unique Key d'Apache Doris, ce qui signifie que le nouvel enregistrement de données remplacera l'ancien. Cela peut considérablement augmenter les performances dans nos scénarios de requêtes.
Vous pourriez vous demander si cela pose des problèmes dans les requêtes, puisque la plupart des requêtes nécessitent des données provenant des deux types de tables ? Ne vous inquiétez pas, nous résolvons ce problème avec la fonctionnalité Rollup de Doris. Sur la base des tables de base, nous pouvons sélectionner les dimensions dont nous avons besoin pour créer des vues Rollup, qui exécuteront automatiquement GROUP BY
. Cela nous évite d'avoir à définir des balises pour chaque vue Rollup et accélère considérablement les requêtes.
D'après notre expérience avec Apache Doris, nous trouvons également d'autres fonctionnalités utiles, je les liste donc également ici pour vous :
1. Vue matérialisée
Une vue matérialisée est un ensemble de données pré-calculé. C'est un moyen d'accélérer les requêtes lorsque vous avez fréquemment besoin d'accéder à des données de certaines dimensions. Dans ces scénarios, nous définissons des balises et des métriques dérivées basées sur celles d'origine. Par exemple, nous créons une métrique dérivée en combinant Metric 1, Metric 2 et Metric 3 : sum(m1+m2+m3)
. Ensuite, nous pouvons créer une vue matérialisée pour cela. Selon le calendrier de publication de Doris, la version 2.1 prendra en charge les vues matérialisées multi-tables, et nous l'attendons avec impatience.
2. Connecteur Flink-Doris
Il s’agit d’une garantie Exactly-Once lors de l’ingestion de données. Le Flink-Doris-Connector implémente un mécanisme de point de contrôle et une validation en deux étapes, et permet la synchronisation automatique des données des bases de données relationnelles vers Doris.
3. Compactage
Lorsque le nombre de tâches d'agrégation ou le volume de données deviennent écrasants pour Flink, il peut y avoir une latence énorme dans le compactage des données. Nous résolvons ce problème avec le compactage vertical et le compactage par segments. Le compactage vertical prend en charge le chargement d'une partie seulement des colonnes, ce qui permet de réduire la consommation de stockage lors du compactage de tables plates. Le compactage des segments peut éviter de générer trop de segments lors de l'écriture des données et permet le compactage lors de l'écriture simultanée.
Dans le but de réduire les coûts et d'augmenter la disponibilité des services, nous prévoyons de tester la nouvelle séparation stockage-calcul et la réplication entre clusters de Doris, et nous acceptons toutes les idées et contributions concernant le framework SuperSonic et le projet Apache Doris.