Skip to content

Commit

Permalink
Finalize management of uniqueness in data table drivers and databases
Browse files Browse the repository at this point in the history
Gestion des cles uniques dans les drivers de fichier et les bases de donnes
- conditionne par la methode IsUnique de KWClass (auraravant GetRoot)
- uniformisation de la terminologie, en passant de root a main, principalement pour la gestion des cles
  - dans les noms de methodes (rappele dans les notes de commit)
  - dans les noms d'attributs, de parametres ou de variables locales
  - dans les commentaires (racine -> principal)

Impacts principaux
- KWMTDatabase
  - PhysicalSkip: conditionnements sur le IsUnique au lieu de GetRoot
- KWDatabaseTask
  - input_ChunkLastRootKey -> input_ChunkLastMainKey
- PLMTDatabaseTextFile
  - SetLastReadRootKey -> SetLastReadMainKey
- KWDataTableDriver
  - GetLastReadRootKey -> GetLastReadMainKey
- KWDataTableDriverTextFile
  - SkipRootRecord -> SkipMainRecord
  - ivRootKeyIndexes -> ivMainKeyIndexes
  - nombreux conditionnements sur le IsUnique au lieu de GetRoot des dictionnaires
- PLDataTableDriverTextFile
  - GetConstRootKeyIndexes -> GetConstMainKeyIndexes
  - GetRootKeyIndexes -> GetMainKeyIndexes

Autres impacts mineurs, uniquement dans les commentaires

Ajout du jeu de test: LearningTest\TestKhiops\MultiTables\NoRootSnowflakeDuplicates
- test avec schema en flocon, sans dictionnaire Root, et doublons dans les tables principale et secondaires
- verification que les doublons sont correctement detectees

Autres tests effectues a la main, sur des cas plus volumineux, ou avec une seule table avec cle, en mode Root ou non

Tests complets sur LearningTest

Les commits de type "Improve terminology between root and main in..." ne concernent que du renommage,
sans aucun impact sur le code:
- ils peuvent etre survoles lors du review
- ils pourraient etre fusionnes en un seul commit
  • Loading branch information
marcboulle committed Dec 17, 2024
1 parent f6dbf56 commit e06fbb2
Show file tree
Hide file tree
Showing 29 changed files with 188 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,7 @@ void KDMultiTableFeatureConstruction::ComputeAllClassesCompliantRules(

// On interdit les cles de la classe
// De facon generale, il s'agit d'un principe: la cle ne sert qu'a encoder une structure et la
// memoriser: il ne s'agit pas d'attributs porteurs d'information. Pour la classe racine, les cle
// memoriser: il ne s'agit pas d'attributs porteurs d'information. Pour la classe principale, les cle
// apparaissent une seule fois instance, et ne peuvent etre informatives. Pour les classes secondaires
// inclues, les cles sont soient unique par instance principale (la cle de l'incluant) sans interet,
// soit avec un role d'identifiant dans la table secondaire, sans interet autre que compter le nombre
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class KDMultiTableFeatureConstruction : public KDFeatureConstruction
// . templateDerivationRule: regle de derivation en cours de construction, selon les parametres de
// construction
// - controle de la profondeur d'extraction
// . sPriorTreeNodeName: identifiant du noeud de l'arbre de construction a partir de la racine
// . sPriorTreeNodeName: identifiant du noeud de l'arbre de construction a partir de la classe principale
// Utilise si non vide, pour indiquer qu'une trace de debugging est demandee
// . nDepth: profondeur dans l'arbre de construction, limite par la variable externe nMaxRuleDepth
// . dRuleCost: cout de la regle en cours de construction, limite par la variable externe dMaxRuleCost
Expand Down Expand Up @@ -390,7 +390,7 @@ class KDMultiTableFeatureConstruction : public KDFeatureConstruction
// . nSelectionSize: taille de selection
// . nMaxSelectionOperandNumber: nombre max d'operandes a constuire
// . dMaxSelectionCost: cout maximum de selection
// . sPriorTreeNodeName: identifiant du noeud de l'arbre de construction a partir de la racine
// . sPriorTreeNodeName: identifiant du noeud de l'arbre de construction a partir de la classe principale
// Utilise si non vide, pour indiquer qu'une trace de debugging est demandee
// . oaSelectionOperands: tableau des dimensions de partition (KDClassSelectionOperandStats: attribut ou regle)
// utilisables en operandes de selection . oaSelectionOperandIndexedFrequencies: tableau des effectif indexes
Expand Down
6 changes: 3 additions & 3 deletions src/Learning/KDDomainKnowledge/KDTextFeatureConstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ class KDTextFeatureConstruction : public KDFeatureConstruction
ObjectDictionary* odConstructedAttributes) const;

// Construction d'un attribut de type texte a partir d'un chemin d'attribut dans un schema multi-table
// L'attribut construit est insere en unused dans la classe et permet de ramener a la racine l'attribut
// texte correspondant au chemin d'attribut, avec le type Text ou TextList selon la nature simple ou multiple du
// chemin
// L'attribut construit est insere en unused dans la classe et permet de ramener a la classe principale
// l'attribut texte correspondant au chemin d'attribut, avec le type Text ou TextList selon la
// nature simple ou multiple du chemin
KWAttribute* ConstructPathAttribute(KDClassCompliantRules* classCompliantRules, KWClass* kwcClass,
const KDTextAttributePath* textAttributePath) const;

Expand Down
2 changes: 1 addition & 1 deletion src/Learning/KNITransfer/KNIDatabaseTransferView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ void KNIDatabaseTransferView::KNITransferDatabase()
// Recopie des caracteristiques de la table principale ou des tables secondaires
else
{
// Cas du mapping racine (premier des mapping)
// Cas du mapping principal (premier des mappings)
if (nMapping == 0)
{
strcpy(recodingOperands.InputFile.DataPath, "");
Expand Down
2 changes: 1 addition & 1 deletion src/Learning/KWData/KWAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class KWAttribute : public KWDataItem
// Ecriture si necessaire des informations prives dans les meta-data (_NotLoaded)
void WritePrivateMetaData(ostream& ost) const;

// Lecture et prise en compte des l'informations privees depuis les meta-data et nettoyage de ceux-ci
// Lecture et prise en compte des informations privees depuis les meta-data et nettoyage de ceux-ci
void ReadPrivateMetaData();

// Bloc d'attribut eventuel auquel l'attribut appartient
Expand Down
2 changes: 1 addition & 1 deletion src/Learning/KWData/KWClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ void KWClass::IndexClass()
ivUsedDenseAttributeNumbers.Initialize();
ivUsedSparseAttributeNumbers.Initialize();

// Il y a unicite dans le cas d'une classe racine, ou si l'unicite est forcee
// A priori, il y a unicite dans le cas d'une classe racine, ou si l'unicite est forcee (cf methode SetForceUnique)
bIsUnique = bRoot or bForceUnique;

// Indexage des tableaux d'attributs par parcours de la liste
Expand Down
7 changes: 5 additions & 2 deletions src/Learning/KWData/KWClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ class KWClass : public Object
// Ecriture si necessaire des informations prives dans les meta-data (_ForceUnique, plus celles des attributs)
void WritePrivateMetaData(ostream& ost) const;

// Lecture et prise en compte des l'informations privees depuis les meta-data et nettoyage de ceux-ci
// Lecture et prise en compte des informations privees depuis les meta-data et nettoyage de ceux-ci
void ReadPrivateMetaData();

// Nom de la classe
Expand All @@ -598,7 +598,10 @@ class KWClass : public Object
// Statut unique force
boolean bForceUnique;

// Statut unique: racine, ou ayant des attribut relation natifs, imposant l'unicite
// Statut unique:
// - racine: unicite necessaire pour les references aux tables externes
// - classe ayant des attribut relation natifs: unicite necessaire pour que chaque
// enregistrement secondaire soit rattache de facon unique a son enregistrement parent
boolean bIsUnique;

// Nom des attributs cles (potentiellement specifies avant la specification des attributs de la classe)
Expand Down
4 changes: 2 additions & 2 deletions src/Learning/KWData/KWClassDomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ KWClassDomain* KWClassDomain::CloneFromClass(const KWClass* mainClass) const
kwcdClone->usName = usName;
kwcdClone->usLabel = usLabel;

// Duplication de la classe racine
// Duplication de la classe principale
kwcCloneElement = mainClass->Clone();
kwcdClone->InsertClass(kwcCloneElement);
oaImpactedClasses.Add(kwcCloneElement);
Expand Down Expand Up @@ -892,7 +892,7 @@ void KWClassDomain::ComputeClassDependence(const KWClass* mainClass, ObjectDicti
require(mainClass->GetDomain() == this);
require(odDependentClasses != NULL);

// Enregistrement de la classe racine
// Enregistrement de la classe principale
// (en la castant, pour contourner le const du parametre)
odDependentClasses->RemoveAll();
odDependentClasses->SetAt(mainClass->GetName(), cast(KWClass*, mainClass));
Expand Down
2 changes: 1 addition & 1 deletion src/Learning/KWData/KWClassDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class KWClassDomain : public Object
// Le domaine source est vide a l'issue de l'import
void ImportDomain(KWClassDomain* kwcdInputDomain, const ALString& sClassPrefix, const ALString& sClassSuffix);

// Calcul de l'ensemble des classes (y compris la racine) dependante d'une classe
// Calcul de l'ensemble des classes (y compris la classe principale) dependante d'une classe
// Le resultat est un dictionnaire referencant les classes resultats par leur nom
void ComputeClassDependence(const KWClass* mainClass, ObjectDictionary* odDependentClasses) const;

Expand Down
4 changes: 2 additions & 2 deletions src/Learning/KWData/KWDataTableDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ KWObject* KWDataTableDriver::Read()

void KWDataTableDriver::Skip() {}

const KWObjectKey* KWDataTableDriver::GetLastReadRootKey() const
const KWObjectKey* KWDataTableDriver::GetLastReadMainKey() const
{
return &lastReadRootKey;
return &lastReadMainKey;
}

void KWDataTableDriver::Write(const KWObject* kwoObject)
Expand Down
8 changes: 4 additions & 4 deletions src/Learning/KWData/KWDataTableDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ class KWDataTableDriver : public Object
// Lecture sans production d'un objet physique, pour sauter un enregistrement
virtual void Skip();

// Cle du dernier objet lu physiquement, uniquement dans le cas d'une classe racine
// Cle du dernier objet lu physiquement, uniquement dans le cas d'une classe principale d'un schema multi-table
// Permet de verifier l'ordre et la duplication des instances dans le fichier
// Mise a jour apres toute analyse d'une ligne, soit par Skip ou par Read (meme si la lecture echoue)
virtual const KWObjectKey* GetLastReadRootKey() const;
virtual const KWObjectKey* GetLastReadMainKey() const;

// Ecriture d'une instance (de la classe initiale)
virtual void Write(const KWObject* kwoObject);
Expand Down Expand Up @@ -227,8 +227,8 @@ class KWDataTableDriver : public Object
ALString sDataTableName;
const KWClass* kwcClass;

// Cle correspondant a la derniere ligne lue, dans le cas d'une classe racine
KWObjectKey lastReadRootKey;
// Cle correspondant a la derniere ligne lue, dans le cas d'une classe principale d'un schema multi-table
KWObjectKey lastReadMainKey;

// Des entiers long sont utilises, pour la gestion de fichiers ayant
// potentiellement plus de deux milliards d'enregistrements (limite des int)
Expand Down
88 changes: 44 additions & 44 deletions src/Learning/KWData/KWDataTableDriverTextFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,11 @@ KWObject* KWDataTableDriverTextFile::Read()
}

// Reinitialisation des champ de la derniere cle lue si necessaire
assert(kwcClass->GetRoot() == (ivRootKeyIndexes.GetSize() > 0));
if (lastReadRootKey.GetSize() > 0)
assert(kwcClass->IsUnique() == (ivMainKeyIndexes.GetSize() > 0));
if (lastReadMainKey.GetSize() > 0)
{
assert(livDataItemLoadIndexes.GetSize() == ivRootKeyIndexes.GetSize());
lastReadRootKey.Initialize();
assert(livDataItemLoadIndexes.GetSize() == ivMainKeyIndexes.GetSize());
lastReadMainKey.Initialize();
}

// Lecture des champs de la ligne
Expand Down Expand Up @@ -400,13 +400,13 @@ KWObject* KWDataTableDriverTextFile::Read()
// Alimentation des champs de la derniere cle lue si necessaire
// On le fait avant l'analyse des champs, car on doit collecter les champs de la cle
// independament des erreurs
if (lastReadRootKey.GetSize() > 0)
if (lastReadMainKey.GetSize() > 0)
{
if (nField < livDataItemLoadIndexes.GetSize() and ivRootKeyIndexes.GetAt(nField) >= 0)
if (nField < livDataItemLoadIndexes.GetSize() and ivMainKeyIndexes.GetAt(nField) >= 0)
{
// Les champs cles sont necessairement lu dans le cas d'un driver physique de classe
assert(liLoadIndex.IsValid());
lastReadRootKey.SetAt(ivRootKeyIndexes.GetAt(nField), Symbol(sField, nFieldLength));
lastReadMainKey.SetAt(ivMainKeyIndexes.GetAt(nField), Symbol(sField, nFieldLength));
}
}

Expand Down Expand Up @@ -597,10 +597,10 @@ void KWDataTableDriverTextFile::Skip()
require(not bWriteMode);
require(inputBuffer != NULL);

// Cas d'une classe racine
assert(kwcClass->GetRoot() == (ivRootKeyIndexes.GetSize() > 0));
if (ivRootKeyIndexes.GetSize() > 0)
SkipRootRecord();
// Cas d'une classe principale
assert(kwcClass->IsUnique() == (ivMainKeyIndexes.GetSize() > 0));
if (ivMainKeyIndexes.GetSize() > 0)
SkipMainRecord();
// Cas standard
else
{
Expand Down Expand Up @@ -1452,10 +1452,10 @@ void KWDataTableDriverTextFile::SetSilentMode(boolean bValue)
outputBuffer->SetSilentMode(GetSilentMode());
}

void KWDataTableDriverTextFile::SkipRootRecord()
void KWDataTableDriverTextFile::SkipMainRecord()
{
char* sField;
int nRootKeyIndex;
int nMainKeyIndex;
int nKeyFieldNumber;
boolean bEndOfLine;
boolean bLineTooLong;
Expand All @@ -1467,11 +1467,11 @@ void KWDataTableDriverTextFile::SkipRootRecord()
require(inputBuffer != NULL);
require(not IsEnd());
require(not inputBuffer->IsBufferEnd());
assert(kwcClass->GetRoot() == (ivRootKeyIndexes.GetSize() > 0));
assert(kwcClass->IsUnique() == (ivMainKeyIndexes.GetSize() > 0));

// Reinitialisation des champ de la derniere cle lue si necessaire
assert(livDataItemLoadIndexes.GetSize() == ivRootKeyIndexes.GetSize());
lastReadRootKey.Initialize();
assert(livDataItemLoadIndexes.GetSize() == ivMainKeyIndexes.GetSize());
lastReadMainKey.Initialize();

// Saut d'une ligne
if (not IsEnd() and not IsError())
Expand All @@ -1487,13 +1487,13 @@ void KWDataTableDriverTextFile::SkipRootRecord()
while (not bEndOfLine)
{
// Analyse du champ si son index ne depasse pas le nombre de colonnes de l'entete et est utilise
nRootKeyIndex = -1;
if (nField < ivRootKeyIndexes.GetSize())
nRootKeyIndex = ivRootKeyIndexes.GetAt(nField);
nMainKeyIndex = -1;
if (nField < ivMainKeyIndexes.GetSize())
nMainKeyIndex = ivMainKeyIndexes.GetAt(nField);

// On ne retient que les attributs ou blocs reconnus et non calcules
// On lit toujours le premier champ pour detecter les lignes vides
if (nRootKeyIndex >= 0 or nField == 0)
if (nMainKeyIndex >= 0 or nField == 0)
bEndOfLine = inputBuffer->GetNextField(sField, nFieldLength, nFieldError, bLineTooLong);
else
bEndOfLine = inputBuffer->SkipField(bLineTooLong);
Expand All @@ -1503,9 +1503,9 @@ void KWDataTableDriverTextFile::SkipRootRecord()
break;

// Alimentation des champs de la derniere cle lue si necessaire
if (nRootKeyIndex >= 0)
if (nMainKeyIndex >= 0)
{
lastReadRootKey.SetAt(ivRootKeyIndexes.GetAt(nField), Symbol(sField, nFieldLength));
lastReadMainKey.SetAt(ivMainKeyIndexes.GetAt(nField), Symbol(sField, nFieldLength));
nKeyFieldNumber++;

// Arret si on a lu tous les champs de la cle
Expand All @@ -1520,7 +1520,7 @@ void KWDataTableDriverTextFile::SkipRootRecord()
// On ignore les lignes trop longues
if (bLineTooLong)
{
lastReadRootKey.Initialize();
lastReadMainKey.Initialize();
AddWarning("Ignored record, " + InputBufferedFile::GetLineTooLongErrorLabel());
}

Expand Down Expand Up @@ -1620,13 +1620,13 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
require(kwcHeaderLineClass != NULL or not GetHeaderLineUsed());
require(kwcHeaderLineClass == NULL or GetHeaderLineUsed());

// Initialisation pour le calcul des index des attributs cles que dans le cas d'une classe racine
ivRootKeyIndexes.SetSize(0);
lastReadRootKey.SetSize(0);
if (kwcLogicalClass->GetRoot())
// Initialisation pour le calcul des index des attributs cles que dans le cas d'une classe principale
ivMainKeyIndexes.SetSize(0);
lastReadMainKey.SetSize(0);
if (kwcLogicalClass->IsUnique())
{
// Creation d'un objet pour accuillir les champ de la cle
lastReadRootKey.SetSize(kwcLogicalClass->GetKeyAttributeNumber());
// Creation d'un objet pour accueillir les champs de la cle
lastReadMainKey.SetSize(kwcLogicalClass->GetKeyAttributeNumber());

// Creation d'un dictionnaire qui a chaque attribut de la cle associe son index
for (i = 0; i < kwcLogicalClass->GetKeyAttributeNumber(); i++)
Expand Down Expand Up @@ -1778,10 +1778,10 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
}

// Calcul des index des attribut de la cle
if (bOk and kwcLogicalClass->GetRoot())
if (bOk and kwcLogicalClass->IsUnique())
{
// Initialisation
ivRootKeyIndexes.SetSize(kwcHeaderLineClass->GetUsedAttributeNumber());
ivMainKeyIndexes.SetSize(kwcHeaderLineClass->GetUsedAttributeNumber());

// Parcours des champs de l'entete
for (i = 0; i < kwcHeaderLineClass->GetUsedAttributeNumber(); i++)
Expand All @@ -1793,9 +1793,9 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
cast(IntObject*, odKeyFieldIndexes.Lookup(headerLineAttribute->GetName()));

// Indexation eventuelle dans le cas d'un attribut de la cle
ivRootKeyIndexes.SetAt(i, -1);
ivMainKeyIndexes.SetAt(i, -1);
if (keyFieldIndex != NULL)
ivRootKeyIndexes.SetAt(i, keyFieldIndex->GetInt());
ivMainKeyIndexes.SetAt(i, keyFieldIndex->GetInt());
}
}
}
Expand Down Expand Up @@ -1872,10 +1872,10 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
}

// Calcul des index des attribut de la cle
if (bOk and kwcLogicalClass->GetRoot())
if (bOk and kwcLogicalClass->IsUnique())
{
// Initialisation
ivRootKeyIndexes.SetSize(oaNativeLogicalDataItems.GetSize());
ivMainKeyIndexes.SetSize(oaNativeLogicalDataItems.GetSize());

// Parcours des champs logiques
livDataItemLoadIndexes.SetSize(oaNativeLogicalDataItems.GetSize());
Expand All @@ -1888,9 +1888,9 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
keyFieldIndex = cast(IntObject*, odKeyFieldIndexes.Lookup(logicalDataItem->GetName()));

// Indexation eventuelle dans le cas d'un attribut de la cle
ivRootKeyIndexes.SetAt(i, -1);
ivMainKeyIndexes.SetAt(i, -1);
if (keyFieldIndex != NULL)
ivRootKeyIndexes.SetAt(i, keyFieldIndex->GetInt());
ivMainKeyIndexes.SetAt(i, keyFieldIndex->GetInt());
}
}
}
Expand Down Expand Up @@ -1933,16 +1933,16 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
}

// Affichage des correspondances entre champs de la cle et leur index dans le fichier
if (kwcClass->GetRoot())
if (kwcClass->IsUnique())
{
cout << "Compute root key indexes of dictionary " << kwcClass->GetName() << endl;
for (i = 0; i < ivRootKeyIndexes.GetSize(); i++)
cout << "Compute main key indexes of dictionary " << kwcClass->GetName() << endl;
for (i = 0; i < ivMainKeyIndexes.GetSize(); i++)
{
if (ivRootKeyIndexes.GetAt(i) != -1)
if (ivMainKeyIndexes.GetAt(i) != -1)
{
cout << "\t"
<< "Key" << ivRootKeyIndexes.GetAt(i) + 1 << "\t"
<< kwcLogicalClass->GetKeyAttributeNameAt(ivRootKeyIndexes.GetAt(i))
<< "Key" << ivMainKeyIndexes.GetAt(i) + 1 << "\t"
<< kwcLogicalClass->GetKeyAttributeNameAt(ivMainKeyIndexes.GetAt(i))
<< "\t" << i << endl;
}
}
Expand All @@ -1953,7 +1953,7 @@ boolean KWDataTableDriverTextFile::ComputeDataItemLoadIndexes(const KWClass* kwc
if (kwcHeaderLineClass != NULL)
cout << "Header line class\n" << *kwcHeaderLineClass << endl;
}
assert(not bOk or lastReadRootKey.GetSize() > 0 or not kwcClass->GetRoot());
assert(not bOk or lastReadMainKey.GetSize() > 0 or not kwcClass->IsUnique());
return bOk;
}

Expand Down
Loading

0 comments on commit e06fbb2

Please sign in to comment.