Objectif
Aujourd'hui la sous-traitance n'apparaît que via le booléen sousTraitanceDeclaree : les actesSousTraitance de la DECP ne sont pas exposés. Or une recherche sur une entreprise devrait aussi remonter les marchés où elle intervient comme sous-traitante.
Proposition : exposer les sous-traitants comme lignes du jeu de données aplati, au même titre que les co-titulaires d'un groupement, en réutilisant les colonnes titulaire_* (id, nom, commune, catégorie, NAF…).
Volume
Mesuré sur decp_prod.parquet :
- 63 757 marchés avec
sousTraitanceDeclaree = True (3,7 %) — c'est un plancher, le champ est NULL sur 1 090 817 marchés (63 %)
- vue
donneesActuelles : 2 068 353 lignes pour 1 728 412 marchés, soit un ratio de 1,20
- ajout estimé : ~+5 % de lignes, ratio 1,20 → 1,26
Moins que la multiplication déjà produite par les groupements (76 633 marchés à 2 titulaires, 33 158 à 3, longue traîne au-delà).
À trancher : titulaire_role, montantSousTraitance, ou les deux ?
Option 1 — titulaire_role seul. montant porterait le montant du marché sur les lignes titulaire et le montant de l'acte sur les lignes sous-traitant. Une colonne de moins, mais montant cesse d'être interprétable sans lire une seconde colonne, définitivement et pour tous les réutilisateurs.
Option 2 — montantSousTraitance seul. Le rôle s'infère de montantSousTraitance IS NOT NULL. Fragile : vu les taux de remplissage de la DECP, un acte sans montant renseigné deviendrait indiscernable d'un titulaire.
Option 3 (recommandée) — les deux, montant inchangé.
titulaire_role ∈ {titulaire, sousTraitant}, jamais NULL — c'est le seul discriminant fiable
montant = montant du marché sur toutes les lignes, y compris sous-traitant (exactement le comportement actuel pour les groupements)
montantSousTraitance = montant de l'acte, NULL sur les lignes titulaire
Avantage décisif : montant reste constant par uid, donc les agrégats existants qui dédoublonnent par marché (group_by("uid").agg(montant.first()) côté colibre) continuent de fonctionner sans modification. Le montant sous-traité se lit par SUM(montantSousTraitance) WHERE titulaire_role = 'sousTraitant'.
Les deux colonnes ne font pas doublon : l'une dit ce qu'est la ligne, l'autre combien vaut l'acte. Une seule des deux laisse toujours un trou.
Impacts en aval
- colibre : les agrégats qui comptent des lignes et non des marchés (répartition par catégorie ou code NAF de titulaire) doivent filtrer sur
titulaire_role, sinon les sous-traitants s'y glissent silencieusement
- ce filtre de rôle gagnerait à être appliqué par défaut au niveau des requêtes, sur le modèle de
donneesActuelles
- schéma et documentation à mettre à jour — les noms de colonnes sont un contrat public (exports, API)
À vérifier au passage
montant n'est déjà pas constant par uid sur ~16 000 marchés (0,9 %) dans donneesActuelles : 10 535 en portent 2 distincts, 2 949 en portent 3. Indépendant de ce chantier, mais fragilise les dédoublonnages par .first().
Objectif
Aujourd'hui la sous-traitance n'apparaît que via le booléen
sousTraitanceDeclaree: lesactesSousTraitancede la DECP ne sont pas exposés. Or une recherche sur une entreprise devrait aussi remonter les marchés où elle intervient comme sous-traitante.Proposition : exposer les sous-traitants comme lignes du jeu de données aplati, au même titre que les co-titulaires d'un groupement, en réutilisant les colonnes
titulaire_*(id, nom, commune, catégorie, NAF…).Volume
Mesuré sur
decp_prod.parquet:sousTraitanceDeclaree = True(3,7 %) — c'est un plancher, le champ est NULL sur 1 090 817 marchés (63 %)donneesActuelles: 2 068 353 lignes pour 1 728 412 marchés, soit un ratio de 1,20Moins que la multiplication déjà produite par les groupements (76 633 marchés à 2 titulaires, 33 158 à 3, longue traîne au-delà).
À trancher :
titulaire_role,montantSousTraitance, ou les deux ?Option 1 —
titulaire_roleseul.montantporterait le montant du marché sur les lignes titulaire et le montant de l'acte sur les lignes sous-traitant. Une colonne de moins, maismontantcesse d'être interprétable sans lire une seconde colonne, définitivement et pour tous les réutilisateurs.Option 2 —
montantSousTraitanceseul. Le rôle s'infère demontantSousTraitance IS NOT NULL. Fragile : vu les taux de remplissage de la DECP, un acte sans montant renseigné deviendrait indiscernable d'un titulaire.Option 3 (recommandée) — les deux,
montantinchangé.titulaire_role∈ {titulaire,sousTraitant}, jamais NULL — c'est le seul discriminant fiablemontant= montant du marché sur toutes les lignes, y compris sous-traitant (exactement le comportement actuel pour les groupements)montantSousTraitance= montant de l'acte, NULL sur les lignes titulaireAvantage décisif :
montantreste constant paruid, donc les agrégats existants qui dédoublonnent par marché (group_by("uid").agg(montant.first())côté colibre) continuent de fonctionner sans modification. Le montant sous-traité se lit parSUM(montantSousTraitance) WHERE titulaire_role = 'sousTraitant'.Les deux colonnes ne font pas doublon : l'une dit ce qu'est la ligne, l'autre combien vaut l'acte. Une seule des deux laisse toujours un trou.
Impacts en aval
titulaire_role, sinon les sous-traitants s'y glissent silencieusementdonneesActuellesÀ vérifier au passage
montantn'est déjà pas constant paruidsur ~16 000 marchés (0,9 %) dansdonneesActuelles: 10 535 en portent 2 distincts, 2 949 en portent 3. Indépendant de ce chantier, mais fragilise les dédoublonnages par.first().