mff-uk / odcs

ODCleanStore
1 stars 11 forks source link

SPARQL Loader NOT Working correctly #316

Closed tomas-knap closed 10 years ago

tomas-knap commented 11 years ago

It does not take into account literals, datatypes, language tags. Everything is hardcoded as URI.

Is there any warning reported?

Jirka can you please start by explaining the functionality of the code below? I mean the replace calls Then we can discuss how to implement it better

 for (Statement nextStatement : statements) {

                String subject = nextStatement.getSubject().stringValue();
                String predicate = nextStatement.getPredicate().stringValue();
                String object = nextStatement.getObject().stringValue();

                object = object.replaceAll("", "")
                        .replaceAll("\\s+", "_")
                        .replaceAll("<", "‹")
                        .replaceAll(">", "›");

                String appendLine = "<" + subject + "> <" + predicate + "> <" + object + "> . ";
                builder.append(appendLine.replaceAll("\\s+", " ").replaceAll(
                        "\"", "'"));

                count++;
                if (count == sizeSplit) {
                    builder.append(insertStop);
                    parts.add(builder.toString());

                    builder = new StringBuilder();
                    builder.append(insertStart);
                    count = 0;
                }
            }  
tomesj commented 11 years ago

object = object.replaceAll("<br\s*/>", "") .replaceAll("\s+", "_") .replaceAll("<", "‹") .replaceAll(">", "›");

String appendLine = "<" + subject + "> <" + predicate + "> <" + object + "> . "; builder.append(appendLine.replaceAll("\s+", " ").replaceAll( "\"", "'"));

Když jsem zkoušel nahrávání dat na SPARQL endpoint, ukázalo se, že jsou některé speciální znaky tomu vadí a bez nich to neprojde....

Kde je problém: 1) object - literál nesmí mít bílé znaky(nahrazeno _), obsahovat šipky <, >, (speciálně pak html značku <\br>) - nahrazeno podobnými šipkami, u kterých to navadí 2) subject, object - nesmí mít bílé znaky(nahrazeno mezerami) 3) trojice nesmí obsahovat jednoduché úvozovky ' - nahrazeno dvojitými "

2) Na SPAQRL endpoint lze vkládat data do Virtuosa se syntaxí: INSERT { http://subject http://predicate http://object . http://sub2 http://pred2 http://obj2 . .... }

3) Implementace funguje to tak, že se vezmou všechny trojice určené k nahrání - ty se rozdělí na bloky o stejné velikosti dané STATEMENTS_COUNT (aktuálně 10) - počet trojic v jednom insert bloku. Tedy podle syntaxe 2) se vytvoří příkazy několik insert bloků z nichž každý má příkaz pro vložení daného počtu (10) prvků (nebo menšího u posledního bloku).

Pak se všechny tyto příkazy pošlou postupně do Virtuosa - postupně probíhá vkládání všech prvků, až jsou vloženy všechny prvky, co jsou potřeba.

Důvod je ten, že jsem nenašel jiný rozumný způsob, jak zařídit efektivně třeba nahrání celého obsahu trojic najedou.

Touhle myšlenkou to nejde, protože příkaz pro nahrání se posílá přes get jako string a ten nemá neomezenou kapacitu, ale vložit (10 nebo klidně 50) prvků naráz zvládne.

tomas-knap commented 11 years ago

Aha,

je tam problem v tom, ze na tom radku:

String appendLine = "<" + subject + "> <" + predicate + "> <" + object + "> . ";

Vlastne rikas, ze se maji vlozit trojice, ktere obsahuji same URI ,ale to tak neni. Literal neni URI, tedy pokud je v trojici literal napr. "U s n e s e n i", tak se z toho nesmi udelat URI , to je zmena puvodnich dat, ktera neni pripustna. Musime zachovat literaly, pripadne dalsi veci

tomas-knap commented 11 years ago

Jeste k tomu rozdelovani do bloku, tech 10 bloku jsi urcil nejak nahodne a je stejny pro libovolne velka RDF data?

tomesj commented 11 years ago

Je mi jasné, že literály chceme původní a originální. Jen najít něco, jak toho docílit....Zkusím se podívat ještě jednou na syntaxi vkládání, jestli na to není nějaká konstrukce, aby to prošlo :-)

K těm blokům - je to aktuálně pro všechny data určená k nahrání na SPARQL endpoint stejné.

tomas-knap commented 11 years ago

Ok, mrkni prosim a posli sem mozna reseni

tomesj commented 11 years ago

Tak jsem přece jen něco našel - u literálu stačí použít uvozovek a pak není s vložením problém, rovnou jsem to zkusil a opravdu to funguje (nevadí potom šipky, mezery ani jednoduché úvozovky), jen je potřeba nahradit případné " v literálu za \"...

Opravím to rovnou v implementaci :-)

tomas-knap commented 11 years ago

Jirko, porad tam vidim problem.

mas tam neco jako:

 String subject = nextStatement.getSubject().stringValue();
                String predicate = nextStatement.getPredicate().stringValue();
                String object = nextStatement.getObject().stringValue();
                subject=subject.replaceAll("\\s+","").replaceAll("\"","'");
                predicate=predicate.replaceAll("\\s+","").replaceAll("\"","'");

                String appendLine = "<" + subject + "> <" + predicate + "> \"" + object + "\" . ";
                builder.append(appendLine);  

Nicmene problemy jsou nasledujici:

  1. Vsechny nodes beres jako Stringy. to obecne neni dobre. Ty potrebujes rozlisit co je URI resource, co je literal, co je literal s datovym typem "10"^^xsd:integer (turtle zapis), co je literal s jazykovym tagem - "xx"@en je jiny literal nez "xx"@de, ale ty ztratis informaci o jazyku.Tedy nelze brat vse jako String, je treba to rozlisovat
  2. nechapu subject.replaceAll("\s+","").replaceAll("\"","'"); To vede akorat k tomu, ze odstranis mezery ze subjektu, coz bys delat nemel. Ty bys proste mel proste nahrat data tak, jak jsou. Chyby by mel odstranovat RDF data validator, ktery mas v planu. Tedy tyhle dva radky bych vynechal.
  3. String appendLine = "<" + subject + "> <" + predicate + "> \"" + object + "\" . "; Nebude fungovat. Neb kdyz bude objekt URI resource, tak z nej udelas literal. Plus je treba zohlednit datove typy, jazyky, jak je v bodu 1. Tedy bod 1 je jeste treba rozpracovat.
tomesj commented 11 years ago

No bral jsem to tak, že URI, nesmí mít nikdy mezery, jinak to selže - pokud to tedy necháme na validaci a nastane-li tento případ, tak vyhodit výjimku, tak to dává smysl....

Jinak bych si chtěl ujasnit pár věcí: subject - je vždy jen URI nebo Literál ? predicate - je vždy URI object - je buď URI nebo Literál....

Je to tak, bych potřeboval vědět s jistotou ?

Potom by se hodilo napsat to tak, aby se rozlišili jednotlivé případy. subject - vrací totiž obecně resource predicate -vrací URI object - vrací Value

A následně to rozlišit pomocí instanceof.

Co ty na to ?

tomas-knap commented 11 years ago

http://www.w3.org/TR/2004/REC-rdf-concepts-20040210/#dfn-subject:

the subject, which is an RDF URI reference or a blank node the predicate, which is an RDF URI reference the object, which is an RDF URI reference, a literal or a blank node

tomas-knap commented 11 years ago

zkusim si oddebugovat ten rdf loader

tomesj commented 11 years ago

OK, díky...Akorát jsem to taky našel :-) Ještě se podívám, jak se to se syntaxí pro vkládání blank_nodes, pak implementuju :-)

tomas-knap commented 11 years ago

Jirka, I have adjusted that a bit, it seems to be ok now. But, when I try to SPARQL load to:

http://localhost:8890/sparql-auth, with user and password set, it does not work and error is reported (see below) Did you test it with sparql-auth? If not, please test and let me know when done. Please try that asap.

cz.cuni.xrg.intlib.commons.loader.LoadException: HTTP/1.1 400 Bad Request. You probably dont have enought PERMISSION for this action. at cz.cuni.mff.xrg.intlib.loader.rdf.RDFLoader.load(RDFLoader.java:65) at cz.cuni.xrg.intlib.backend.execution.PipelineWorker.runLoader(PipelineWorker.java:643) at cz.cuni.xrg.intlib.backend.execution.PipelineWorker.runNode(PipelineWorker.java:577) at cz.cuni.xrg.intlib.backend.execution.PipelineWorker.run(PipelineWorker.java:338) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:722) Caused by: cz.cuni.xrg.intlib.rdf.exceptions.RDFException: HTTP/1.1 400 Bad Request. You probably dont have enought PERMISSION for this action. at cz.cuni.xrg.intlib.rdf.impl.BaseRDFRepo.getEndpointStreamReader(BaseRDFRepo.java:1592) at cz.cuni.xrg.intlib.rdf.impl.BaseRDFRepo.loadtoSPARQLEndpoint(BaseRDFRepo.java:588) at cz.cuni.mff.xrg.intlib.loader.rdf.RDFLoader.load(RDFLoader.java:62) ... 6 more

tomesj commented 11 years ago

Jo, zkoušel jsem to u mě na sparq-auth a vše bylo OK.

tomas-knap commented 11 years ago

Jirko, problem je v tom, ze mi to hazi chybu HTTP/1.1 400 Bad Request., ale problem je v tom, ze se ten INSERT proste nepodari, nebot jsou tam nejake problemy s validitou dat, napriklad:

Virtuoso 22007 Error DT006: Cannot convert Date2012-02-09T10:00:00 to datetime : Incorrect year delimiter
SPARQL query:
define sql:big-data-const 0 
#output-format:text/n3
define input:default-graph-uri  INSERT {  """Date2012-02-09T10:00:00"""^^ .  """2012-01-27TLhůta pro doručení žádostí o dokumentaci nebo pro přístup k dokumentům: 27.1.2012:00"""^^ .  """Date2012-02-09T10:00:00"""^^ .  """Date2012-02-09T10:00:00"""^^ .   .  """wie oben"""@de .  """ Herrn Berger Hans"""@de .   .  _:b10208 .  _:b10209 .} 
tomas-knap commented 11 years ago

Jirko, pohraj si tedy prosim s tim a pokud je chyba v datech a pri pokusu o nahrani se vrati trebas "Virtuoso 22007 Error DT006: Cannot convert Date2012-02-09T10:00:00 to datetime : Incorrect year delimiter", tak je potreba tohle reportovat uzivateli (a ne zavadejici chybu HTTP bad request). Pridej prosim take do dialogu do details moznost nastavit si, jak se chovat pri chybe tohoto typu:

1) Bud se dany INSERT part preskoci a jede se dal a zaznamena se warning 2) V pripade takoveto chyby prace loaderu skonci, poznamena se error, vsechny predhozi zaznamy se smazou, tedy zadne dosavadni INSERTed parts se neobjevi v target grafu (tedy nejjednodussi je v tomto pripade, pokud se merguji data (tedy neprepisuji, je tato volba zaskrtnuta na loader->details), nahrat ty data do nejakeho temp grafu a az kdyz se opravdu vsechny insert parts povedou, tak teprve prekopirovat (primergovat) data do prislusneho ciloveho grafu. Jinak hrozi, ze pri chybe tam nejaka data uz budou a nejaka ne, coz je blbe!

tomesj commented 11 years ago

Zkoušel jsem vložit např. trojici insert {_:464 http://predicate "Date2012-02-09T10:00:00"^^xsd:datetime .}

A ta prošla v pořádku. Tedy žádný problém s typem.

Zjistil jsem, že u objektů v případě literálů by se měly používat jen jedny úvozovky, nikoliv troje (v některých případech to totiž způsobuje potíže)

Správně tedy 1) "Date2012-02-09T10:00:00"^^xsd:datetime místo """Date2012-02-09T10:00:00"""^^xsd:datetime (i když v tomto konkrétním případě projdou oba, ale narazil jsem na případ, kdy to tak nebylo...)

V kódu to tedy opravím.

Pro jistotu ale přidám do detail v rámci DPU ty 2 možnosti, jak píšeš + jejich implementaci.

Máš nějaká data, na které jsi to zkoušel, že bych to taky zkusil ? Případně použiju DBPedii či TED data.

tomesj commented 11 years ago

Zajímavý rovněž je i například to, že 1) insert {_:125 http://a "2012-01-27TLhůta pro doručení žádostí o dokumentaci nebo pro přístup k dokumentům: 27.1.2012:00"^^xsd:datetime .}

PROJDE

Ale 2) insert {_:125 http://a "2012-01-27TLhůta pro doručení žádostí o dokumentaci nebo pro přístup k dokumentům: 27.1.2012:00"^^xsd:dateTime .}

NEPROJDE a nahlásí chybu : Virtuoso 22007 Error DT006: Cannot convert 2012-01-27TLhůta pro doručení žádostí o dokumentaci nebo pro přístup k dokumentům: 27.1.2012:00 to datetime.

Měl by tento literál projít nebo ne ?

tomas-knap commented 11 years ago

Jirko, odkazes me prosim na misto, kde ses dozvedel, ze troje uvozovky jsou problem? Jsem myslel, ze by to melo byt ekvivalentni a trojite uvozovky naviz umozni mit normalni uvozovky v textu a dalsi veci

K tem datum, zkus ten ted, soubor co ma asi 53KB. Mno, asi uz jsi zkusil, ale pro jistotu jeste pisu

Jirko, k tomu literalu "2012-01-27TLhůta pro doru....", pokud se kontroluj, zda dana hodnota je opravu typu xsd:dateTime, tak to nemuze projit. Je divne, ze ti ten prvni priklad projde a druhy ne. V cem se lisi??

tomesj commented 11 years ago

Tak nakonec to navadí, mě jsem jeden z mnoha příkladů, kdy to tak vypadalo, že ano, ale nakonec se ukázalo, že 3 úvozovky jsou taky OK....Takže to už je vyřešené.

Jinak jsem to zkoušel právě na TED souboru - momentálně už tam máme možnost přeskočit parts, které mají chybu (dá se warning) nebo přerušit a vyhodit výjimku a skončit.

Příklady se liší v tom, že jeden je xsd:datetime (vše malé) - projde , ale xsd:dateTime (s velkým T) - neprojde... V tomto konkrétním případě je správně to druhé - projít by to nemělo.

Správný dateTime je totiž např: 2012-01-27T12:15:30 (tedy datum v rok-mesic-den+T+čas v hod:min:sec)

tomas-knap commented 11 years ago

Dobra, tak tam ale prosim dej zpet ty troje uvozovky, pokud jsi je jeste nedal ;-) Aha, mno, tak ten duvod je ten, ze zatimco xsd:dateTime je validni datovy typ z XML Schema, xsd:datetype je blbe, resp. je to jiny datovy typ, jehoz vyznam, ale Virtuoso nezna a proto nezakrici kdyz tam clovek cpe blbosti

tomas-knap commented 11 years ago

Jeste k te variante, kdy se vyhodi vyjimka a skonci se, funguje to opravdu "transakcne"? Tedy kdyz mi to spadne u posledniho parts, vyhodi se vyjimka, skonci nahravani a zadne predchozi data se tam nenahrajou? Viz jak jsem psal ten trik s pouzitim temp named grafu.

tomesj commented 11 years ago

Troje úvozovky jsou zpět. Zkoušel jsem zatím jen netransakční variantu, jak to vůbec bude fungovat. Na transakční variantě pracuju teď...

Řešil jsem dnes hlavně testování complex pipeline, vypadá to na pár problémů, ještě to prozkoumám víc a pak to napíšu k odpovídajícímu issue :-)

tomesj commented 11 years ago

Tak přidána i varianta podporující transakce :-) Tím je to asi uzavřené :-)

tomas-knap commented 11 years ago

Thanks, I will test and then close