Formulės

Formulės rašomos prepare stulpelyje. Formulių pagalba galima atlikti įvairius duomenų transformavimo, nuasmeninimo, filtravimo ir kokybės tikrinimo veiksmus.

Kadangi yra labai didelė įvairovė duomenų formatų ir duomenų valdymo mechanizmų, siekiant suvaldyti visą šią įvairovę DSA formulės leidžia vieningai aprašyti veiksmus su duomenimis. Vėliau formulės verčiamos į vieningą AST, kurį gali interpretuoti automatizuotos priemonės, priklausomai nuo duomenų šaltinio ir konteksto ir DSA sluoksnio.

Gramatika

Formulių sintaksė atitinką šią ABNF gramatiką:

formula     = testlist
testlist    = test *("," test) *1","
test        = or
or          = and *("|" and)
and         = not *("&" not)
not         = "!" not / comp
comp        = expr *(compop expr)
expr        = term *(termop term)
term        = factor *(factorop factor)
factor      = sign factor / composition
composition = atom *trailer
atom        = "(" *1group ")"
            / "[" *1list "]"
            / func / value / name
group       = test *("," test) *1","
list        = test *("," test) *1","
trailer     = "[" *1filter "]" / method / attr
func        = name call
method      = "." name call
call        = "(" *1arglist ")"
arglist     = argument *("," argument) *1","
argument    = test / kwarg
kwarg       = name ":" test
filter      = test *("," test) *1","
attr        = "." name
value       = null / bool / integer / number / string / star
compop      = ">=" / "<=" / "!=" / "=" / "<" / ">"
termpop     = "+" / "-"
factorop    = "*" / "/" / "%"
sign        = "+" / "-"
star        = "*"
name        = ~/[a-z_][a-z0-9_]*/i
number      = ~/\d+(\.\d+)?/
integer     = ~/0|[1-9]\d*/
bool        = "false" / "true"
null        = "null"
string      = ~/(?!"").*?(?<!\\)(\\\\)*?"|'(?!'').*?
                (?<!\\)(\\\\)*?'/i

Sintaksės medis

Formulės verčiamos į vieningą abstraktų sintaksės medį. Vieningas abstraktus sintaksės medis leidžia atskirti formulės skaitymo ir interpretavimo veiklas.

Abstraktus sintaksės medis sudarytas iš vienodų elementų turinčių tokias savybes:

name

Funkcijos pavadinimas.

args

Funkcijos argumentų sąrašas, kurį gali sudaryti konkrečios reikšmės ar kiti medžio elementai, veiksmai.

Visos formulėje naudojamos išraiškos sintaksės medyje verčiamos į funkcijų ir argumentų medį. Pavyzdžiui test("a", "b") bus verčiamas į:

{
    "name": "test",
    "args": ["a", "b"],
}

Funkcijų iškvietimas

Formulės susideda iš vykdomų funkcijų sekos. Pavyzdžiui funkcijos pavadinimu test vykdymas formulėje atrodys taip:

test()

Aukščiau pavyzdyje pateikta furmulė vykdo funkciją test, be argumentų. Tačiau funkcijos gali turėti pozicinius ir vardinius argumentus.

Poziciniai argumentai

Poziciniai argumentai perduodami taip:

test(a, b, c)

Pavyzdyje, funkcijai test perduodami trys argumentai a, b ir c. Šioje dokumentacijoje, tais atvejais, kai funkcijos pozicinių argumentų skaičius nėra fiksuotas, naudojama *args išraiška, kur * nurodo, kad pozicinių argumentų gali būti 0 ar daugiau.

Vardiniai argumentai

Vardiniai argumentai funkcijai perduodami taip:

test(a: 1, b: 2, c: 3)

Pozicinius argumentus būtina perduoti tiksliai tokia tvarka, kokios tikisi funkcija. Tačiau vardinius argumentus, galima perduoti, bet kuria tvarka.

Jei vardinių argumentų sąrašas nėra fiksuotas, dokumentacijoje toks argumentų sąrašas užrašomas **kwargs forma, kur ** nurodo, kad vardinių argumentų gali būti 0 ar daugiau.

Alternatyvus funkcijos iškvietimas

Funkcijų iškvietimas gali būti užrašomas įprastiniu būdu, pavyzdžiui:

test(test(test(a), b), c)

Arba funkcijų grandinės (angl. Method chain) būdu:

a.test().test(b).test(c)

Kadangi formulės dažnai naudojamos tam tikros reikšmės transformavimui, todėl dažnai formulė yra lengviau skaitoma, naudojant funkcijų grandinę.

test(a) yra a.test() arba test(a, b) ir a.test(b) yra ekvivalentūs (UFCS).

Standartinės funkcijos

Priklausomai nuo duomenų šaltinio ar konteksto gali būti naudojami skirtingi veiksmai, tačiau žemiau yra pateikti bendrosios paskirties veiksmai:

func.bind(name)

Rodo į reikšmę pavadinimu name iš konteksto. Reikšmės ieškoma tokia tvarka:

func.prop(name)

Modelio savybė pavadinimu nameproperty stulpelio.

func.item(name)

Sąrašo elemento savybė pavadinimu name.

func.param(name)

Parametras pavadinimu name. Žiūrėti Parametrai.

func.var(name)

Kintamasis apibrėžtas set() funkcijos pagalba.

func.self()

Rodo į aktyvią reikšmę, naudojamas property.prepare formulėse.

func.or(*args)

Taip pat galima naudoti tokia išraiška:

a | b | c

Grąžiną pirmą netuščią reikšmę. Pirmoji netuščia reikšmė nutraukia sekančių args argumentų interpretavimą.

func.and(*args)

Taip pat galima naudoti tokia išraiška:

a & b & c

Grąžina pirmą tuščią reikšmę arba paskutinę reikšmę, jei prieš tai esančios reikšmės netuščios.

func.not(arg)

Taip pat galima naudoti tokia išraiška:

!arg

Jei arg tuščia grąžina true, priešingu atveju false.

func.eq(a, b)

Taip pat galima naudoti tokia išraiška:

a = b

a lygus b.

func.ne(a, b)

Taip pat galima naudoti tokia išraiška:

a != b

a nelygus b.

func.lt(a, b)

Taip pat galima naudoti tokia išraiška:

a < b

a mažiau už b.

func.le(a, b)

Taip pat galima naudoti tokia išraiška:

a <= b

a mažiau arba lygu už b.

func.gt(a, b)

Taip pat galima naudoti tokia išraiška:

a > b

a daugiau už b.

func.ge(a, b)

Taip pat galima naudoti tokia išraiška:

a >= b

a daugiau arba lygu už b.

func.add(a, b)

Taip pat galima naudoti tokia išraiška:

a + b

a ir b suma.

func.sub(a, b)

Taip pat galima naudoti tokia išraiška:

a - b

a ir b skirtumas.

func.mul(a, b)

Taip pat galima naudoti tokia išraiška:

a * b

a ir b sandauga.

func.div(a, b)

Taip pat galima naudoti tokia išraiška:

a / b

a ir b dalyba.

func.mod(a, b)

Taip pat galima naudoti tokia išraiška:

a % b

a ir b modulis.

func.positive(a)

Taip pat galima naudoti tokia išraiška:

+a

Gali būti interpretuojamas skirtingai, priklausomai nuo konteksto. Įprastiniu atveju keičia skaičiaus ženklą.

func.negative(a)

Taip pat galima naudoti tokia išraiška:

-a

Gali būti interpretuojamas skirtingai, priklausomai nuo konteksto. Įprastiniu atveju keičia skaičiaus ženklą.

func.tuple(*args)

Taip pat galima naudoti tokia išraiška:

(*args)

Grupė argumentų.

()
Tuščia grupė.
a, b
Tas pats, kas tuple(a, b).
func.list(*args)

Taip pat galima naudoti tokia išraiška:

[*args]

Sąrašas reikšmių.

func.getattr(object, attr)

Taip pat galima naudoti tokia išraiška:

object.attr

Gaunamos reikšmės pagal atributą arba raktą.

func.getitem(object, item)

Taip pat galima naudoti tokia išraiška:

a[item]

Gaunamos reikšmės pagal atributą arba raktą.

getitem() gali būti interpretuojamas kaip sąrašo reikšmių filtras:

a[b > c]
func.dict(**kwargs)

Taip pat galima naudoti tokia išraiška:

{a: b}

Sudėtinė duomenų struktūra.

func.set(**kwargs)

Taip pat galima naudoti tokia išraiška:

{a, b}

Reikšmių aibė.

func.op(operator)

Taip pat galima naudoti tokia išraiška:

a(*)

Operatoriai gali būti naudojami kaip argumentai.

func.stack(columns, values, exclude)

Visus stulpelius išskyrus exclude verčia į vieną stulpelių eilutei suteikiant columns pavadinimą, o reikšmių stulpeliui values pavadinimą. Pavyzdžiui:

vertinimas 2015P2 2016P2
Neigiamai 0 1
Teigiamai 39 28

Tokiai lentelei pritaikius stack("data", "rodiklis", ["vertinimas"]) transformaciją, gausime tokį rezultatą:

vertinimas data rodiklis
Neigiamai 2015P2 0
Neigiamai 2016P2 1
Teigiamai 2015P2 39
Teigiamai 2016P2 28
func.datetime(str, format)

Parse datetime from str, using strftime format.

func.date(str, format)

Parse date from str, using strftime format.

func.date(datetime)

Return date from datetime.

Failai

Dažnai duomenys teikiami failų pavidalu, kurie gali būti saugomi tiek lokaliai failų sistemoje, tiek nuotoliniame serveryje. Failai gali būti suspausti ir patalpinti į archyvo konteinerius. DSA leidžia aprašyti įvairius prieigos prie duomenų, saugomų failuose, atvejus.

resource.source

Nutolusiame serveryje saugomo failo URI arba kelias iki lokalaus katalogo. Lokalaus katalogo kelias gali būti pateikiamas tiek POSIX, tiek DOS formatais, priklausomai nuo to, kokioje operacinėje sistemoje failai saugomi.

resource.prepare
func.file(resource, encoding: "utf-8")
Parametrai:
  • resource -- Kelias arba URI iki failo.
  • encoding -- Failo koduotę.

Ši funkcija leidžia nurodyti failo koduotę, jei failas yra užkoduotas kita, nei UTF-8 koduote. Pilną palaikomų koduočių sąrašą galite rasti šiame sąraše.

func.extract(resource, type)
Parametrai:
  • resource -- Kelias arba URI iki archyvo failo arba failo objektas.
  • type -- Archyvo tipas.

Išpakuoja archyvą, kuriame saugomi failai. Galimos type reikšmės:

zip
tar
rar

Funkcijos rezultatas yra archyvo objektas, kuris leidžia pasiekti esančius archyvo failus getitem() funkcijos pagalba.

func.decompress(resource, type)
Parametrai:
  • resource -- Kelias arba URI iki archyvo failo arba failo objektas.
  • type -- Archyvo tipas.

Taikomas srautinis failo glaudinimo filtras. Galimos type reikšmės:

gz
bz2
xz

Stulpeliai lentelėje

CSV ar skaičiuoklių lentelėse stulpelių pavadinimai pateikiami pačioje lentelėje. Eilutė, kurioje surašyti pavadinimai nebūtinai gali būti pirma. Stulpelių pavadinimai gali būti pateikti keliose eilutėse iš kurių formuojamos kompleksinės struktūros (žiūrėti Kompleksinės struktūros). Įvairias situacijas galima aprašyti formulių pagalba.

model.prepare
func.header(*line)
null

Lentelėje eilučių pavadinimų nėra. Tokiu atveju, property.source stulpelyje reikia pateikti stulpelio numerį, pradedant skaičiuoti nuo 0.

line

Nurodomas eilutės numeris, pradedant eilutes skaičiuoti nuo 0, kur yra pateikti lentelės stulpelių pavadinimai. Pagal nutylėjimą stulpelių pavadinimų ieškoma pirmoje eilutėje.

*line

Jei lentelė turi kompleksinę stulpelių struktūrą, tada galima pateikti daugiau nei vieną eilutės numerį iš kurių bus nustatomi stulpelių pavadinimai.

func.head(n)

Praleisti n einančių po stulpelių pavadinimų eilutės.

func.tail(n)

Ignoruoti n eilučių failo pabaigoje.

property.source

Jei naudojamas header(null), tada nurodomas stulpelio numeris, pradedant nuo 0.

Jei naudojamas header(line), tada nurodomas stulpelio pavadinimas, toks koks įrašytas lentelės line eilutėje.

Jei naudojamas header(*line), tada nurodomas stulpelio pavadinimas, toks koks įrašymas lentelės pirmajame line argumente.

property.prepare

Jei naudojamas header(*line), žiūrėti Kompleksinės struktūros.

Duomenų atranka

Duomenų filtravimui naudojamas model.prepare stulpelis, kuriame galima apriboti iš šaltinio skaitomų duomenų imtį.

Tarkime, jei turime tokias dvi duomenų lenteles:

COUNTRIES
COUNTRY CODE
Lietuva lt
Latvija lv
CITIES
ID CITY COUNTRY
1 Vilnius lt
2 Kaunas lt
3 Ryga lv

Jei norėtume atveri ne visų šalių duomenis, o tik Lietuvos, tada duomenų struktūros aprašas turėtu atrodyti taip:

d r b m property type ref source prepare
datasets/example/countries        
  salys sql   sqlite://  
      Country   code COUNTRIES code = "lt"
        name string   COUNTRY  
        code string   CODE  
      City   id CITIES  
        id integer   ID  
        name string   CITY  
        country ref Country COUNTRY  

Kaip ir visur, formulės reikia naudoti pavadinimus ne iš source stulpelio, o iš property, model arba dataset.

Jei lentelės yra susijusios ryšiais tarpusavyje, užtenka filtrą nurodyti tik vienoje lentelėje, visose kitose susijusios lentelėse filtrai bus taikomi automatiškai, kad užtikrinti duomenų vientisumą.

Nurodant filtrus yra galimybė naudoti ne tik vienos lentelės laukus, bet ir susijusių lentelių laukus, pavyzdžiui yra galimybė nurodyti tokį filtrą:

d r b m property type ref source prepare
      City   id CITIES country.code = "lt"

Tačiau šiuo atveju, toks filtras būtų perteklinis, nes toks filtras generuojamas automatiškai ir susijusio Country modelio, kadangi negalime publikuoti Latvijos miestų, jei publikuojama tik Lietuvos šalis.

Pilnas galimų filtrų sąrašas:

model.prepare
a = b

a ir b reikšmės yra lygios.

a != b

a nelygu b.

a > b

a daugiau už b.

a < b

a mažiau už b.

a >= b

a daugiau arba lygu b.

a <= b

a mažiau arba lygu b.

a.in(b)

a lygi bent vienai iš b sekos reikšmių.

a.notin(b)

a nelygi nei vienai iš b sekos reikšmių.

a.contains(b)

a seka savyje turi b seką.

a.startswith(b)

a seka prasideda b seka.

a.endswith(b)

a seka baigiasi b seka.

a & b

a ir b.

a | b

a arba b.

sort(+a, -b)

Rūšiuoti didėjimo tvarka pagal a ir mažėjimo tvarka pagal b.

Periodiškumas

Periodiškumui nurodyti naudojamas model.prepare stulpelis, kuriame galima naudoti tokias formules:

model.prepare
func.cron(line)

Duomenų atnaujinimo laikas, analogiškas cron formatui.

line argumentas aprašomas taip:

nm
n-toji minutė, n ∊ 0-59.
nh
n-toji valanda, n ∊ 0-23.
nd
n-toji mėnesio diena, n ∊ 1-31.
$d
Paskutinė mėnesio diena.
nM
n-tasis mėnuo, n ∊ 1-12.
nw
n-toji savaitės diena, n ∊ 0-6 (sekmadienis-šeštadienis).
n#iw
n-toji savaitės diena, i-toji mėnesio savaitė, i ∊ 1-6.
n$iw
n-toji savaitės diena, i-toji savaitė nuo mėnesio galo, i ∊ 1-6.
,
Kableliu galim atskirt kelias laiko vertes.
-
Brūkšneliu galima atskirti laiko verčių intervalą.
/
Pasvyruoju brūkšniu galima atskirti laiko verčių kartojimo žingsnį.

Laiko vertės atskiriamos tarpo simbolių. Jei laiko vertė nenurodyta, reiškia įeina visos įmanomos laiko vertės reikšmės.

func.hourly()

cron('0m')

func.daily()

cron('0m 0d')

func.weekly()

cron('0m 0h 0w')

func.monthly()

cron('0m 0h 1d')

func.yearly()

cron('0m 0h 1d 1M')

Statinės reikšmės

Statinės reikšmės arba konstantos duomenų laukams gali būti nurodomos property.prepare stulpelyje naudojant formulės sintaksę. Plačiau apie formules žiūrėti Formulės skyrelyje.

Transformavimas

property.prepare stulpelyje gauta šaltinio reikšmė gali būti pasiekiama per self kintamąjį.

property.prepare formulėje gali būti aprašomos kelios reikšmės atskirtos kableliu, tai naudojama ryšio laukams, kai ryšiui aprašyti reikia daugiau nei vieno duomenų lauko.

Formulėje galima naudoti kitus to pačio modelio property pavadinimus, kai aprašomo property reikšmės formuojamos dinamiškai naudojant viena ar kelis jau aprašytus laukus.

property.prepare stulpelyje galima naudoti tokias formules:

property.prepare
func.null()

Grąžina null reikšmę, jei toliau einančios transformacijos grąžina null.

func.replace(old, new)

Pakeičia visus old į new simbolių eilutėje.

func.re(pattern)

Grąžina atitinkančią reguliariosios išraiškos pattern reikšmę arba pirmos grupės reikšmę jei naudojama tik viena grupė arba reikšmių grupę jei pattern yra daugiau nei viena grupė.

func.cast(type)

Konvertuoja šaltinio tipą į nurodytą type tipą. Tipų konvertavimas yra įmanomas tik tam tikrais atvejais. Jei tipų konvertuoti neįmanoma, tada metodas turėtų grąžinti klaidą.

func.split()

Dalina simbolių eilutę naudojant s+ reguliariąją išraišką. Grąžina masyvą.

func.strip()

Pašalina tarpo simbolius iš pradžios ir pabaigos.

func.lower()

Verčia visas raides mažosiomis.

func.upper()

Verčia visas raides didžiosiomis.

func.len()

Grąžina elementų skaičių sekoje.

func.choose(default)

Jei šaltinio reikšmė nėra viena iš Klasifikatoriai, tada grąžinama default reikšmė.

Jei default nepateiktas, grąžina vieną iš property.enum reikšmių, jei duomenų šaltinio reikšmė nėra viena iš property.enum, tada grąžinama klaida.

func.switch(*cases)
func.case(cond, value)
func.case(default)

Grąžina value, jei tenkina cond arba default. Jei case(default) nepateiktas, tada grąžina pradinę reikšmę.

Jei, cases nepateikti, grąžina vieną iš switch.source reikšmių, tenkinančių switch prepare sąlygą.

func.swap(old, new)

Swaps an old value with new, if self is equal to old.

func.return()

Nutraukia transformacijų grandinę ir grąžina reikšmę.

func.set(name)

Išsaugo reikšmę į kintamąjį name.

func.url()

Skaido URI į objektas turintį tokias savybes:

scheme
URI schema.
netloc
Visada URI dalis tarp scheme ir path.
username
Naudotojo vardas.
password
Slaptažodis.
host
Domeno vardas arba IP adresas.
port
Prievado numeris.
path
Kelias.
query
URL dalis einanti tarp ? ir #.
fragment
URL dalis einanti po #.
func.query()

Skaido URI query dalį į parametrus.

func.path()

Skaido failų sistemos arba URI kelią į tokias savybes:

parts
Skaido kelią į dalis (plačiau).
drive
Diskas (plačiau).
root
Šaknis (plačiau).

Kompleksinės struktūros

Daugelis duomenų šaltiniu turi galimybę saugoti kompleksines struktūros. Jei duomenys yra kompleksiniai, tada property.source stulpelyje galima nurodyti tik duomens pavadinimą iš pirmojo lygmens, gilesniuose lygmenyse esančius duomenis galima aprašyti naudojant formules property.prepare stulpelyje.

Analogiškai duomenų atranką galima daryti ir model eilutėse, jei tai leidžia duomenų šaltinis.

Kaip pavyzdį naudosime tokią JSON duomenų struktūrą:

{
    "result": {
        "count": 1,
        "results": [
            {
                "type": "dataset",
                "tags": ["CSV"]
            }
        ]
    }
}
property.prepare
func.getattr(object, name)

Grąžina object savybe name.

>>> self.result.count
1
func.getitem(object, item)

Grąžina object objekto item savybę arba object masyvo item elementą.

>>> self["result"]["count"]
1

getitem() ir getattr() gali būti naudojami kartu.

>>> self.result.results[0].type
"dataset"

getitem() gali būti naudojamas, kaip masyvo elementų filtras pateikiant filtro sąlygą.

>>> self.result.results[tags = "CSV"].type
["dataset"]

>>> self.result.results[item(tags) = "CSV"].type
["dataset"]

Norint gauti visus masyvo elementus, galima naudoti tokią išraišką:

>>> self.result.results[].tags[]
["CSV"]

Analogiška struktūra gali būti gaunama ir lentelėse, kai stulpelių pavadinimai nurodyti keliose eilutėse, pavyzdyje pateiktą struktūrą atitiktų tokia lentelė:

result    
count results  
type tags
1 dataset CSV

Šioje lentelėje stulpelių pavadinimai pateikti trijose eilutėse, todėl model.prepare reikėtų naudoti header(0, 1, 2).