Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending Khiops entries with a lightweight json structure for scenarios #230

Open
marcboulle opened this issue Apr 9, 2024 · 6 comments · May be fixed by #419
Open

Extending Khiops entries with a lightweight json structure for scenarios #230

marcboulle opened this issue Apr 9, 2024 · 6 comments · May be fixed by #419
Assignees
Labels
Priority/0 To do NOW Type/Enhancement New feature or request

Comments

@marcboulle
Copy link
Collaborator

Contexte: Khiops peut-être pilote via la ligne de commande via des scénarios

  • option -i: pour passer un fichier scenario en paramètre
  • option -r: pour faire des search/replace, permettant une variabilité via des scenarios rendus génériques

Ce mode de contrôle est intéressant pour intégrer rapidement des traitements Khiops et les lancer depuis n'importe quel
langage de programmation.
Par contre, c'est plus complexe dans le cas de de paramétrage plus complexe, comme par exemple l'ensemble
des table d'un schema en flocon. Dans ce cas, on doit passer un un algorithme de création de scénario comportant
potentiellement des boucles de search/replace.

Proposition d'évolution fonctionnelle:

  • étendre le formalisme des scénarios pour avoir quelques structures de contrôle
  • étendre le search/replace (-r) pour avoir une structure de donnée en entrée plutôt que des paires (key/value)

Intérêt de la fonctionnalité:

  • étend la facilité de pilotage de Khiops pour tous les utilisateurs/intégrateurs
  • facilite l'interfaçage avec tout langage de programmation
  • facilite la mise au point d'une API "officielle"
  • simplifie les évolutions d'AutoML

Ebauche de spécification, a titre illustratif

  • évolution des scenarios
    • structure de boucle: begin loop(tag), end loop (tag)
    • structure de conditionnement: begin if(tag), end if(tag)
    • tag d'encodage: khiops encoding(encoding type), pour l'encodage ascii, ansi, utf8... des paramètres
  • évolution des inputs: nouvelle option -j, pour prendre un json (léger) en entrée
    • le json est une liste de clé/valeurs
    • si valeur string: clé/valeur utilisée pour un search/replace
    • si valeur boolean: clé utilisée pour un tag de structure de conditionnement
    • si valeur de type array: clé utilisée pour un tag de structure de boucle
    • si autre type: erreur
    • limiter le niveau de profondeur des structure?

Ebauche d'étude d'impact:

  • on a un analyseur lexical de json (src/Learning/KWData/JsonLex.lex)
  • il est utilisé pour la relecture des fichiers de coclustering au format json (src/Learning/MODL_Coclustering/CCCoclusteringReport.h)
  • dans l'analyse de la ligne de commande, on traite déjà les search/replace dans les scenarios
  • globalement, cela ne devrait pas être couteux en développement
@alexisbondu alexisbondu added the Type/Enhancement New feature or request label Apr 10, 2024
@alexisbondu alexisbondu added the Priority/2 To do after P1 label Apr 10, 2024
@folmos-at-orange
Copy link
Contributor

// Dictionary file and class settings
ClassManagement.OpenFile
ClassFileName __dictionary_file_path__
OK
ClassManagement.ClassName __dictionary_name__

// Here would be a StopIfErrors

// Train/test database settings
TrainDatabase.DatabaseFiles.List.Key __dictionary_name__
TrainDatabase.DatabaseFiles.DataTableName __data_table_path__
__LOOP__ __additional_data_tables__
TrainDatabase.DatabaseFiles.List.Key __datapath__
TrainDatabase.DatabaseFiles.DataTableName __path__
__END_LOOP__
TrainDatabase.HeaderLineUsed __header_line__
TrainDatabase.FieldSeparator __field_separator__
__OPT__ __detect_format__
TrainDatabase.DatabaseFormatDetector.DetectFileFormat
__END_OPT__
TrainDatabase.SampleNumberPercentage __sample_percentage__
TrainDatabase.SamplingMode __sampling_mode__
TrainDatabase.SelectionAttribute __selection_variable__
TrainDatabase.SelectionValue __selection_value__
TrainDatabase.TestDatabaseSpecificationMode __test_database_mode__

// Target variable
AnalysisSpec.TargetAttributeName __target_variable__
AnalysisSpec.MainTargetModality __main_target_value__

// Predictors to train
AnalysisSpec.PredictorsSpec.SelectiveNaiveBayesPredictor __snb_predictor__
AnalysisSpec.PredictorsSpec.AdvancedSpec.UnivariatePredictorNumber __univariate_predictor_number__

// Selective Naive Bayes settings
AnalysisSpec.PredictorsSpec.AdvancedSpec.InspectSelectiveNaiveBayesParameters
TrainParameters.MaxEvaluatedAttributeNumber __max_evaluated_variables__
SelectionParameters.MaxSelectedAttributeNumber __max_selected_variables__
Exit

// Feature engineering
AnalysisSpec.PredictorsSpec.ConstructionSpec.MaxTreeNumber __max_trees__
AnalysisSpec.PredictorsSpec.ConstructionSpec.MaxAttributePairNumber __max_pairs__
AnalysisSpec.PredictorsSpec.AdvancedSpec.InspectAttributePairsParameters
AllAttributePairs __all_possible_pairs__
__LOOP__ __specific_pairs__
SpecificAttributePairs.InsertItemAfter
SpecificAttributePairs.FirstName __first_name__
SpecificAttributePairs.SecondName __second_name__
__END_LOOP__
Exit
AnalysisSpec.PredictorsSpec.ConstructionSpec.MaxConstructedAttributeNumber __max_constructed_variables__
AnalysisSpec.PredictorsSpec.AdvancedSpec.InspectConstructionDomain
__LOOP__ __construction_rules__
UnselectAll
ConstructionRules.List.Key __rule_name__
ConstructionRules.Used __rule_used__
__END_LOOP__
Exit

// Data preparation (discretization & grouping) settings
AnalysisSpec.PreprocessingSpec.TargetGrouped __group_target_value__
AnalysisSpec.PreprocessingSpec.DiscretizerSpec.SupervisedMethodName __discretization_method__
AnalysisSpec.PreprocessingSpec.DiscretizerSpec.UnsupervisedMethodName __discretization_method__
AnalysisSpec.PreprocessingSpec.DiscretizerSpec.MinIntervalFrequency __min_interval_frequency__
AnalysisSpec.PreprocessingSpec.DiscretizerSpec.MaxIntervalNumber __max_intervals__
AnalysisSpec.PreprocessingSpec.GrouperSpec.SupervisedMethodName __grouping_method__
AnalysisSpec.PreprocessingSpec.GrouperSpec.UnsupervisedMethodName __grouping_method__
AnalysisSpec.PreprocessingSpec.GrouperSpec.MinGroupFrequency __min_group_frequency__
AnalysisSpec.PreprocessingSpec.GrouperSpec.MaxGroupNumber __max_groups__

// Output settings
AnalysisResults.ResultFilesDirectory __results_dir__
AnalysisResults.ResultFilesPrefix __results_prefix__

// Build model
ComputeStats

@marcboulle
Copy link
Collaborator Author

marcboulle commented Apr 18, 2024

Extension du pilotage de Khiops via les scénarios

Résumé

On propose dans ce document une extension du pilotage de Khiops via des scénarios.

Khiops peut-être piloté via la ligne de commande via des scénarios

  • option -i: pour passer un fichier scenario en paramètre
  • option -r: pour faire des search/replace, permettant une variabilité via des scenarios rendus génériques

Ce mode de contrôle est intéressant pour intégrer rapidement des traitements Khiops et les lancer depuis n'importe quel
langage de programmation.
Par contre, cela est limité dans le cas de paramétrage plus complexe, comme par exemple l'ensemble
des tables d'un schéma en flocon. Dans ce cas, on doit passer un un algorithme de création de scénario comportant
potentiellement des boucles de search/replace.

On propose d'étendre d'étendre le pilotage de khiops via les scénarios:

  • extension du formalisme des scénarios pour avoir quelques structures de contrôle
  • extension du search/replace (-r) pour avoir une structure de donnée en entrée plutôt que des paires (key/value)

L'intérêt de cette extension fonctionnelle est multiple:

  • étend la facilité de pilotage de Khiops pour tous les utilisateurs/intégrateurs
  • facilite l'interfaçage avec tout langage de programmation
  • facilite la mise au point d'une API "officielle"
  • simplifie les évolutions d'AutoML

Spécification fonctionnelle

Structure de contrôle dans les scénarios

On ajoute quelques structures de contrôle dans les scénario pour permettre
un pilotage complet des opérations de search/replace.

Les structures de contrôle sont matérialisées par des instructions en UPPER CASE sur des lignes dédiées.

Boucle

Une structure de boucle permet d'entourer un bloc de lignes de scenario entre deux instructions

  • LOOP <loop key>
  • END LOOP

Toutes les lignes d'un bloc de boucle sont répétées autant de fois que nécessaire.

Test

Une structure de test permet d'entourer un bloc de lignes de scenario entre deux instructions

  • IF <if key>
  • END IF

Toutes les lignes d'un bloc de test sont prise en compte conditionnellement au test.

Paramétrage par une structure de données

Ajout d'un option sur la ligne de commande des outils Khiops:
-j \<file\> json file used to set replay parameters

Le fichier json contient une série de paires clé/valeur:

  • valeur de type string ou number
    • clé dans le scénario a remplacer par la valeur
  • valeur de type array
    • la clé du tableau permet d'identifier (loop key) un bloc de lignes dans le scenario, pour une structure de boucle (LOOP)
    • la valeur est associée dans le json à un array contenant des object json, tous de la même structure,
      avec la même liste de paires clé/valeur de type string ou number
    • on duplique les lignes de la boucle autant de fois qu'il y d'objets dans le tableau, en effectuant les search/replace
      selon les clés/valeur de l'objet courant
  • valeur de type boolean
    • la clé du boolean permet d'identifier (if key) un bloc de lignes dans le scenario, pour une structure de test (IF)
    • on prend en compte les lignes du test selon la valeur true ou false associée à la clé

Format json: https://www.json.org/json-en.html

Contraintes sur les options de la ligne de commande

Pour faciliter la mise au point du pilotage par scenario, on rajoute l'option suivante:
-O \<file\> same as -o option, but without replay

Contraintes:

  • les options -r (search/replace basique) et -j (search/replace piloté par un fichier json) sont exclusives.
  • les options -o et -O sont exclusives.

Contraintes sur la structure du json

Seule une petite partie de l'expressivité du format json est gérée

  • pas de valeur nul
  • pas de récursion dans la structure: la seul usage autorisé et celui d'un array contenant des object

Contraintes sur les clés

  • les clés utilisées dans le json doivent être distinctes
    • pour l'object à la racine d'objet json principal
    • pour chaque tableau, localement au tableau, et entre les clé du tableau et celle de l'objet englobant
  • les clés ont une syntaxe de variables de langage: uniquement des caractères alpha-numériques
  • aucune clé ne doit être une sous-partie d'une autre clé
    • évite les ambiguités selon l'ordre de remplacement dans les search/replace

Liens entre clés dans le json et dans le scénario

  • chaque clé dans le scenario est utilisable dans le json si elle est entourée de '__' (double tiret du 8)
    • exemple, une clé name dans le json est utilisable avec la valeur à remplacer name dans le scenario
  • chaque clé dans le json doit être utilisée dans le scénario, et réciproquement
    • exception: si une clé de tableau peut être absent du json, cela equivaut à un tableau vide
  • chaque clé dans un array du json ne peut être utilisée que dans la boucle correspondante du scénario
  • dans le cas d'une clé dont la valeur est une string, la ligne du scenario utilisant cette clé devra être terminée par " // commentaire" afin d'autoriser les valeurs contenant la sous-chaine '//'

Remarque:

  • l'option -j avec un json sans valeur de type array (LOOP) ou boolean (IF) est
    équivalente à l'option -r utilisée autant de fois qu'il y a de paires clé/valeur dans le json
    • cela permet de passer très simplement du paramétrage basique par -r au paramétrage avancé par -j

Exemple d'utilisation

Scénario en entrée:

ClassManagement.OpenFile // Open...
ClassFileName __dictionaryFile__ // Dictionary file
OK // Open
ClassManagement.ClassName __dictionaryName__

LOOP __dataTables__
TrainDatabase.DatabaseFiles.List.Key __dataPath__
TrainDatabase.DatabaseFiles.DataTableName __dataFile__
END LOOP

TrainDatabase.SampleNumberPercentage __trainPercentage__  // Sample percentage

IF __detectFormat__
TrainDatabase.DatabaseFormatDetector.DetectFileFormat
END IF

AnalysisSpec.TargetAttributeName __targetName__
ComputeStats // Analyse database

Exit // Close
OK // Close

Fichier json en entrée:

{
  "dictionaryFile": "./SpliceJunction/SpliceJunction.kdic",
  "dictionaryName": "SpliceJunction",
  "dataTables": [
    {
      "dataPath": "SpliceJunction",
      "dataFile": "./SpliceJunction/SpliceJunction.txt"
    },
    {
      "dataPath": "SpliceJunction`DNA",
      "dataFile": "./SpliceJunction/SpliceJunctionDNA.txt"
    }
  ],
  "detectFormat": true,
  "trainPercentage": 10,
  "targetName": "Class"
}

Scénario en sortie:

ClassManagement.OpenFile // Open...
ClassFileName ./SpliceJunction/SpliceJunction.kdic // Dictionary file
OK // Open
ClassManagement.ClassName SpliceJunction

TrainDatabase.DatabaseFiles.List.Key SpliceJunction
TrainDatabase.DatabaseFiles.DataTableName ./SpliceJunction/SpliceJunction.txt
TrainDatabase.DatabaseFiles.List.Key SpliceJunction`DNA
TrainDatabase.DatabaseFiles.DataTableName ./SpliceJunction/SpliceJunctionDNA.txt

TrainDatabase.SampleNumberPercentage 10  // Sample percentage

TrainDatabase.DatabaseFormatDetector.DetectFileFormat

AnalysisSpec.TargetAttributeName Class
ComputeStats // Analyse database

Exit // Close
OK // Close

Encodage des valeurs dans le json

Analyse des besoins et contraintes

Khiops accepte tout types de valeurs en entrée, ce qui permet d'être applicable à toutes sources de données.
Cela impose des scénario qui sont sont encodés sous formes de bytes (et non UTF-8 par exemple), ce qui permet par exemple:

  • de gérer des noms de fichiers quelconques (par exemple, sous linux, un nom de fichier est une séquence de bytes)
  • de gérer des noms de variables de base de données ou de valeurs encodées en Ansi étendu, et non en UTF-8

Comme la structure json comporte une liste de clés/valeurs, les valeurs doivent donc pouvoir comporter n'importe quelle séquence de bytes.

Khiops doit décoder les valeurs des clés du json en paramètre pour les transformer en chaines de caractères C++, qui sont des tableau de bytes.
Il est donc nécessaire de spécifier comment les valeurs sont encodées, au dela du format UTF-8.

Selon la spécification de json https://datatracker.ietf.org/doc/html/rfc8259#section-8.1,
on peut éventuellement utiliser le format json sans respecter l'encodage UTF-8, puisque l'on se trouve dans l'éco-système fermé Khiops.

8.1. Character Encoding

JSON text exchanged between systems that are not part of a closed
ecosystem MUST be encoded using UTF-8 [RFC3629].

Previous specifications of JSON have not required the use of UTF-8
when transmitting JSON text. However, the vast majority of JSON-
based software implementations have chosen to use the UTF-8 encoding,
to the extent that it is the only encoding that achieves
interoperability.

Choix d'encodage

On choisit un encodage UTF-8 systématique pour le json en paramètre de Khiops, selon la norme Json.
Dans le cas de paramètres dont les valeurs peuvent être soit des strings UTF-8, soit des chaines de bytes, on étend le format json de la façon suivantes.
Pour un paramètre concerné (ex: dataPath):

  • le fichier scénario reste inchangé, avec utilisation de __dataPath__
  • le fichier json en paramètre peut comporter les deux variantes de la valeurs
    • chaine de caractères UTF-8: nom de la variable et valeur sans encodage
      • exemple: "dataPath" = "UTF-8 string value"
    • chaine de bytes: nom de la variable préfixé par byte, la première lettre du nom de la variable en majuscule, et valeur avec encodage Base64

Au moment de l'écriture du scénario en sortie, on recherche la clé correspondante dans le json ou sa variante avec préfixe byte pour décoder ou non la valeur dans le search/replace.

Contraintes spécifique sur la structure du json:

  • chaque clé associé à une valeur chaine de caractères, et présente dans le scénario, doit exister sous une seule des deux variantes, avec ou sans préfixe byte.

Remarques

Le format Quoted-Printable pourrait être une alternative à l'encodage Byte64

Liens avec protobuf

  • cf. https://protobuf.dev/
  • les choix effectués pour le pilotage de Khiops via des scénarios et json ont été évalués avec l'utilisation de protobuf
  • une sous-utilisation de protobuf compatible avec la spécification ci-dessous parait pertinente
    • permet de produire une API de sérialisation de paramètres de méthode utilisable en pratique
    • permet de produire des json dans un format directement utilisable

Choix d'implémentation principaux

Choix techniques avec impacts utilisateur:

  • le fichier de paramètre json est lu et traite en entier de façon préalable, avec une taille limitée
  • le fichier de commande est traite en flux, ce qui permet de n'avoir aucune limite de taille
  • toute ligne de commande peut être commentée, y compris les lignes du langage de pilotage de type IF ou LOOP
  • les lignes d'un fichier de commande template n'ont pas besoin de se terminer par un commentaire
  • toute key du fichier de commande doit se trouver dans le fichier json
  • toute key du fichier json doit être utilisée dans le fichier de commande
  • les key de paramétrage json ne peuvent concerner que la partie paramétrage utilisateur d'une valeur
  • toute erreur ou incohérence dans les fichiers de commande et de paramétrage json provoquent une erreur fatale

@marcboulle
Copy link
Collaborator Author

marcboulle commented Apr 19, 2024

Suite à échanges avec Felipe

Expression de besoin d'étendre les structures de contrôle pour les besoins actuels de pykhiops

  • pilotage par un dictionnaire
    • un dictionnaire python est une liste de paires clé/valeur: cas particulier ou les valeur sont des chaines de caractères
    • exemple d'utilisation dans pykhiops: le dictionnaire additional_data_tables , avec des data_path en clé et des path en valeur
    • une fois sérialisé dans un json, cela devient un objet json, avec la liste de ses clés/valeur de type object dans le json: le contenu de l'objet est naturellement un dictionnaire, avec des valeurs de type string
    • on peut alors avoir dans le scenario une structure de contrôle de type DICT et END_DICT, avec les lignes de la boucle répétée autant de fois qu'il y a de clé valeur
      • nécessité d'avoir des mots clés réservés dans le json pour désigner les valeurs à remplacer (ex: DICT_KEY et DICT_VALUE)
  • pilotage par une liste de valeurs, ou par une liste de tuples
    • besoin similaire pour une autre structure de données python
    • exemple d'utilisation dans pykhiops: la liste des paires de variables, qui est une liste de tuples de taille 2 (première et seconde variable de la paire)
  • problème d'encodage non statué dans le cas des bytes: commencer en première version par un encodage UTF-8

Analyse des besoins

  • ces besoins sont-il ad-hoc pour pykhiops, ou plus généralistes?
  • le coût de prise en compte de ces besoins est important
    • refonte nécessaire de la première proposition de spécification, pour la compléter et la rendre cohérente dans le cadre d'un langage de commande généraliste pour un moteur de serach/replace
    • au moins doublement du coût de spécification/développement/test/documentation de la spécification initiale
  • développement potentiellement inutile
    • si cela ne répond pas bien au besoins de pykhiops, et que pykhiops ne puisse être considérablement simplifié en ce qui concerne le pilotage de Khiops par des scénarios
    • peut-on envisager qu'une spécification minimaliste dans Khiops core (cf spécification initiale avec uniquement des LOOP et des IF) soit néanmoins utile de façon générale, même si pour des usages avancés (cf. pykhiops), cela ne résout pas tout?
      • cela ne ne permet pas de traiter directement le dictionnaire python des paramètres d'une méthode pour alimenter un fichier json en input de l'option -j de khiops
      • cela facilite quand même suffisamment le travail pour justifier un développement significatif dans Khiops core
    • ou est-ce plus pragmatique de laisser ces développements dans pykhiops, qui gère déjà ces problèmes de façon efficace et adapté à ses besoins
    • difficulté de proposer une fonctionnalité généraliste au niveau de Khiops core, si on a un seul usage actuellement
  • a-t-on l'ambition de développer une API "officielle"?
    • cela pourrait justifier des extensions significatives de la spécification initiale
    • quel fonctionnalité pour quel segment utilisateur?
    • quel niveau d'investissement, quelle priorité?
    • en attente des réflexions sur la stratégie produit, la stratégie de développement, le rapport coût/bénéfice et les priorisations

Bilan

Fonctionnalité en attente de maturation: attendre pour annuler ou lancer le développement

@marcboulle
Copy link
Collaborator Author

marcboulle commented May 6, 2024

Suite à discussion avec Stéphane

Extension avec expressivité faible

Si expressivité faible tel que proposé initialement (uniquement structures LOOP et IF):

  • intérêt "léger" pour augmenter l'expressivité des mode d'intégration par scénario
    • suffisamment simple pour être peu couteux à implémenter/tester/documenter dans khiops core
    • suffisamment complet pour couvrir tous les besoins existant (très peu de cas de LOOP associés à des tableaux de d'objets de paramétrage
    • actuellement, aucun besoin à venir exigeant une expressivité plus forte
  • intérêt pour les utilisateurs externes, dans le cas d'intégration "ponctuelle": extension "limitée" d'une fonctionnalité existante, besoin "faible"
    • intégration pour un projet spécifique avec une petite sous-partie des fonctionnalité Khiops
    • tests rapides, avec intégration dans R, Matlab...
  • intérêt pour simplifier l'intégration dans pykhiops (refactoring)
  • intérêt pour simplifier la mise au point d'une éventuelle future API "officielle"
    • une API pourrait se limité à cette expressivité

Extension avec expressivité forte

Si expressivité forte, tel que suggérée par Felipe pour les beson de pykhiops (structure DIC et VECTOR additionnelles)

  • trop complexe pour être implémentée dans Khiops core
    • au moins doublement du coût d'implémentation/miantenance
    • trop complexe et adhoc pour être exhibé fonctionnelement aux utilisateur
  • mais répond potentiellement mieux aux besoins de pykhiops et d'une éventuelle future API
    • dans ce cas, devra être spécifié à part en mode boite noire dans un composant technique interne

Bilan

  • Seul le cas avec expressivité faible est envisageable pour une implémentation dans Khiops
  • En attente de choix sur le refactoring ou non de pykhiops, et sur la décision d'exhiber une API "officielle"

@sgouache
Copy link
Contributor

sgouache commented Jul 1, 2024

Suite à une étude impliquant un petit code utilisateur de l'API en java (KhiopsAPI.java) un certain nombre de points ont évolué (mis à jour dans la discussion ci-dessus).

  • les classes générés par protobuf ont des accesseurs setXbytes, équivalent à setX mais permettant de passer la valeur sous forme de chaine de bytes. C'est problématique pour les variables de type string car elle seront automatiquement converties en chaines UTF8. Afin de permettre de passer des valeurs non-UTF8 il a été décidé de nommer les champs correspondant "byteX". Cela se traduit par la génération d'un accesseur setbyteX qui se comporte correctement (pas de conversion), qui est plus facilement reconnaissable du setXbytes généré par défaut.
  • le caractère "$" choisis pour identifier les paramètres des templates doivent être échappés pour être substitués à l'aide d'outils de type sed. Afin d'éviter les problèmes futurs ces "$" sont remplacés par "__"
  • lors de la conversion des paramètres du proto en JSON, les attributs membre d'un oneof étant exclusifs, la présence de l'un d'eux ne peut être garanti par le proto. Il a donc été décidé de forcer la valeur de l'attribut string à la chaine vide si ce cas devait se présenter.
  • les paramètres "string" des templates pouvant avoir des valeurs quelconques, y compris la chaine "//", par convention les lignes des templates qui admettent une valeur "string" devront se terminer par " // un commentaire"

Moyennant ces ajustements, la spécification décrite ci-dessus ne semble pas poser de problème d'implémentation et offre un confort d'utilisation satisfaisant pour le programmeur (vérifié pour java).

@sgouache
Copy link
Contributor

sgouache commented Jul 1, 2024

Pour référence, un exemple de spécification d'opération - ici TrainPredictor - décrite en langage proto v2 avec les contraintes simplificatrices permettant une conversion simplifiée vers JSON et son utilisation avec le search replace décrit plus haut.

message DatapathParam {
    oneof t1 {
        string data_path = 1;
        bytes byte_data_path = 2;
    }
    oneof t2 {
        string file_path = 3;
        bytes byte_file_path = 4;
    }
}

message PairParam {
    oneof t1 {
        string pair_string_param1 = 1;
        bytes byte_pair_string_param1 = 2;
    }
    oneof t2 {
        string pair_string_param2 = 3;
        bytes byte_pair_string_param2 = 4;
    }
}

message ConstructionRule {
    required string rule = 1;
}

message TrainPredictor {
    oneof v1 {
        string dictionary_file_path = 1; // default = ""
        bytes byte_dictionary_file_path = 2;
    };
    oneof v2 {
        string dictionary_name = 3; // default = ""
        bytes byte_dictionary_name = 4;
    };
    oneof v3 {
        string data_table_path = 5; // default = ""
        bytes byte_data_table_path = 6;
    };
    oneof v4 {
        string target_variable = 7; // default = ""
        bytes byte_target_variable = 8;
    };
    oneof v5 {
        string results_dir = 9; // default = ""
        bytes byte_results_dir = 10;
    };
    optional bool detect_format = 11 [ default = true ];
    optional bool header_line = 12 [ default = true ];
    optional string field_separator = 13 [ default = "" ];
    optional double sample_percentage = 14 [ default = 100.0 ];
    optional string sampling_mode = 15 [ default = "Include sample" ];
    optional string test_database_mode = 16 [ default = "Complementary" ];
    optional string selection_variable = 17 [ default = "" ];
    optional string selection_value = 18 [ default = "" ];
    repeated DatapathParam additional_data_table = 19;
    oneof v6 {
        string main_target_value = 20; // default = ""
        bytes byte_main_target_value = 21;
    };
    optional bool snb_predictor = 22 [ default = true ];
    optional int32 univariate_predictor_number = 23 [ default = 0 ];
    optional int32 max_evaluated_variables = 24 [ default = 0 ];
    optional int32 max_selected_variables = 25 [ default = 0 ];
    optional int32 max_constructed_variables = 26 [ default = 0 ];
    repeated ConstructionRule construction_rule = 27 ;
    optional int32 max_trees = 28 [ default = 10 ];
    optional int32 max_pairs = 29 [ default = 0 ];
    optional bool all_possible_pairs = 30 [ default = true ];
    repeated PairParam specific_pair = 31 ;
    optional bool group_target_value = 32 [ default = false ];
    optional string discretization_method = 33 [ default = "MODL" ];
    optional int32 min_interval_frequency = 34 [ default = 0 ];
    optional int32 max_intervals = 35 [ default = 0 ];
    optional string grouping_method = 36 [ default = "MODL" ];
    optional int32 min_group_frequency = 37 [ default = 0 ];
    optional int32 max_groups = 38 [ default = 0 ];
    optional string results_prefix = 39 [ default = "" ];
    optional string dummy_value = 40;
}

et un JSON conforme à cette spécification:

{
  "byteDictionaryFilePath": "V2hhdGV2ZXIgeW91IHdhbnQh",
  "dictionaryName": "xxx",
  "dataTablePath": "zzz",
  "byteTargetVariable": "S+lr6Q==",
  "byteResultsDir": "eHh4",
  "detectFormat": true,
  "headerLine": true,
  "fieldSeparator": "",
  "samplePercentage": 100.0,
  "samplingMode": "Include sample",
  "testDatabaseMode": "Complementary",
  "selectionVariable": "",
  "selectionValue": "",
  "additionalDataTable": [{
    "dataPath": "xxx",
    "filePath": "yyy"
  }, {
    "byteDataPath": "6Q==",
    "byteFilePath": "U29tZSBvdGhlciBieXRlcw=="
  }],
  "mainTargetValue": "",
  "snbPredictor": true,
  "univariatePredictorNumber": 0,
  "maxEvaluatedVariables": 0,
  "maxSelectedVariables": 0,
  "maxConstructedVariables": 0,
  "constructionRule": [],
  "maxTrees": 10,
  "maxPairs": 0,
  "allPossiblePairs": true,
  "specificPair": [],
  "groupTargetValue": false,
  "discretizationMethod": "MODL",
  "minIntervalFrequency": 0,
  "maxIntervals": 0,
  "groupingMethod": "MODL",
  "minGroupFrequency": 0,
  "maxGroups": 0,
  "resultsPrefix": ""
}

@lucaurelien lucaurelien added Priority/0 To do NOW and removed Priority/2 To do after P1 labels Sep 5, 2024
marcboulle added a commit that referenced this issue Oct 29, 2024
Reference
- issue #230  Extending Khiops entries with a lightweight json structure for scenarios #230
- #230
  - cette issue contient les specification detaillees de la fonctionnalité, donc on pourra
    extraire la documentation
  - cf. commentaire "Extension du pilotage de Khiops via les scénarios"
  - #230 (comment)

Choix d'implementation principaux
- le fichier de parametre json est lu et traite en entier de facon prealable, avec une taille limitee
- le fichier de commande est traite en flux, ce qui permet de n'avoir aucune limite de taille
- toute ligne de commande peut etre commentee, y compris les lignes du langage de pilotage de type IF ou LOOP
- les lignes d'un fichier de commande template n'ont pas besoin de se terminer par un commentaire
- toute __key__ du fichier de commande doit se trouver dans le fichier json
- toute key du fichier json doit etre utilise dans le fichier de commande
- les __key__ de parametrage json ne peuvent concerner que la partie parametrage utilisateur d'une valeur
- toute erreur ou incoherence dans les fichiers de commande et de parametrage json provoquent une erreur fatale

CommandFile
- methodes publiques
  - ReadInputCommand: refactoring et simplification
  - ReadWriteCommandFiles: pour ecrire le scenario en sortie sans rejouer les commandes
- methodes privees principales de parsing des scenario et de leur langage
  - ResetParser
  - RecodeCurrentLineUsingJsonParameters
  - ParseInputCommand: analyse syntaxique des lignes d'un fichier de commande en entree
  - TokenizeInputCommand
  - GetFirstInputToken
- variables de travail du parser
  - prefixees par parser (ex: nParserState, sParserBlockKey, nParserLineIndex...)
  - maintenues le temps d'une session d'analyse, pour gerer le parser de scenario en flux
- contraintes
  - nMaxLineLength = 500: longueur max d'une ligne de fichier de commande
  - nLoopMaxLineNumber = 1000: Taille max d'un bloc d'instruction IF ou LOOP d'un fichier de commande
- constantes: renommees et etendues pour harmonisation
  - sCommentPrefix
  - sJsonKeyDelimiter
  - sByteJsonKeyPrefix
  - ...

JsonLex.lex
- STRINGERROR: variante de STRINGVALUE dans le cas d'erreur d'encodage utf8
JsonYac.yac
- regles impliquant STRINGERROR pour avoir des erreurs interpretable en cas de STRINGERROR

UIObject: prise en compte de l'option -O, pour les scenarios en sortie sans rejouer les commandes
- ParseMainParameters
- CheckCommandLineOptions

TextService:
- parametrage avance de la conversion de lencodage Json vers un encodage C pas necessairemernet Utf8
  pour le cas des rapport Khiops
  - Set|GetForceUnicodeToAnsi
  - Set|GetForceUtf8ToAnsi
- modifie le comportement de la methode JsonToCString utilisee par le parser de Json
- utilise uniquement dans CCCoclusteringReport

LearningTestTool
- kht_test.py
  - --nop-output-scenario: "create an output scenario nop_output_test.prm in results dir, without replaying commands"
- _kht_families
  - ajout de la famille JsonParameters

Ajout de test\LearningTest\TestKhiops\Standard\JsonSpliceJunction pour la CI/CD

Batterie de tests LearningTest\TestKhiops\JsonParameters
- une petite cinquantaine de test, les trois-quart concernant la detection des erreurs
marcboulle added a commit that referenced this issue Oct 29, 2024
Reference
- issue #230  Extending Khiops entries with a lightweight json structure for scenarios #230
- #230
  - cette issue contient les specification detaillees de la fonctionnalité, donc on pourra
    extraire la documentation
  - cf. commentaire "Extension du pilotage de Khiops via les scénarios"
  - #230 (comment)

Choix d'implementation principaux
- le fichier de parametre json est lu et traite en entier de facon prealable, avec une taille limitee
- le fichier de commande est traite en flux, ce qui permet de n'avoir aucune limite de taille
- toute ligne de commande peut etre commentee, y compris les lignes du langage de pilotage de type IF ou LOOP
- les lignes d'un fichier de commande template n'ont pas besoin de se terminer par un commentaire
- toute __key__ du fichier de commande doit se trouver dans le fichier json
- toute key du fichier json doit etre utilise dans le fichier de commande
- les __key__ de parametrage json ne peuvent concerner que la partie parametrage utilisateur d'une valeur
- toute erreur ou incoherence dans les fichiers de commande et de parametrage json provoquent une erreur fatale

CommandFile
- methodes publiques
  - ReadInputCommand: refactoring et simplification
  - ReadWriteCommandFiles: pour ecrire le scenario en sortie sans rejouer les commandes
- methodes privees principales de parsing des scenario et de leur langage
  - ResetParser
  - RecodeCurrentLineUsingJsonParameters
  - ParseInputCommand: analyse syntaxique des lignes d'un fichier de commande en entree
  - TokenizeInputCommand
  - GetFirstInputToken
- variables de travail du parser
  - prefixees par parser (ex: nParserState, sParserBlockKey, nParserLineIndex...)
  - maintenues le temps d'une session d'analyse, pour gerer le parser de scenario en flux
- contraintes
  - nMaxLineLength = 500: longueur max d'une ligne de fichier de commande
  - nLoopMaxLineNumber = 1000: Taille max d'un bloc d'instruction IF ou LOOP d'un fichier de commande
- constantes: renommees et etendues pour harmonisation
  - sCommentPrefix
  - sJsonKeyDelimiter
  - sByteJsonKeyPrefix
  - ...

JsonLex.lex
- STRINGERROR: variante de STRINGVALUE dans le cas d'erreur d'encodage utf8
JsonYac.yac
- regles impliquant STRINGERROR pour avoir des erreurs interpretable en cas de STRINGERROR

UIObject: prise en compte de l'option -O, pour les scenarios en sortie sans rejouer les commandes
- ParseMainParameters
- CheckCommandLineOptions

TextService:
- parametrage avance de la conversion de lencodage Json vers un encodage C pas necessairemernet Utf8
  pour le cas des rapport Khiops
  - Set|GetForceUnicodeToAnsi
  - Set|GetForceUtf8ToAnsi
- modifie le comportement de la methode JsonToCString utilisee par le parser de Json
- utilise uniquement dans CCCoclusteringReport

LearningTestTool
- kht_test.py
  - --nop-output-scenario: "create an output scenario nop_output_test.prm in results dir, without replaying commands"
- _kht_families
  - ajout de la famille JsonParameters

Ajout de tests unitaires: test\UnitTests\Norm\results.ref\base_TextService.txt

Ajout de test CI/CD: test\LearningTest\TestKhiops\Standard\JsonSpliceJunction

Batterie de tests LearningTest\TestKhiops\JsonParameters
- une petite cinquantaine de test, les trois-quart concernant la detection des erreurs
marcboulle added a commit that referenced this issue Oct 29, 2024
Reference
- issue #230  Extending Khiops entries with a lightweight json structure for scenarios #230
- #230
  - cette issue contient les specification detaillees de la fonctionnalité, donc on pourra
    extraire la documentation
  - cf. commentaire "Extension du pilotage de Khiops via les scénarios"
  - #230 (comment)

Choix d'implementation principaux
- le fichier de parametre json est lu et traite en entier de facon prealable, avec une taille limitee
- le fichier de commande est traite en flux, ce qui permet de n'avoir aucune limite de taille
- toute ligne de commande peut etre commentee, y compris les lignes du langage de pilotage de type IF ou LOOP
- les lignes d'un fichier de commande template n'ont pas besoin de se terminer par un commentaire
- toute __key__ du fichier de commande doit se trouver dans le fichier json
- toute key du fichier json doit etre utilise dans le fichier de commande
- les __key__ de parametrage json ne peuvent concerner que la partie parametrage utilisateur d'une valeur
- toute erreur ou incoherence dans les fichiers de commande et de parametrage json provoquent une erreur fatale

CommandFile
- methodes publiques
  - ReadInputCommand: refactoring et simplification
  - ReadWriteCommandFiles: pour ecrire le scenario en sortie sans rejouer les commandes
- methodes privees principales de parsing des scenario et de leur langage
  - ResetParser
  - RecodeCurrentLineUsingJsonParameters
  - ParseInputCommand: analyse syntaxique des lignes d'un fichier de commande en entree
  - TokenizeInputCommand
  - GetFirstInputToken
- variables de travail du parser
  - prefixees par parser (ex: nParserState, sParserBlockKey, nParserLineIndex...)
  - maintenues le temps d'une session d'analyse, pour gerer le parser de scenario en flux
- contraintes
  - nMaxLineLength = 500: longueur max d'une ligne de fichier de commande
  - nLoopMaxLineNumber = 1000: Taille max d'un bloc d'instruction IF ou LOOP d'un fichier de commande
- constantes: renommees et etendues pour harmonisation
  - sCommentPrefix
  - sJsonKeyDelimiter
  - sByteJsonKeyPrefix
  - ...

JsonLex.lex
- STRINGERROR: variante de STRINGVALUE dans le cas d'erreur d'encodage utf8
JsonYac.yac
- regles impliquant STRINGERROR pour avoir des erreurs interpretable en cas de STRINGERROR

UIObject: prise en compte de l'option -O, pour les scenarios en sortie sans rejouer les commandes
- ParseMainParameters
- CheckCommandLineOptions

TextService:
- parametrage avance de la conversion de lencodage Json vers un encodage C pas necessairemernet Utf8
  pour le cas des rapport Khiops
  - Set|GetForceUnicodeToAnsi
  - Set|GetForceUtf8ToAnsi
- modifie le comportement de la methode JsonToCString utilisee par le parser de Json
- utilise uniquement dans CCCoclusteringReport

LearningTestTool
- kht_test.py
  - --nop-output-scenario: "create an output scenario nop_output_test.prm in results dir, without replaying commands"
- _kht_families
  - ajout de la famille JsonParameters

Ajout de tests unitaires: test\UnitTests\Norm\results.ref\base_TextService.txt

Ajout de test CI/CD: test\LearningTest\TestKhiops\Standard\JsonSpliceJunction

Batterie de tests LearningTest\TestKhiops\JsonParameters
- une petite cinquantaine de test, les trois-quart concernant la detection des erreurs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority/0 To do NOW Type/Enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants