Skip to content

Commit

Permalink
Improve management of too many unique values in huge datasets
Browse files Browse the repository at this point in the history
Cf. issue  Fix bug for descriptive stats with huge dataset (400 Gb) #90
- corrige dans la V10.2 et reporte dans la V11
- amelioration supplementaire dans la V11 uniquement
  - amelioration du dimensionnement de la tache de preparation univariée
    - KWDataPreparationTask::ComputeNecessaryUnivariateStatsMemory
      - prise en compte si necessaire d'au moins la place de un Symbol et une valeur sparse par record
  - vérification de la protection contre plus de deux milliard d'instances
    - gere dans KWDatabaseBasicStatsTask
    - erreur diagnostiquee dans KWClassStats::ComputeStats
  - ajout d'un warning si trop d'instances
    - limite a 10000000 definie dans KWClassStats::GetLargeDatabaseSize
    - warning dans KWClassStats::ComputeStats
  - ajout d'une protection contre le depassement de deux milliards de Symbol lors de la lecture de la base
    - gerer dans KWDataTableSlice::PhysicalReadObject

Correction additionnelle
- KWDRTableSortCompareObjects: ajout de la prise en compte du type Text pour les champs triables
  • Loading branch information
marcboulle committed Nov 23, 2023
1 parent ac8e8d2 commit 8fe164e
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 59 deletions.
3 changes: 3 additions & 0 deletions src/Learning/KWDRRuleLibrary/KWDRMultiTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1853,6 +1853,9 @@ int KWDRTableSortCompareObjects(const void* elem1, const void* elem2)
nDiff = sortOperand->GetTimestampTZValue(object1).Compare(
sortOperand->GetTimestampTZValue(object2));
break;
case KWType::Text:
nDiff = sortOperand->GetTextValue(object1).CompareValue(sortOperand->GetTextValue(object2));
break;
default:
nDiff = 0;
assert(false);
Expand Down
31 changes: 16 additions & 15 deletions src/Learning/KWData/KWDataTableDriverTextFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ longint KWDataTableDriverTextFile::GetEstimatedObjectNumber()
lHeaderLigneSize = temporaryFile.GetPositionInFile();

// Calcul du nombre de lignes hors ligne d'entete
lLineNumber = temporaryFile.GetBufferLineNumber() - 1;
lLineNumber = (longint)temporaryFile.GetBufferLineNumber() - 1;

// Calcul de la taille correspondante occupee dans le fichier
lTotalLineSize = temporaryFile.GetCurrentBufferSize() - lHeaderLigneSize;
Expand Down Expand Up @@ -1026,7 +1026,7 @@ longint KWDataTableDriverTextFile::GetUsedMemory() const
return lUsedMemory;
}

longint KWDataTableDriverTextFile::GetInMemoryEstimatedObjectNumber(longint lInputFileSize)
longint KWDataTableDriverTextFile::GetInMemoryEstimatedObjectNumber(longint lInputFileSize) const
{
boolean bDisplay = false;
longint lEstimatedObjectNumber;
Expand Down Expand Up @@ -1113,14 +1113,14 @@ longint KWDataTableDriverTextFile::GetEstimatedUsedInputDiskSpacePerObject() con
// Estimation de la taille d'un objet natif
lNativeObjectSize = nMinRecordSize; // Fin de ligne plus un minimum
lNativeObjectSize +=
nDenseNativeValueNumber * nDenseValueSize; // Valeurs dense de l'objet (valeur + separateur)
(longint)nDenseNativeValueNumber * nDenseValueSize; // Valeurs dense de l'objet (valeur + separateur)
lNativeObjectSize +=
nTextNativeValueNumber *
(longint)nTextNativeValueNumber *
nTextValueSize; // Longueur moyenne d'un champ texte (entre un ancien et un nouveau tweet...)
lNativeObjectSize += nSparseNativeValueNumber *
lNativeObjectSize += (longint)nSparseNativeValueNumber *
nSparseValueSize; // Valeurs sparse de l'objet (cle + ':' + valeur + blanc + separateur)
lNativeObjectSize +=
GetClass()->GetKeyAttributeNumber() * nKeyFieldSize; // Taille des champs de la cle (heuristique)
(longint)GetClass()->GetKeyAttributeNumber() * nKeyFieldSize; // Taille des champs de la cle (heuristique)

// Affichage
if (bDisplay)
Expand Down Expand Up @@ -1197,12 +1197,13 @@ longint KWDataTableDriverTextFile::GetEstimatedUsedMemoryPerObject() const
// Estimation de la memoire necessaire pour stocker un objet
lObjectSize = sizeof(KWObject) + 2 * sizeof(void*); // KWObject a vide
lObjectSize +=
nPhysicalDenseLoadedValueNumber * (sizeof(KWValue) + nDenseValueSize); // Valeurs dense de l'objet
lObjectSize += nPhysicalTextLoadedValueNumber * nTextValueSize; // Valeurs Text de l'objet
lObjectSize += nPhysicalSparseLoadedValueNumber * (sizeof(int) + sizeof(KWValue)); // Valeurs sparse de l'objet
lObjectSize += nPhysicalSparseLoadedValueBlockNumber * sizeof(KWSymbolValueBlock);
nPhysicalDenseLoadedValueNumber * (sizeof(KWValue) + nDenseValueSize); // Valeurs dense de l'objet
lObjectSize += (longint)nPhysicalTextLoadedValueNumber * nTextValueSize; // Valeurs Text de l'objet
lObjectSize +=
GetClass()->GetKeyAttributeNumber() *
(longint)nPhysicalSparseLoadedValueNumber * (sizeof(int) + sizeof(KWValue)); // Valeurs sparse de l'objet
lObjectSize += (longint)nPhysicalSparseLoadedValueBlockNumber * sizeof(KWSymbolValueBlock);
lObjectSize +=
(longint)GetClass()->GetKeyAttributeNumber() *
(Symbol::GetUsedMemoryPerSymbol() + nKeyFieldSize); // Taille des Symbol de la cle (sans leur contenu)

// Affichage
Expand Down Expand Up @@ -1279,10 +1280,10 @@ longint KWDataTableDriverTextFile::GetEstimatedUsedOutputDiskSpacePerObject(cons
// Estimation de la memoire necessaire pour stocker un objet a ecrire
// (generalisation de l'objet natif)
lWrittenObjectSize = nMinRecordSize;
lWrittenObjectSize += nDenseLoadedValueNumber * nDenseValueSize;
lWrittenObjectSize += nTextLoadedValueNumber * nTextValueSize;
lWrittenObjectSize += nSparseLoadedValueNumber * nSparseValueSize;
lWrittenObjectSize += kwcLogicalClass->GetKeyAttributeNumber() * nKeyFieldSize;
lWrittenObjectSize += (longint)nDenseLoadedValueNumber * nDenseValueSize;
lWrittenObjectSize += (longint)nTextLoadedValueNumber * nTextValueSize;
lWrittenObjectSize += (longint)nSparseLoadedValueNumber * nSparseValueSize;
lWrittenObjectSize += (longint)kwcLogicalClass->GetKeyAttributeNumber() * nKeyFieldSize;

// Affichage
if (bDisplay)
Expand Down
2 changes: 1 addition & 1 deletion src/Learning/KWData/KWDataTableDriverTextFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class KWDataTableDriverTextFile : public KWDataTableDriver

// Variante de l'estimation du nombre d'objets dans la base, en memoire et sans acces disque,
// en analysant la structure du dictionnaire avec dimensionnement heuristique
longint GetInMemoryEstimatedObjectNumber(longint lInputFileSize);
longint GetInMemoryEstimatedObjectNumber(longint lInputFileSize) const;

// Estimation heuristique de la place disque par record d'un fichier a lire en se basant sur les variable native
// du dictionnaire
Expand Down
9 changes: 1 addition & 8 deletions src/Learning/KWData/KWSymbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ Symbol Symbol::BuildNewSymbol(const char* sBaseName)
return Symbol(sNewSymbol);
}

int Symbol::GetSymbolNumber()
{
int nSymbolNumber;
nSymbolNumber = sdSharedSymbols.GetCount();
return nSymbolNumber;
}

longint Symbol::GetAllSymbolsUsedMemory()
{
longint lUsedMemory;
Expand Down Expand Up @@ -512,7 +505,7 @@ inline KWSymbolData* KWSymbolData::NewSymbolData(const char* sValue, int nLength
pSymbolData->nLength = nLength;

// Recopie de la chaine de caracteres ('\0' en fin de chaine)
memcpy(&(pSymbolData->cFirstStringChar), sValue, nLength + 1);
memcpy(&(pSymbolData->cFirstStringChar), sValue, (longint)nLength + 1);
return pSymbolData;
}

Expand Down
11 changes: 8 additions & 3 deletions src/Learning/KWData/KWSymbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,17 +331,17 @@ class KWSymbolData : public SystemObject
//// Implementation
protected:
// Longueur de la chaine de caracteres
inline int GetLength()
inline int GetLength() const
{
return nLength;
}

// Acces a la valeur chaine de caracteres
inline char* GetString()
inline const char* GetString() const
{
return cFirstStringChar;
}
inline char GetAt(int nIndex)
inline char GetAt(int nIndex) const
{
return cFirstStringChar[nIndex];
}
Expand Down Expand Up @@ -645,6 +645,11 @@ inline void Symbol::Reset()
symbolData = NULL;
}

inline int Symbol::GetSymbolNumber()
{
return sdSharedSymbols.GetCount();
}

#ifdef __C11__
inline Symbol::Symbol(Symbol&& sSymbol) noexcept
{
Expand Down
11 changes: 11 additions & 0 deletions src/Learning/KWDataPreparation/KWClassStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ boolean KWClassStats::ComputeStats()
LongintToReadableString(lCollectedObjectNumber) + ")");
bOk = false;
}
// Warning si nombre tres important d'instances
if (bOk and lCollectedObjectNumber >= GetLargeDatabaseSize())
{
AddWarning(sTmp + "The train dataset contains many instances (" +
LongintToReadableString(lCollectedObjectNumber) + ")");
}

// Calcul des statistiques de l'attribut cible (ou du nombre d'instances a traiter en non supervise)
bOk = bOk and not TaskProgression::IsInterruptionRequested();
Expand Down Expand Up @@ -1472,6 +1478,11 @@ int KWClassStats::GetTargetValueLargeNumber(int nDatabaseSize)
return 10 + (int)sqrt(1.0 * nDatabaseSize);
}

int KWClassStats::GetLargeDatabaseSize()
{
return 10000000;
}

boolean KWClassStats::CheckConstructionAttributes(const ObjectDictionary* odConstructedAttributes) const
{
boolean bOk = true;
Expand Down
3 changes: 3 additions & 0 deletions src/Learning/KWDataPreparation/KWClassStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ class KWClassStats : public KWLearningReport
// Nombre de valeurs cibles dans le cas categoriel, considere comme important
virtual int GetTargetValueLargeNumber(int nDatabaseSize);

// Taille de base consideree comme important
int GetLargeDatabaseSize();

// Verification de la specification d'un ensmeble de variable de construction
boolean CheckConstructionAttributes(const ObjectDictionary* odConstructedAttributes) const;

Expand Down
47 changes: 28 additions & 19 deletions src/Learning/KWDataPreparation/KWDataPreparationTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ int KWDataPreparationTask::ComputeMaxLoadableAttributeNumber(const KWLearningSpe
// esclaves en les faisant travailler plusieurs fois chacun, de facon a minimer l'attente du dernier
// esclave
if (lMaxAttributeNumber * nMaxProcessBySlave * nSlaveNumber > nUsedAttributeNumber)
lMaxAttributeNumber = 1 + nUsedAttributeNumber / (nSlaveNumber * nMaxProcessBySlave);
lMaxAttributeNumber =
1 + (longint)nUsedAttributeNumber / ((longint)nSlaveNumber * nMaxProcessBySlave);

// On ajuste le nombre d'attribut pour qu'il soit si possible equilibre par process esclave
nMaxAttributeNumber = (int)lMaxAttributeNumber;
Expand Down Expand Up @@ -351,10 +352,10 @@ longint KWDataPreparationTask::ComputeNecessaryUnivariateStatsMemory(const KWLea
// L'estimation est tres approximative, et est consideree comme raisonnable que ce soit dans le cas supervise
// ou non supervise, meme avec des histogrammes
lAttributeStatSize +=
nMeanValueNumber * lSymbolSize + sizeof(KWAttributeStats) + sizeof(KWDescriptiveContinuousStats) +
(longint)nMeanValueNumber * lSymbolSize + sizeof(KWAttributeStats) + sizeof(KWDescriptiveContinuousStats) +
sizeof(KWDataGridStats) + 2 * (sizeof(KWDGSAttributeGrouping) + KWClass::GetNameMaxLength()) +
(nMeanPartNumber + nMeanValueNumber + nTargetModalityNumber) * (sizeof(KWValue) + sizeof(int)) +
nMeanPartNumber * nTargetModalityNumber * sizeof(int);
(longint)(nMeanPartNumber + nMeanValueNumber + nTargetModalityNumber) * (sizeof(KWValue) + sizeof(int)) +
(longint)nMeanPartNumber * nTargetModalityNumber * sizeof(int);
return lAttributeStatSize;
}

Expand Down Expand Up @@ -389,11 +390,11 @@ longint KWDataPreparationTask::ComputeNecessaryBivariateStatsMemory(const KWLear
nTargetModalityNumber = nMeanPartNumber;

// Taille occupee par une paire d'attribut
lAttributePairStatSize =
lAttributeBaseStatSize + nMeanValueNumber * lSymbolSize + sizeof(KWDataGridStats) +
3 * (sizeof(KWDGSAttributeGrouping) + KWClass::GetNameMaxLength()) +
(2 * nMeanPartNumber + 2 * nMeanValueNumber + nTargetModalityNumber) * (sizeof(KWValue) + sizeof(int)) +
nMeanPartNumber * nMeanPartNumber * nTargetModalityNumber * sizeof(int);
lAttributePairStatSize = lAttributeBaseStatSize + nMeanValueNumber * lSymbolSize + sizeof(KWDataGridStats) +
3 * (sizeof(KWDGSAttributeGrouping) + KWClass::GetNameMaxLength()) +
(longint)(2 * nMeanPartNumber + 2 * nMeanValueNumber + nTargetModalityNumber) *
(sizeof(KWValue) + sizeof(int)) +
(longint)nMeanPartNumber * nMeanPartNumber * nTargetModalityNumber * sizeof(int);
return lAttributePairStatSize;
}

Expand Down Expand Up @@ -487,15 +488,23 @@ longint KWDataPreparationTask::ComputeNecessaryWorkingMemory(const KWLearningSpe
kwcClass = learningSpec->GetClass();
check(kwcClass);

// Calcul de la taille a vide d'un objet (avec au minimum un champs, en prenant en compte le cas sparse)
// Calcul de la taille a vide d'un objet
// On compate au minimum un champs, en prenant en compte le cas sparse
// et un eventuel attribut Symbol ayant autant de valeurs que d'instances
lEmptyObjectSize = sizeof(KWObject) + sizeof(KWObject*) + sizeof(KWValue*) + GetNecessaryMemoryPerDenseValue();
if (kwcClass->GetLoadedAttributeBlockNumber() > 0)
lEmptyObjectSize += GetNecessaryMemoryPerEmptyValueBlock();
if (kwcClass->GetUsedDenseAttributeNumberForType(KWType::Symbol) +
kwcClass->GetUsedDenseAttributeNumberForType(KWType::Text) >
0)
lEmptyObjectSize += Symbol::GetUsedMemoryPerSymbol();

// Prise en compte d'un dictionnaire et d'une base minimale
lClassAttributeMemorySize = ComputeNecessaryClassAttributeMemory();
lWorkingMemorySize += dummyClass.GetUsedMemory();
lWorkingMemorySize += lClassAttributeMemorySize;
lWorkingMemorySize += dummyDatabase.GetUsedMemory();
lWorkingMemorySize += 2 * KWClass::GetNameMaxLength();
lWorkingMemorySize += 2 * (longint)KWClass::GetNameMaxLength();

// Taille de la base chargee en memoire avec deux champs dont un categoriel
// On a ainsi une petite marge pour un dimensionnement minimal
Expand Down Expand Up @@ -570,23 +579,23 @@ longint KWDataPreparationTask::ComputeNecessaryWorkingMemory(const KWLearningSpe

// Un grille bivariee maximale complete initiale (cf. KWAttributeSubsetStats.CreateDatagrid)
lInitialDatagridSize =
nDatabaseObjectNumber * sizeof(KWDGMCell) +
(nSourceValueNumber + nTargetValueNumber) *
(longint)nDatabaseObjectNumber * sizeof(KWDGMCell) +
(longint)(nSourceValueNumber + nTargetValueNumber) *
(sizeof(KWDGMPart) + max(sizeof(KWDGInterval), sizeof(KWDGValueSet) + sizeof(KWDGValue)));
lWorkingMemorySize += lInitialDatagridSize;

// Plus une grille univariee pour la post-optimisation (cf.
// KWDataGridPostOptimizer::BuildUnivariateInitialDataGrid)
lInitialUnivariateDatagridSize = (int)ceil(sqrt(nDatabaseObjectNumber * 1.0)) *
lInitialUnivariateDatagridSize = (longint)ceil(sqrt(nDatabaseObjectNumber * 1.0)) *
(sizeof(KWDGMCell) + sizeof(KWDGMPart) +
max(sizeof(KWDGInterval), sizeof(KWDGValueSet) + sizeof(KWDGValue)));
lWorkingMemorySize += lInitialUnivariateDatagridSize;

// Plus deux grilles reduites de travail (cf. VNSOptimizer)
lWorkingDatagridSize =
nDatabaseObjectNumber * (sizeof(KWDGMCell) + 2 * sizeof(KWDGValue)) +
(int)ceil(sqrt(nDatabaseObjectNumber * 1.0) +
min(nTargetValueNumber * 1.0, sqrt(nDatabaseObjectNumber * 1.0))) *
(longint)ceil(sqrt(nDatabaseObjectNumber * 1.0) +
min(nTargetValueNumber * 1.0, sqrt(nDatabaseObjectNumber * 1.0))) *
(sizeof(KWDGMPart) + max(sizeof(KWDGInterval), sizeof(KWDGValueSet) + sizeof(KWDGValue)));
lWorkingMemorySize += 2 * lWorkingDatagridSize;

Expand Down Expand Up @@ -910,10 +919,10 @@ longint KWDataPreparationTask::ComputeDatabaseMinimumAllValuesMemory(int nDenseS
require(nObjectNumber >= 0);

// Memoire pour les valeurs des attributs dense
lDatabaseAllValuesMemory = (nDenseSymbolAttributeNumber + nDenseContinuousAttributeNumber) *
lDatabaseAllValuesMemory = (longint)(nDenseSymbolAttributeNumber + nDenseContinuousAttributeNumber) *
GetNecessaryMemoryPerDenseValue() * nObjectNumber;

// Prise uen compte d'un overhead en cas d'attributs d'ense Symbol
// Prise en compte d'un overhead en cas d'attributs d'ense Symbol
if (nDenseSymbolAttributeNumber > 0)
lDatabaseAllValuesMemory += ComputeEstimatedAttributeSymbolValuesMemory(
nObjectNumber * GetExpectedMeanSymbolValueLength(), nObjectNumber);
Expand Down Expand Up @@ -990,7 +999,7 @@ longint KWDataPreparationTask::GetNecessaryMemoryPerSparseValue() const

longint KWDataPreparationTask::GetExpectedMeanSymbolValueLength() const
{
// On se base arbitrairement su une longueur moyenne egale a celle d'un champ
// On se base arbitrairement sur une longueur moyenne egale a celle d'un champ
return sizeof(KWValue);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ boolean KWDataPreparationUnivariateTask::SlaveProcess()
// la memoire minimum demandee
lAvailableWorkingMemory =
shared_lLargestSliceUsedMemory - lSliceUsedMemory +
+(shared_nLargestSliceAttributeNumber - slice->GetClass()->GetLoadedAttributeNumber()) *
+(shared_nLargestSliceAttributeNumber - (longint)slice->GetClass()->GetLoadedAttributeNumber()) *
lNecessaryUnivariateStatsMemory +
shared_lLargestSliceMaxBlockWorkingMemory + shared_lLargestSliceDatabaseAllValuesMemory;

Expand Down Expand Up @@ -934,7 +934,7 @@ void KWDataPreparationUnivariateTask::InitializeSliceLexicographicSortCriterion(
require(masterDataTableSliceSet != NULL);

// Premier critere: nombre total de valeurs, dense plus sparse
slice->GetLexicographicSortCriterion()->Add(double(slice->GetClass()->GetLoadedDenseAttributeNumber() *
slice->GetLexicographicSortCriterion()->Add(double((longint)slice->GetClass()->GetLoadedDenseAttributeNumber() *
masterDataTableSliceSet->GetTotalInstanceNumber() +
slice->GetTotalAttributeBlockValueNumber()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class KWDataPreparationUnivariateTask : public KWDataPreparationTask
// Sortie:
// . ivUsedAttributeStepIndexes: pour chaque attribut, index de l'etape de chargement (-1 si attribut en
// Unused)
// Retourne le nombre de partie de la partition
// Retourne le nombre de parties de la partition
int ComputeSlicePartition(KWDataTableSlice* slice, int nObjectNumber, longint lAvailableWorkingMemory,
IntVector* ivUsedAttributePartIndexes);

Expand Down
23 changes: 18 additions & 5 deletions src/Learning/KWDataUtils/KWDataTableSliceSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ boolean KWDataTableSliceSet::ReadAllObjectsWithClass(const KWClass* kwcInputClas
}

KWClass* KWDataTableSliceSet::BuildClassFromAttributeNames(const ALString& sInputClassName,
const StringVector* svInputAttributeNames)
const StringVector* svInputAttributeNames) const
{
KWClass* kwcNewClass;
ObjectDictionary odSliceAttributes;
Expand Down Expand Up @@ -3179,15 +3179,15 @@ boolean KWDataTableSlice::ReadAll()
Global::DesactivateErrorFlowControl();

// Test si interruption sans qu'il y ait d'erreur
if (IsError() or TaskProgression::IsInterruptionRequested())
if (not bOk or IsError() or TaskProgression::IsInterruptionRequested())
{
bOk = false;

// Warning ou erreur selon le cas
if (IsError())
AddError("Read data table slice interrupted because of errors");
else
if (TaskProgression::IsInterruptionRequested())
AddWarning("Read data table slice interrupted by user");
else
AddError("Read data table slice interrupted because of errors");
}

// Fermeture
Expand Down Expand Up @@ -3592,6 +3592,7 @@ boolean KWDataTableSlice::PhysicalOpenForRead(KWClass* driverClass, boolean bOpe
boolean KWDataTableSlice::PhysicalReadObject(KWObject*& kwoObject, boolean bCreate)
{
boolean bOk = true;
const int nMaxSymbolNumber = 2000000000;
ALString sTmp;

require(IsOpenedForRead());
Expand Down Expand Up @@ -3635,6 +3636,18 @@ boolean KWDataTableSlice::PhysicalReadObject(KWObject*& kwoObject, boolean bCrea
LongintToString(read_SliceDataTableDriver->GetRecordIndex()) + " (slice " +
FileService::GetURIUserLabel(svDataFileNames.GetAt(read_nDataFileIndex)) + ")");
}

// Arret si trop de valeurs unique dans les Symbol avec risque de depassement de la capacite
// des dictionnaires de Symbol
if (bOk and Symbol::GetSymbolNumber() > nMaxSymbolNumber)
{
bOk = false;
AddError(sTmp + "Read slice file interrupted " +
"because of too many unique categorical values in the data (beyond " +
LongintToReadableString(nMaxSymbolNumber) + "), after line " +
LongintToString(read_SliceDataTableDriver->GetRecordIndex()) + " (slice " +
FileService::GetURIUserLabel(svDataFileNames.GetAt(read_nDataFileIndex)) + ")");
}
}

// Fermeture si necessaire du fichier courant
Expand Down
2 changes: 1 addition & 1 deletion src/Learning/KWDataUtils/KWDataTableSliceSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class KWDataTableSliceSet : public Object
// a vis des noms, types, et blocs d'attributs, et son nom sera specifie dans l'appele
// Memoire: la classe construite en retour appartient a l'appelant
KWClass* BuildClassFromAttributeNames(const ALString& sInputClassName,
const StringVector* svInputAttributeNames);
const StringVector* svInputAttributeNames) const;

// Acces au tableau des tranches
// Memoire: le tableau et son contenu appartiennent a l'appelant, mais peuvent etre modifies sous la
Expand Down
Loading

0 comments on commit 8fe164e

Please sign in to comment.