jandoubek / pvs-2020-lectures

Project for PVS lecture in fall 2020
0 stars 0 forks source link

Získat data #3

Open pakk-minidose opened 3 years ago

pakk-minidose commented 3 years ago

Bude potřeba získat data pro aplikaci.

agehrtenab commented 3 years ago

Zeptal jsem se paní Majerové ohledně popisů předmětů a dat rozvrhu. Pokud jde o popisy předmětů, odkázala mě na pány Beneše a Fučíka, tak jim napíšu. Pokud jde o data aktuálního rozvrhu, ta jsou na adrese https://rozvrh.fjfi.cvut.cz/timetable/20-21-zimni.xml.

hetsko commented 3 years ago

Ještě k tomu scrapování - objevil jsem celoškolní bílou knihu http://bilakniha.cvut.cz/cs/f4.html, popřípadě http://bilakniha.cvut.cz/cs/f4-predmety.html.

Existuje v ní předmět 01TR1, 01TR2, který v geraldine není (myslím, že je to nový předmět, je z nového oboru AAA). Tudíž tady možná jsou všechny předměty. Na druhou stranu to je aktuálně místy děravé ve smyslu chybějícího počtu kreditů a hodin a přiřazení k oborům.

agehrtenab commented 3 years ago

Pan Fučík mě na tu stránku odkázal také. Podívám se, co všechno by z toho šlo vytáhnout. Z odkazů na tisk jednotlivých studijních plánů se dá najít XML, z kterých se formátují, pro každý studijní plán jeden soubor. Tam jsou tytéž informace ve strojově čitelné podobě.

SachCZ commented 3 years ago

Duplikát #9.

hetsko commented 3 years ago

Duplikát #9.

Diskutabilní? Sice se konverzace zvrhla k datům o rozvrhu, ale pointa téhle issue by mělo být konečné řešení toho, jak budeme získávat ta reálná data. A to jak

  1. z rozvrhu
  2. tak i (a asi primárně) z nějaké formy bílé knihy

Nechal bych to otevřené přinejmenším dokud @agehrtenab nepředstaví své skripty na stahování dat (z bílé knihy).

SachCZ commented 3 years ago

Duplikát #9.

Diskutabilní? Sice se konverzace zvrhla k datům o rozvrhu, ale pointa téhle issue by mělo být konečné řešení toho, jak budeme získávat ta reálná data. A to jak

  1. z rozvrhu
  2. tak i (a asi primárně) z nějaké formy bílé knihy

Nechal bych to otevřené přinejmenším dokud @agehrtenab nepředstaví své skripty na stahování dat (z bílé knihy).

Souhlasím 👍

agehrtenab commented 3 years ago

Jdu na to (jak jsme se myslím dohodli?) primárně podle bílé knihy, se kterou se v případě dostupnosti mergují data z rozvrhu. Ovšem tam jsem narazil na problém, který si asi zaslouží samostatné issue: jakožto nepražák jsem v BS nenarazil na situaci, že se jeden předmět dá zapsat více způsoby (zpravidla proto, že se v Praze u některých předmětů nemusejí všichni vejít do jedné učebny na cvičení), a v NMS v Praze jsme tohle neměli. Ale u některých předmětů to zřejmě je nutné řešit, a to jak na straně předvyplnění již zabraných časových slotů v rozvrhu i na straně zjišťování, zda si student může nějaký předmět zapsat.

Takže prozatím ještě řeším nějakou heuristiku, která toto bude hádat (a nejspíš se musíme kolektivně dohodnout, co s tím). Předpokládám, že výsledkem bude pro každý předmět něco jako seznam alternativních množin časových slotů, z nichž aspoň jedna musí být splnitelná, aby byl předmět vybrán do výsledku vyhledávání. Triviální příklad: předmět má v rozvrhu přednášku v Út 11.30-13.30 a cvičení jsou v Po 9.30-11.30 a ve Čt 11.30-13.30. Pak student musí mít čas v Po 9.30-11.30 A SOUČASNĚ v Út 11.30-13.30, NEBO musí mít čas v Út 11.30-13.30 A SOUČASNĚ ve Čt 11.30-13.30, pokud jsou to dvě paralelky.

Momentálně jsem commitnul exporty dat předmětů z BK, které případně doplním. Zatím je tam seznam studijních plánů/oborů s opravenými názvy (v BK jsou nepravidelnosti s mezerami a malými/velkými písmeny) k zobrazení (bakalářské obory se do seznamu v UI snadno vyfiltrují tak, že začínají třemi znaky "BS ", zatímco magisterské jsou ty zbývající) a k pozdějšímu referencování z předmětů, a samozřejmě seznam předmětů (dalši informace budou v případě potřeby doplněny). Jsou to dva skripty, abyste si nemusíte stahovat data opakovaně - první krok (stažení) stačí provést pouze jednou (zatím).

SachCZ commented 3 years ago

Proč je v tom prvním skriptu sleep 8 ? Předem dík.

SachCZ commented 3 years ago

Data vypadají skvěle, dobrý práce! Jinak trochu mě vyvedl z míry ten první skript, tak jsem udělal ten data fetch rovnou ve druhém skriptu, s tím že se to případně zapickluje, aby byl snazší debugging. Teď to fetchuje na mém internetu asi 36s, předtím to trvalo asi 6 min, z čeho mám podezření, že většina času byla sleep 8. První skript tedy již není třeba a tento by se možná slušelo přejmenovat.

Další věc je, že bych preferoval data nechat v JSON a nedělat "export const OBORY=" to mi připadá trošku hloupé. Prostě nech

{
"obory": ...,
"courses": ...
}

a v js něco na motivy:

import data from ‘./data/data.json’;

Jinak měl bych trochu konstruktivní kritiky k tomu jak je napsané to parsování. Můžu ti to sem napsat? Nerad bych tě urazil a přeci jen to funguje a to je hlavní. Ty data vypadají dobře a určitě muselo dát hrozné práce se v tom zorientovat, takže klobou dolů.

agehrtenab commented 3 years ago

Stažení dat je jednorázové, takže není důvod ho opakovat (minimálně dokud se nezmění BK), a jsem v podstatě zvyklý do takových věcí dávat sleep kvůli zátěži serverů (někdy tam může být i limit na requesty, někde jsem narazil i na auto IP bany).

Klidně z toho udělám jeden objekt, jestli chceš. Sem s jakýmikoli výhradami, je to napsané trošku narychlo, takže to ber jako prototyp/proof-of-concept. Určitě to šlo/půjde udělat líp v dalších iteracích.

SachCZ commented 3 years ago

Ne to je naprosto jasný, právě proto na to reaguji. Vůbec jsem nepředpokládal, že je to něco jiného něž proof of concept. I tak už je tam prostě rychlejší verze. Mám tušení, že ty data budeme stahovat častěji něž si teď myslíme.

Jinak můj názor na ten sleep je, že je to problém serveru a né náš. Jakmile bychom dostali ip ban za pokus o DDOS :laughing: tak to budeme řešit. Jdu na ty připomínky.

SachCZ commented 3 years ago

Nejde udělat code review na kódu, který už je v mainu. Tj. napíšu to sem trapně řádek po řádce.

Obecně:

Sprostě jsem smazal všechny commenty. Commenty dávej jen k definicím funkcí/class, kde slouži jako documentation comment. Nebo je li to úplně nezbytně nutné tak někam krátký komentíček do kódu (ale tvůj kód by měl být readable enough aby nepotřeboval tento typ komentů). Všechno ostatní co tam bylo a chceš to zmínit tak naházej tady do issues. Můžeš se dokonce odkazovat na konkrétní řádek v konkrétním commitu.

Nyní již řádek po řádku:

obory = parse_obory(...)

def parse_courses(...) for ... slozita logika yield ...

courses = parse_courses()

- 46 co je c (tím chci říct pojmenuj to rozumněji)
- 47 použivej "bla bla {}".format(current_semester)
- 48 až 53 naprosto zbytečné řádky
- 54 místo appedn yield
- 70 neděl řazení prostě zahoď ten BS (pun intended) a udělej bachelor_obory, masters_obory
- 73 je readable, nice !
- 75 prostě smazat - pokud chceš podávat nějaké info tak returni nějaké rozumné values a ty printuj v main, případně je li to nutné použi logging
- 77 - 87 bych prostě smazal, by now bys měl mít tři proměné `bachelor_obory` (list stringů), `masters_obory` (list stringů) a `courses`, list dict (ten id indexing je k ničemu). Poslední co zbývá je:

json.dump({"masters_obory": masters_obory, "bachelor_obory": bachelor_obory, "courses": courses}, file)


- 89 nepoužívej volně stojící open, použij with a nepužívej close

Shrnuto podtrženo, rozseskej to na funkce a ty zdokumentuj. Jestli nepoužáváš debugger, tak určitě začni (rád pomůžu), viděl jsem tam v kódu něco zakommentovaného pro debug, tak jsem to radši rychle smazal :smile: .

Jsem schopen obhájit si to co tady píšu, jsou k tomu různé důvody, ale už tak je to docela dlouhé, takže se spíš prosím ptej konkrétně. Snad je to srozumitelné. Naprosto chápu, že to byl první draft. Moje první drafty nevypadají jinak :smiley: .
agehrtenab commented 3 years ago

OK, ber to tak, že na Python sáhnu tak jednou za půl roku a není to můj "rodný jazyk", takže to podle toho stylově vypadá. ;) Ovšem v mém "rodnějším" Common Lispu nebo Scheme bych se to pro ostatní psát neodvažoval (to bych na tom pak dělal asi sám), takže musíme najít nějakou společnou řeč.

20: PEP-8 už neplatí? Měl jsem za to, že tohle byl normální styl.

22: Evil? Je s globem v Pythonu nějaký problém?

23: OK, to jsou nějaké věci, co by se ve větším programu nejspíše logovaly na info levelu nebo tak něco, ale tohle jsem nechtěl takhle komplikovat (ale přitom jsem potřeboval u některých věcí orientačně zjistit, kolik jich v datech je, tak jsem si je prostě vypsal - teď už to není tak důležité).

25: Myslim, že jde o to, že nějaké uzly s textem v XMLkách BK mohou být nepřítomné, prázdné, nebo s obsahem - tohle je řeší. Když třeba chybí anotace, tak z tohohle vypadne prázdný řetězec. Ten je neutrální vůči prohledávání, takže třeba nemusíš řešit speciální případy typu "pokud anotace je None NEBO v ní nejde najít X, vyřaď předmět z výsledků", stačí "pokud v anotaci nelze najít X, vyřaď předmět z výsledků". Takových polí tam bylo několik, takže helper, co to řeší na jednom místě.

31: Jo, ty názvy oborů mají nějaké nepravidelnosti, takže abych je slušně seřadil, tak tohle pomohlo. Ovšem celé tohle možná ještě budu řešit ještě jednodušeji - např. po opravě dvojitých mezer v názvech studijních plánů v BK už tohle vlastně nemusím řešit. Jinými slovy, tohle je myslím evoluční artefakt, odstraní se.

35: No reason, to jen bude ten můj nedostatek pythonýrské praxe. :) Jak mi to teď přišlo pod ruku, tak jsem to tam dal.

38: Jasně.

39: Tím máš na mysli použít výchozí parametry, nebo něco jiného? Změnil jsem formát kvůli čitelnosti výstupu při ladění.

41..43: Síla zvyku plus proof-of-concept efekt, taky jsem to chtěl nakonec přepsat do něčeho "méně skriptoidního". Klidně přepíšu. Opět evoluční artefakt ladění po kouskách.

46: c je course, opraví se.

47: Jasně, obyčejná lenost. :)

48..53: To byl myslím pozůstatek nějakého ladění, samozřejmě jsou v téhle fázi zbytečné.

54: Chápu, je to modulárnější (a souvisí s ~43 výše).

70: Toho se trošku bojím, protože datově jsou pořád na stejné úrovni a mám pocit, že jsem to kvůli něčemu takhle potřeboval. Teď se pokusím si vzpomenout, proč přesně (ale obecně nechci iterovat dvě kolekce místo jedné na více místech, kde to může být zapotřebí projít všechno najednou).

75: Jasne, už jsem zmiňoval u 23.

77-87: Tady jde o to, že v XML BK se odkazuje na studijní plány pomocí těch názvů, které opravuju, jenom jejich názvem. Nějakým způsobem je pak musím po extrakci předmětů překládat buď na opravené názvy - nebo na ta číselná ID - v okamžiku deduplikace. Každý předmět totiž dostanu z BK tolikrát, kolikrát je v nějaké roli (povinný nebo volitelný) obsažen v různých studijních plánech, jelikož každý studijní plán v XML má samozřejmě svoji kopii dat o daném předmětu (ověřoval jsem, že se jejich informace shodují, proto zahazuji všechny kromě prvního). Přitom číselná ID mi tady přijdou přirozenější, pokud si u předmětu potřebuju pamatovat, v jakých plánech je zahrnut v jaké roli, což dost možná budu potřebovat (což tam ještě musím dopsat, proto byl možná účel toho kusu kódu matoucí).

Ovšem nechat to v řetězcích znamená výrazně větší JSON data a spotřebu paměti (celá řada předmětů je v mnoha plánech, což by znamenalo mít v datech JS pole opakujících se řetězců), leda že bych na straně JS potom použil symboly (jsou internované - je zapotřebí méně paměti, porovnávání je O(1), atd.), což by možná šlo taky, ale nevím, kdo tuhle část bude psát a jestli nad tím mám kontrolu. Pokud bych tohle všechno smazal, tak mám pořád denormalizovaný seznam duplikovaných předmětů, se kterým musím něco dělat.

89: Já vím, to byla zase lenost. :)

Díky za připomínky. S pythoním debuggerem zkušenosti nemám, ale podívám se na něj. Nevěřím, že je tak užitečný jako debugger v SBCL, ale je pravda, že spoustu těch věcí, co jsem si tady ladil "pokoutnými" prostředky, by mi možná usnadnil. Bohužel jsem historicky většinou nepoužíval prostředí, kde by se zrovna pythoní debugger používal pohodlně, takže právě proto asi na něj nejsem zvyklý (třeba Emacs+SLIME/SLY má skvělý debugger pro SBCL, ale pro Python mi to v Emacsu přišlo takové e-e a nějak jsem na to rezignoval). Podívám se asi na PyCharm, jak to je v něm.

(Ale teď půjdu aspoň na chvíli spát. :))

SachCZ commented 3 years ago

Pokusím se o krátký příklad jak programovat v pythonu s daty. Představ si, že máš list stringů. Chceš removnout duplikáty, vyhodit všechny stringy == "pythonsucks" a ve výsledku vše kapitalizovat:

data = ["somestring", "pythonsucks", "another", "somestring"]
data = [s.capitalize() for s in set(data) if s != "pythonsucks"]
# result: ["Somestring", "Another"]

To že se tam nakopíruje ten set je všem většinou úplně jedno. To prostě neřeš :smile:.

Možná ti tenhle příklad připadá moc konkrétní, tak obecně:

def modify():
    ...
def condition():
   ...
def preprocess():
   ...
data = [modify(ele) for ele in preprocess(elements) if condition(element)]

Toto je neskutečně mocný nástroj. Pokud chceš, ještě něco složitějšího tak takovýhle řádků můžeš mít několik, ideálně schovaných do funkcí.

Zkus ten PyCharm.

agehrtenab commented 3 years ago

77: Každý výsledek (předmět) získaný z jednoho souboru BK obsahuje informace o předmětu (kód, anotace, atd.) plus o tom, v jakém plánu byl nalezený. Cílem je mít každý předmět jen jednou, ale se seznamem plánů, v kterých se nachází (ještě by u toho asi měly být role, což se doplní, pak by tam byl seznam dvojic (plán, role) ).

Set nad slovníky? To mě napadlo taky, ale měl jsem za to, že klíče (a tedy i prvky množin) mohou v Pythonu být pouze neměnné hodnoty. Jinak ty příklady chápu, ten prvotní kód prostě nebyl vyfaktorovaný do funkcí (určitě ne kvůli optimalizacím, prostě jen kvůli tomu, jak prototypově "vyrostl" někdy v druhou hodinu ranní :)).

SachCZ commented 3 years ago
SachCZ commented 3 years ago

Dovolil jsem si pro toto udělat user story #24.

agehrtenab commented 3 years ago

První rozumně funkční verze commitnuta v aaaa632f62494e0b6a3e9c0af3f37117398e9279.

Generuje soubor data.json, který je seznamem objektů jednotlivých předmětů. Každý předmět má následující klíče:

Obyčejná pole:

Pole pro fulltextové hledání

Rozvrh

[ [ { "od": 317.5, "do": 319.5, "typ": "C", "vyucujici": "Tran", "mistnost": "T-105", "budova": 2 }, { "od": 111.5, "do": 113.5, "typ": "C", "vyucujici": "Tran", "mistnost": "T-115", "budova": 2 } ], [ { "od": 211.5, "do": 213.5, "typ": "C", "vyucujici": "Kukal", "mistnost": "T-115", "budova": 2 }, { "od": 407.5, "do": 409.5, "typ": "C", "vyucujici": "Kukal", "mistnost": "T-115", "budova": 2 } ] ]

Tohle je předmět 18MPT, který má dotaci 0+4 a buď můžu chodit v pondělí 11.30-13.30 a ve středu v 17.30-19.30, NEBO můžu chodit v úterý 11.30-13.30 a ve čtvrtek v 7.30-9.30.