Aller au contenu

Architecture technique - PT0CE

Table des matières

  1. Structure modulaire
  2. Flux de données
  3. Gestion des tables
  4. Stratégies d'optimisation
  5. Gestion des erreurs
  6. Configuration

Structure modulaire

Organisation des modules

pt0ce_main.py
├── extract_pas_prb.py
├── extract_master_data.py
│   └── utils/data_validator.py
├── compute_price_cubes.py
│   └── utils/cube_calculator.py
├── price_sensitivity.py
├── create_corridor_history.py
├── business_rules.py
└── config/pt0ce_config.py
    └── utils/period_manager.py

Responsabilités des modules

pt0ce_main.py

  • Orchestration du workflow complet
  • Gestion des arguments ligne de commande
  • Coordination des phases d'exécution
  • Nettoyage des tables temporaires

extract_pas_prb.py

  • Extraction de l'historique PAS jour par jour
  • Extraction des PAS/PRB actifs
  • Création des tables PT0CE_PAS_PRB_*

extract_master_data.py

  • Chargement des mappings CSV
  • Enrichissement des transactions
  • Calcul de la marge nette
  • Création de PT0CE_MASTER_DATA_*

compute_price_cubes.py

  • Calcul des cubes MASTER et NATIONAL
  • Pré-calcul des statistiques par niveau
  • Délégation du calcul des corridors

utils/cube_calculator.py

  • Logique de remontée hiérarchique
  • Calcul des bornes PL1-PLX
  • Application des contraintes
  • Gestion du keep-alive Oracle

price_sensitivity.py

  • Analyse fréquence/ventes
  • Classification F1/F2 × S1/S2
  • Attribution sensibilité HIGH/MEDIUM/LOW

create_corridor_history.py

  • Fusion corridors + sensibilité
  • Création tables finales
  • Génération statistiques

business_rules.py

  • Règles de détermination des univers
  • Filtres standards
  • Matrice de sensibilité

Flux de données

Vue d'ensemble

graph TD
    A[CSV Files] -->|Validation| B[Tables de mapping]
    C[SYS Tables] -->|Extraction| D[PAS History]
    C -->|Extraction| E[Master Data]
    B -->|Enrichissement| E
    D -->|Jointure| E
    E -->|Agrégation| F[Cubes MASTER]
    E -->|Agrégation| G[Cubes NATIONAL]
    F -->|Remontée| H[Corridors]
    G -->|Direct| H
    H -->|Fusion| I[Sensitivity]
    I -->|Merge| J[CORRIDOR_HISTORY]

Phase 1 : Extraction PAS/PRB

# Historique jour par jour
WITH DATE_RANGE AS (
    SELECT start_date + LEVEL - 1 AS BUSINESS_DATE
    FROM DUAL
    CONNECT BY LEVEL <= end_date - start_date + 1
)
# Jointure avec SYS_MD_CONDITION pour chaque jour

Phase 2 : Enrichissement Master Data

# 1. Chargement mappings CSV → Oracle
PT0CE_TYPE_CLIENT_MAPPING (rechargée)
PT0CE_TYPE_RESTAURANT_MAPPING (rechargée)

# 2. Enrichissement transactions
- Jointure avec mappings
- Calcul UNIVERS selon règles
- Calcul marge nette avec PAS historique

# 3. Création DIMENSION_MAPPING
- Combinaisons uniques avec MT_CAB > 0
- Pour export SAP dans PT1CE

Phase 3 : Calcul des cubes

# Pour chaque univers :
1. Cubes MASTER
   - Group by dimensions
   - Calcul statistiques si  30 marges distinctes

2. Cubes NATIONAL  
   - Group by ID_ART uniquement
   - Statistiques toutes transactions confondues

Phase 4 : Calcul des corridors

# 1. Pré-calcul statistiques par niveau
grouped_by_level = {
    0: {'dims': ['ID_ART', 'TYPE_CLIENT', ...], 'stats': {...}},
    1: {'dims': ['ID_ART', 'TYPE_CLIENT'], 'stats': {...}},
    ...
}

# 2. Pour chaque cube
if cube_type == 'NATIONAL':
    SOURCE_LEVEL = -1
else:
    # Recherche dans la hiérarchie
    for level in range(0, max_levels):
        if stats_found and distinct_margins >= 30:
            SOURCE_LEVEL = level + 1
            break

Phase 5 : Analyse sensibilité

# Par cube MASTER uniquement
1. Calcul métriques article
   - Nombre commandes
   - CA total

2. Classification fréquence
   - Top 25%  F1

3. Classification Pareto
   - Cumul jusqu'à 70% CA → S1

4. Attribution sensibilité
   - Matrice F×S  HIGH/MEDIUM/LOW

Gestion des tables

Tables temporaires

Format : PT0CE_[TYPE]_[UNIVERS]_YYYYMMDD

-- Exemple
PT0CE_MASTER_DATA_20250115
PT0CE_CUBES_ZOOM1_20250115
PT0CE_CORRIDORS_ZOOM1_20250115

Caractéristiques :
- COMPRESS NOLOGGING pour performance
- Suppression automatique en fin de traitement
- Index sur colonnes clés

Tables permanentes de référence

-- Rechargées à chaque run depuis CSV
PT0CE_TYPE_CLIENT_MAPPING
PT0CE_TYPE_RESTAURANT_MAPPING

-- Structure exemple
CREATE TABLE PT0CE_TYPE_CLIENT_MAPPING (
    TYPE_CLIENT VARCHAR2(100),
    UNIVERS VARCHAR2(10),
    ID_TC_CG VARCHAR2(10),
    ID_TC_CIBLE VARCHAR2(10),
    FG_HM VARCHAR2(1),
    PRB NUMBER(1)
)

Table de mapping dimensions

-- Conservée pour PT1CE
PT0CE_DIMENSION_MAPPING_YYYYMMDD

-- Contient uniquement combinaisons avec CA > 0
ID_ART × UNIVERS × TYPE_CLIENT × TYPE_RESTAURANT × GEO
 ID_TC_CIBLE, ID_SFC_CIBLE, ID_RGC_GRV_SAP

Tables finales

PT0CE_CORRIDOR_HISTORY_ZOOM1
PT0CE_CORRIDOR_HISTORY_ZOOM2  
PT0CE_CORRIDOR_HISTORY_ZOOM3

-- Remplacées à chaque run
-- Contiennent corridors + sensibilité + métadonnées

Stratégies d'optimisation

Performance Oracle

Parallélisation

SELECT /*+ PARALLEL(8) */ ...
CREATE INDEX ... PARALLEL 8 COMPRESS

Insertion par batch

batch_size = 5_000_000
for i in range(0, total_rows, batch_size):
    batch_data = data_tuples[i:i+batch_size]
    q.execute(params=batch_data, batch_errors=True)
    if i % 10_000_000 == 0:
        db.commit()

Keep-alive connexion

# Pendant les longs calculs
if current_time - last_ping > timedelta(minutes=2):
    q = db.create_query("SELECT 1 FROM DUAL")
    q.read_value()
    q.close()

Optimisation mémoire

Pré-calcul et mise en cache

# Au lieu de recalculer pour chaque cube
grouped_data = precompute_statistics_by_level()

# Réutilisation pour tous les cubes
for cube in cubes:
    stats = lookup_in_grouped_data(cube, grouped_data)

Libération mémoire

# Après chaque phase
del master_data, cubes_df
gc.collect()

Traitement vectorisé

# Calcul des bornes en masse avec numpy
valid_mask = (pas_actif > 0) & (percentiles < 1)
calculated_prices = np.where(
    valid_mask,
    pas_actif / (1 - percentiles),
    np.nan
)

Réduction de volumétrie

Cubes NATIONAL vs hypothétiques

  • Avant : Produit cartésien complet (millions de cubes)
  • Maintenant : 1 cube NATIONAL par article
  • Réduction : 10-100x moins de cubes

Filtrage précoce

-- Exclusion dès l'extraction
AND NOT (TYPE_CLIENT = 'Hors référentiel' 
     OR TYPE_RESTAURANT = 'Hors référentiel')

Gestion des erreurs

Validation des inputs

class DataValidator:
    def validate_input_files(self):
        # Vérification existence CSV
        # Validation colonnes requises
        # Contrôle format PRB (1 ou 2)
        # Standardisation FG_HM

Gestion des cas limites

# Division par zéro
if percentile >= 1:
    # Borne non calculable
    return np.nan

# PAS manquant
if pas_actif is None or pas_actif <= 0:
    # Skip calcul bornes

Logging structuré

app.log.info(f"Phase 1: {description}")
app.log.debug(f"  Détail: {metrics}")
app.log.warning(f"⚠️ Attention: {issue}")
app.log.error(f"❌ Erreur: {error}")

Configuration

Fichier pt0ce_config.json

{
    "processing": {
        "min_distinct_margins": 30,
        "parallel_degree": 8,
        "batch_size": 100000
    },
    "price_sensitivity": {
        "frequency_threshold": 0.25,
        "sales_threshold": 0.70,
        "sensitivity_matrix": {
            "F1_S1": "HIGH",
            "F1_S2": "MEDIUM",
            "F2_S1": "MEDIUM",
            "F2_S2": "LOW"
        }
    },
    "universes": {
        "ZOOM1": {"has_geo": true, "levels": 3},
        "ZOOM2": {"has_geo": true, "levels": 3},
        "ZOOM3": {"has_geo": false, "levels": 2}
    }
}

Surcharge par arguments

# Ligne de commande prioritaire
if app.args.min_distinct_margins:
    config['min_distinct_margins'] = app.args.min_distinct_margins

Points de configuration

  • Seuils ajustables sans modification code
  • Matrice sensibilité paramétrable
  • Chemins fichiers CSV configurables