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 formulė 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 param.

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)#

Išgaunama data ir laikas iš str, naudojant strftime formatą.

func.date(str, format)#

išgaunama data iš str, naudojant strftime formatą.

func.date(datetime)#

Gražinama data iš datos ir laiko.

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 vieną 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 simbolius 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š enum, 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)#

Pakeičia old reikšmę new, jeigu self atitinka 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 į objektą 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ūras. 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 savybę 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"]
func.first(object, default)#

Grąžina pirmą object sąrašo reikšmę, jei sąrašas tuščias, tada grąžina default reikšmę, jei default nenurodytas, tada nutraukia vykdymą su klaidą.

>>> self.result.results[].tags.first()
"CSV"

Jei `self.result.results[].tags būtų tuščias, tada:

>>> self.result.results[].tags.first(null)
null

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).