Parquedit

Sist endret

July 1, 2026

CautionTjenesten lanseres september 2026

Parquedit lanseres september 2026 og er ikke klar for bruk.

Parquedit er en tjeneste som gir statistikere database-funksjonalitet over Parquet-filer. Formålet med tjenesten er å dekke lagringsbehovene knyttet til arbeid med manuell editering av data i SSB. Les mer om Prinsipper og retningslinjer for dataeditering i SSB.

Parquedit inkluderer IKKE et grafisk grensesnitt (GUI) for å gjøre manuelle endringer på data, kun en enkel Python-funksjon som oppdaterer informasjon i en rad i et datasett. Parquedit kan derimot benyttes som en underliggende lagringsløsning som oppdateres via GUI’er som Editeringsrammeverket eller andre løsninger.

ssb-parquedit er bygget på Ducklake og har følgende egenskaper:

Tjenesten lagrer data i statistikkteamets produktbøtte, mens metadata lagres i en sentral katalog på Dapla. Teamene kan benytte seg av Python-pakken ssb-parquedit for å jobbe med Parquedit-tabellen sine fra Dapla Lab.

  1. Installer pakken i prosjektet ditt:
Terminal
poetry add ssb-parquedit
  1. Opprett en klient og se data:
Notebook
from ssb_parquedit import ParquEdit

con = ParquEdit()
con.view(table_name="manuell_tabell", limit=5)
  1. Oppdater en rad med begrunnelse:
Notebook
row = con.view(table_name="manuell_tabell", where="enhet_id = '12345'")
rowid = row["rowid"].iloc[0]

con.edit(
    table_name="manuell_tabell",
    rowid=rowid,
    changes={"status": "GODKJENT"},
    change_event_reason="REVIEW",
    change_comment="Manuell kvalitetssikring",
)

Bruksområde

Parquedit er ment som et midlertidig lagringsformat under arbeidsprosessen for manuell editering. Tjenesten forutsetter at brukeren ønsker å oppdatere en og en rad etter manuelle vurderinger av en person, og at dette skjer etter maskinelle kontroller og rettinger er gjennomført. Tjenesten forutsetter også at oppdateringer skjer i en enkelttabell. Parquedit har ikke støtte for primary eller foreign nøkler.

Når arbeidsprosessen med manuell editering er gjennomført og data lagres i stabile datatilstander, så forutsetter systemet at teamet som eier dataene selv henter ut opplysninger fra Parquedit med logger som skal benyttes til kvalitetsrapporter og gi evnen til å gjenskape manuelle editeringer på et senere tidspunkt.

Forberedelser

For at et team skal kunne benytte seg av Parquedit må Teamansvarlig først aktivere tilgang i Dapla Ctrl. Det gjøres på følgende måte:

  1. Gå inn i Dapla Ctrl
  2. Åpne Instillinger på Teamsiden
  3. Under Parquedit velger du Aktiver tilgang

Etter dette kan teamets medlemmer opprette så mange Parquedit-tabeller de ønsker.

Et team som har aktivert tilgangen kan åpne en tjeneste i Dapla Lab og installere Python-pakken ssb-parquedit i et ssb-project på følgende måte:

Terminal
poetry add ssb-parquedit

Funksjonalitet

Under beskrives funksjonaliteten som tilbys av Parquedit. Vanlig funksjonalitet tilbys som funksjoner i Python-biblioteket ssb-parquedit.

Opprette kobling

For å jobbe med Parquedit-tabeller må man første opprette en kobling. Opprett en standardkobling på følgende måte:

Notebook
from ssb_parquedit import ParquEdit

con = ParquEdit()

Avanserte brukere kan også konfigurere sin egen kobling til Parquedit. Det beskrives nærmere senere.

Opprette ny tabell

Man kan opprette en ny Parquedit-tabell basert på følgende input:

  • Parquet-fil
  • Dataframe i minnet (Pandas, Polars, etc.)
  • json-skjema
Notebook
# Opprett fra eksisterende Parquet-fil i GCS (skjema utledes fra filen)
con.create_table(
    table_name="manuell_tabell_gcs",
    source="gs://my-bucket/path/to/file.parquet",
    product_name="eksempelprodukt",
    user_defined_id=["enhet_id", "aar"],
)
Notebook
import pandas as pd

df = pd.DataFrame(
    {
        "enhet_id": ["A1", "A2"],
        "aar": [2025, 2025],
        "status": ["NY", "NY"],
    }
)

con.create_table(
    table_name="manuell_tabell",
    source=df,
    product_name="eksempelprodukt",
    unique_key=["enhet_id", "aar"],
    fill=True,
)

Følgende argumenter må oppgis ved opprettelse av ny tabell:

table_name er det navnet på tabellen du ønsker å opprette. Siden et team kan ha flere tabeller, er det dette navnet som benyttes senere for å referere til tabellen.

source er kilden (Parquet, Dataframe eller json-skjema) som skal benyttes til å opprette tabellen.

product_name er obligatorisk og lagres som en kommentar på tabellen. Tabellnavn må være lowercase, starte med bokstav eller underscore, kun inneholde lowercase-bokstaver, tall og underscore, og være maks 20 tegn.

unique_key er en liste med kolonner som til sammen unikt identifiserer en rad, tilsvarende en primærnøkkel.

Partisjonert tabeller

Notebook
# Opprett partisjonert tabell og fyll med data
con.create_table(
    table_name="manuell_tabell_partisjonert",
    source=df,
    product_name="eksempelprodukt",
    part_columns=["aar"],
    unique_key=["enhet_id"],
    fill=True,
)

Laste data

Notebook
con.insert_data(
    table_name="manuell_tabell",
    source=df,
)

Lese data

Notebook
# Hent alle rader (pandas DataFrame)
df = con.view(table_name="manuell_tabell")

# Filter og velg kolonner
utvalg = con.view(
    table_name="manuell_tabell",
    where="aar = 2025",
    columns=["enhet_id", "status", "verdi"],
    order_by="enhet_id ASC",
)
Notebook
# Alle rader (returnerer pandas DataFrame som standard)
result = con.view("manuell_tabell")

# Filtrering med WHERE-betingelse
result = con.view("manuell_tabell", where="aar = 2025")
result = con.view("manuell_tabell", where="enhet_id = 'A1' AND aar >= 2025")

# Velg spesifikke kolonner
result = con.view("manuell_tabell", columns=["enhet_id", "aar"])

# Sorter resultater
result = con.view("manuell_tabell", order_by="aar DESC")

# Returner som polars eller pyarrow
result = con.view("manuell_tabell", output_format="polars")
result = con.view("manuell_tabell", output_format="pyarrow")

Editering

En vanlig flyt er:

  1. Finn riktig rad og les ut rowid.
  2. Kall edit() med nye verdier for raden identifisert med rowid.
  3. Oppgi årsak (change_event_reason) og kommentar (change_comment).
Notebook
# 1) Finn raden som skal endres
rad = con.view(
    table_name="manuell_tabell",
    where="enhet_id = 'A1' AND aar = 2025",
)
rowid = rad["rowid"].iloc[0]

# 2) Oppdater verdier på raden
con.edit(
    table_name="manuell_tabell",
    rowid=rowid,
    changes={"status": "KORRIGERT"},
    change_event_reason="REVIEW",
    change_comment="Endret etter intern kontroll",
)

changes er en ordbok (dict) med par på formen {kolonnenavn: ny_verdi}.

Gyldige verdier for change_event_reason er:

  • OTHER_SOURCE
  • REVIEW
  • OWNER
  • MARGINAL_UNIT
  • DUPLICATE
  • OTHER

Lese logger

Bruk get_edits() for å hente historikk over manuelle endringer.

Notebook
# Endringer for en tabell
logg = con.get_edits(table_name="manuell_tabell")

# Alternativt alle tabeller
alle_endringer = con.get_edits()

Dette gir blant annet:

  • hvem som gjorde endringen
  • tidspunkt for endringen
  • begrunnelse og kommentar
  • gamle og nye verdier

Liste tabeller

Liste ut alle tabeller som tilhører teamet:

Notebook
tabeller = con.list_tables()

Antall rader i en tabell

Notebook
con.count(table_name="manuell_tabell")

Sjekk av eksistens

Notebook
con.exists(table_name="manuell_tabell")

Slette tabell

Gjør følgende for å fjerne tabellen fra den sentrale katalogen og slette filene i teamets bøtte og all editeringshistorikk:

Notebook
con.drop_table("manuell_tabell", cleanup=True)

Hvis man ønsker å beholde selve datafilene i produktbøtta og editeringshistorikk, legger man til cleanup=False på denne måten:

Notebook
con.drop_table("manuell_tabell", cleanup=False)

Vedlikehold

Flush inlined data

Flush inlined data materialiserer inline-rader til Parquet-filer for en tabell. Dette er en vedlikeholdsoperasjon for arbeidsmengder med hyppige, små skriveoperasjoner, og bidrar til å holde lagringsstrukturen effektiv og spørreytelsen stabil. Den endrer ikke tabellverdiene, kun hvordan dataene fysisk lagres. Operasjonen er trygg å kjøre gjentatte ganger: Å kjøre den når det ikke er noe å flushe har ingen effekt.

Notebook
con.flush_inlined_table(table_name="manuell_tabell")

Merge adjacent files

Merge adjacent files komprimerer en tabells små Parquet-filer til færre, større filer. Dette er et vedlikeholdssteg for tabeller som mottar mange små skriveoperasjoner, og forbedrer skanneeffektiviteten og reduserer overhead knyttet til filhåndtering. Den bevarer tabelldata og historikksemantikk, og endrer kun den fysiske fillayouten. Operasjonen er trygg å kjøre gjentatte ganger: Å kjøre den når det ikke er noe å slå sammen har ingen effekt.

Notebook
con.merge_adjacent_files(table_name="manuell_tabell")

Avansert

Få tilgang til en rå DuckDB-tilkobling

ParquEdit pakker inn en DuckDBConnection, som eksponerer den underliggende duckdb.DuckDBPyConnection via .raw-egenskapen. Dette er nyttig når man integrerer med biblioteker som krever en native DuckDB-tilkobling, som Ibis.

Notebook
con = ParquEdit()
raw = con._get_connection().raw  # duckdb.DuckDBPyConnection

Merknader:

  • _get_connection() er en intern metode. Den rå tilkoblingen deler tilstand med ParquEdit — å lukke den ene vil påvirke begge. Ikke lukk den rå tilkoblingen manuelt mens ParquEdit fortsatt er i bruk.
  • Ved bruk av den rå tilkoblingen er brukeren selv ansvarlig for å oppgi den nødvendige informasjonen som ParquEdit-metodene ellers gir. F.eks. ved oppretting og redigering av tabeller.

Sette opp lokal tilkobling

Opprett en ParquEdit-instans støttet av en persistent lokal SQLite-katalog. Nyttig for lokal utvikling og testing uten tilgang til GCS eller PostgreSQL. Katalogen og datafilene lagres på path og består på tvers av økter. Katalogen opprettes dersom den ikke allerede finnes.

Notebook
con = ParquEdit().local(path="/home/onyxia/work/")