Skip to content

4.1 Delivery file

RnoldR edited this page Sep 5, 2024 · 9 revisions

De delivery.yaml file wordt ingelezen door dido_import. De hoofdstruktuur is dezelfde als die van [config.yaml](https://github.com/MinBZK/DiDo/wiki/3.1-Config-file), namelijk leveranciers met daaronder de projekten.

Bijvoorbeeld config.yaml:

SUPPLIERS:
  leverancier1:
    project1:
       schema_file: Bronanalyse_Leverancier1_project1
    project2:
       schema_file: Bronanalyse_Leverancier1_project2
  leverancier12:
    project1:
      schema_file: Bronanalyse_Leverancier2_project1
  leverancier3:
    project1:
      schema_file: Bronanalyse_Leverancier3_project1

Ziet er voor delivery.yaml als volgt uit:

DELIVERIES:
  leverancier1:
    project1:
       delivery_2022-Q3:
    project2:
       delivery_2022-J1:
  leverancier12:
    project1:
      delivery_2018-W23
  leverancier3:
    project1:
      delivery_2021-M9

Zoals je ziet is de struktuur is overal hetzelfde. Onder het projekt komen een of meer leveringen. Een levering begint altijd met delivery_ gevolgd door jaar en door een levering rapportageperiode.

DELIVERIES: leverancier: delivery_2023-Q2: code_bronbestand: LEVDATA levering_leveringsdatum: 2024-02-29 data_file: s3://s3_dgdoobi_dwh_sta_prd/personeel/jopi/ftpes_productie/salaris/20240229_data.CSV # data_file: test-bestand.CSV data_check: yes origin: input:

delivery_2023-Q3:
  code_bronbestand: LEVDATA
  levering_leveringsdatum: 2024-02-29
  data_file: s3://s3_dgdoobi_dwh_sta_prd/personeel/jopi/ftpes_productie/salaris/20240229_data.CSV
  data_check: yes
  origin:
    input: <file>

delivery_2023-Q4:
  code_bronbestand: LEVDATA
  levering_leveringsdatum: 2024-02-29
  data_file: s3://s3_dgdoobi_dwh_sta_prd/personeel/jopi/ftpes_productie/salaris/20240229_data.CSV
  data_check: yes
  origin:
    input: <file>

SUPPLIERS_TO_PROCESS: ['*']

Indicate whether delivery contains header row or not

HEADERS: leverancier: no

Definieer de kolommen waarvan de de spaties links en rechts moeten worden gestript

voor iedere cel. Geef kolommen op als lijst:

- [] lege lijst: niets wordt gestript

- ['*']: alle kolommen worden gestript

- ['a', 'b', 'd']: van kolommen a, b, d worden de spaties links en rechts gestript

STRIP_SPACE: leverancier: ['*']

Rename data on column base

Conversies voor ikb_jopi: ontbrekende datums worden aangegeven door 0(0000000)

In DWH is de conventie 29991231

Niet nodig voor vertaaltabel

RENAME_DATA: leverancier: kalenderdag: {"re": True, "^00000000$":"99991231", "^0$": "99991231", "^$": "99991231"} deeltijdfactor_in: {"re": True, "(.)-": "-\1"} leeftijd_in_jaren: {"re": True, "(.)-": "-\1"} aantal: {"re": True, "(.*)-": "-\1"}

Parameters for dido-import

LIMITS faciliteert het instellen van limieten zodat getest kan worden op

een beperkte hoeveelheid data of dat afgebroken wordt als er teveel fouten zijn gedetekteerd

LIMITS: max_rows: 0 # <1 = read all rows max_errors: 1000

SNAPSHOTS: zip: yes destroy_todo: yes

Deze voorbeeldleveringsfile beschrijft drie kwartalen aan data die geleverd zijn door de leverancier `leverancier`. Indien `dido_import` en `dido_import` gedraaid worden dan zullen deze de drie leveringen ophalen uit de s3 bucket, ze prepareren en vervolgens de file `import-all-deliveries.sql` aanmaken in de map work/sql die kan ingelezen worden met `psql`.

Na `DELIVERIES` volgt er een lijst van leveranciersnamen die eerder zijn gedefinieerd in [config.yaml](<Config file>). Elke leverancier kent een of meer leveringen. Elke levering wordt gekenmerkt door `delivery_` gevolgd door een [levering rapportageperiode](<Levering rapportageperiode>) gevolgd door de parameters die die levering definieren. Bijvoorbeeld `delivery_2023-Q3:` betekent dat er een levering is voor het derde kwartaal van 2023. Daaronder worden een aantal parameters van die specifieke levering genoemd.

# Opties voor een levering
#### data_file
de naam van de datafile. Als die voorafgegaan wordt door s3:// dan wordt hij gezocht in de s3 bucket. Als het geen absolute padnaam is dan wordt hij gezocht onder root_directory/data/leverancier/data_file

#### data_check
yes = de data wordt gecontroleerd, no = dus niet. Indien `input` gelijk is aan `<table>` (zie verderop) dan is `data_check` altijd `no`

#### data_encoding
Naam van erkende ISO encoding, bijvoorbeeld `utf8` of `CP850` 

#### delimiter
Scheidingsteken van de in te lezen .csv file. Dit is standaard ';' maar hier kan de gebruiker dat veranderen als exotische scheidingstekens zoals een komma worden gebruikt.

#### delivery_type
**Mutatie heeft al gewerkt maar is op dit moment niet goed getest. Gebruik op eigen risico**

Specifeert het type van de levering met additionele parameters:
  - mode: deze is `insert` of `mutation`
  - mutation_key: een unieke sleutel voor een record; hij is uniek voor een geschiedenis van een record. Er bestaat er echter maar maximaal een die nu geldig is, als het record is verwijderd dan is er geen record met dit recordnummer dat geldig is
  - mutation_instructions: indien de `mode` `mutation` is, dan is dit een lijst met de namen van de kolommen die het type van de mutat ie aangeven. Bijvoorbeeld voor postcodes is dit een kolom `type` waarin `insert`, `delete` of `mutate` de opties van de mutatie zijn. Voor andere api's kan dit een andere betekenis hebben.

#### origin
Geeft aan waar de data vandaan komt. Kent een aantal opties:
  - input: `<file>`, `<table>` of `<api>`
  - source: de naam van de bron
  - table_name ???: naam van de table indien `input` is `<table>`
  - voor `<api>` gelden nog een aantal opties die de toeging tot de api regelen. Bij vrijwel alle API's dient er ingelogd te worden. De specifieke credentials voor die API moet worden gespecificeerd in de .env file in de config directory van het projekt.
    - url_account: een account waar de credentials te vinden zijn
    - url_delivery: het url waar de gegevens kunnen worden opgehaald
    - start_date: datum vanaf wanneer de gegevens kunnen worden opogehaald in YYYY-MM-DD formaat

Niet altijd is het gewenst de leveringen van alle leveranciers op te halen gedurende een import run. Dit kan worden aangegevens met de optie `SUPPLIERS_TO_PROCESS: [<lijst van te verwerken leveranciers>]`. Als de lijst alleen '\*' bevat is (\['\*']) dan worden alle leveranciers verwerkt.

# Extra bewerkingen tijdens inlezen Data
Hoewel DiDo het "binnensluizen" van ruwe data "as is" in de ODL laag van de database betreft, kunnen er toch een paar modificaties door de gebruiker worden gespecificeerd. Dit betreft kleine, reproduceerbare wijzigingen die de verdere verwerking van de data in Postgres sterk vereenvoudigd.

#### HEADERS

HEADERS: : yes|no

Standaard wordt een .csv file als input verwacht met kolomnamen in de eerste rij. Indien voor die leverancier geen headers worden meegeleverd dan leidt DiDo die af uit de definitie van de data zoals die is opgeslagen in postgres. Als er kolommen te weinig of teveel zijn of zijn omgewisseld dan merkt DiDo dat niet. Ergens in de verwerking door DiDo of Postgres worden in zo'n geval nogal ondoorgrondelijke foutmeldingen gegenereerd. Probeer zo'n situatie te voorkomen.

#### STRIP_SPACE

STRIP_SPACE: leverancier: ['*']

Deze optie strips spaties links en rechts van alle data weg van de aangegeven kolommen: ['*'] betekent van alle kolommen.

#### Decimale conversie
Niet iets dat de gebruiker kan specificeren, dit gebeurt automatisch als in de meta file in `schemas/leverancier` bij `Bronbestand decimaal` een komma is gespecificeerd:

Bronbestand decimaal;,

De achterliggende reden is dat Postgres op geen enkele manier een komma accepteert en ook niet wil konverteren. Daarom konverteert DiDo automatisch alle real-type velden zoals `real`, `numeric` en `double precision`. Dido doet geen konversie van duizendtal scheidingstekens. Deze leiden tot een foutmelding van `psql` als geprobeerd wordt een file met duizendtal schedingstekens in te lezen.

#### RENAME_DATA

RENAME_DATA: leverancier: kalenderdag: {"re": True, "^00000000$":"99991231", "^0$": "99991231"} leeftijd_in_jaren: {"re": True, "(.)-": "-\1"} aantal: {"re": True, "(.)-": "-\1"} : {"00000000":"29991231", "0": "29991231"}

Deze optie maakt het mogelijk om data te wijzigen die anders tot fouten zouden leiden bij het inlezen door Postgres. P-Direkt levert data aan waarin in een datum veld 8 nullen, of 1 nul betekent dat de data ver in de toekomst ligt In alle gevallen leidt dat tot het afbreken van het inleesproces door Postgres omdat er een ISO datum wordt verwacht. Om dat te voorkomen worden sommige datumkolommen `gerenamed` naar `99991231`. 

Ook worden data aangeleverd met een min(-) teken aan het eind van het getal in plaats van ervoor. Met `{"re": True, "(.*)-": "-\\1"}` wordt het min-tekent voor het getal gezet. In beide voorbeelden wordt gebruik gemaakt van [regular expressions](https://regex101.com/).

Indien een datatype tussen \<...> wordt gezet dan worden alle kolommen van dat datatype geconverteerd. In de logfile valt terug te lezen welke kolommen tot dat type behoren en worden geconverteerd.

Door 

#### Lege cellen worden NULL bij niet-tekst
Voor alle types behalve tekst wordt afgedwongen dat ze NULL worden in de postgres database. Dat gebeurt met SQL instructie FORCE NULL bij het inlezen van de .csv datafile.

Voor tekst types betekent een leeg veld een veld met een lege string.

# Volgorde van de bewerkingen

`Dido_import` verwerkt alle gegevens als tekst. Pas tijdens het inlezen door Postgres probeert Postgres de tekst als het desbetreffende datatype in te lezen: `date`, `integer`, `floating point`, etc. De volgorde waarin de controles worden uitgevoerd zijn:
1. Controle op de headers
2. Alle spaties links en rechts wegstrippen indien dat gespecificeerd is
3. Konversie van decimale komma naar decimale punt indien dat aan de orde is
4. Data renaming
5. Lege velden van niet tekst kolommen worden geconverteerd naar NULL

### LIMITS
- max_rows: n betekent dat de eerste n rijen worden ingelezen. Handig voor het testen van grote files. n = 0 betekent dat alles wordt ingelezen.
- max_errors: 1000 geeft aan dat als er meer dan 1000 fouten worden ontdekt dat de bewerking wordt afgebroken. Als er zoveel fouten optreden dan is er meestal iets misgegaan bij het datatype o.i.d. Ook worden alle fouten gelogd. Het loggen van miljoenen fouten kan uren, zo niet dagen duren. En nee, DiDo hangt dan niet.

### Bestaande leveringen negeren
Indien een levering reeds bestaat in de database dan wordt deze genegeerd. De `levering_rapportageperiode` wordt gebruikt om te kijken of er al een levering bestaat. Dat is handig want op die manier kunnen aan een bestaande `delivery.yaml` telkens nieuwe leveringen worden toegevoegd zonder dat de oude leveringen worden overschreven en zelfs zonder dat de data voor de oude leveringen hoeft te bestaan.

Wanneer de gebruiker toch leveringen wil controleren omdanks dat deze al in de database is opgeslagen dan kan dat door de `ENFORCE_`parameter te gebruiken. Indien die op `yes` staan dan wordt de controle uitgevoerd.

ENFORCE_IMPORT_IF_TABLE_EXISTS: yes

**Waarschuwing**: de gebruiker moet er zelf voor zorgen dat de oude leveringen worden verwijderd met behulp van `dido_remove.py` voor specifieke leveringen of door eerst alle data weg te halen, deze opnieuw op te bouwen met `create_tables.py` waarna de bewuste leveringen worden ingelezen met `psql`.
Clone this wiki locally