2012-07-10 18 views
7

Ho una query sparql che restituisce i duplicati e voglio che li pulisca solo su uno dei valori (subjectID). A differenza di DISTINCT sembra trovare un valore univoco per la combinazione di valori selezionati, piuttosto che per uno solo dei parametri. Ho visto qualcuno qui proporre il gruppo, ma ciò sembra applicabile solo se elenco tutti i parametri dopo il gruppo (il mio endpoint sparql si lamenta, ad esempio variabile chiave non di gruppo in SELECT:? Occupazione). Ho provato a eseguire una selezione interna, ma non sembra funzionare per questa query specifica. Quindi potrebbe essere un problema con la query stessa (i valori del vissutoIn opzionale sembrano causare il duplicato)?Chiavi Sparql rispetto a valori distinti

Mentre sei abbastanza felice con i DB relazionali nelle prime fasi della curva di apprendimento con SPARQL, quindi sentiti libero di spiegare l'ovvio per il contrario non iniziato! :)

select distinct 
    ?subjectID ?englishName ?sex ?locatedIn15Name 
    ?dob ?dod ?dom ?bornLocationName ?occupation 
    where { 
     ?person a hc:Person ; 
     hc:englishName ?englishName ; 
     hc:sex ?sex; 
     hc:subjectID ?subjectID; 
     optional { ?person hc:livedIn11 ?livedIn11 . 
      ?livedIn11 hc:englishName ?lived11LocationName . 
      ?livedIn11 hc:locatedIn11 ?locatedIn11 . 
      ?locatedIn11 hc:englishName ?locatedIn11Name . 
      ?locatedIn11 hc:locatedIn15 ?locatedIn15 . 
?locatedIn15 hc:englishName ?locatedIn15Name . 
} . 
     optional {?person hc:born ?dob } . 
     optional {?person hc:dateOfDeath ?dod } . 
     optional {?person hc:dateOfMarriage ?dom } . 
     optional { ?person hc:bornIn ?bornIn . 
     ?bornIn hc:englishName ?bornLocationName . 
      ?bornIn hc:easting ?easting . 
      ?bornIn hc:northing ?northing } . 
     optional { ?person hc:occupation ?occupation } 
     FILTER regex(?englishName, "^FirstName LastName") 
     } 
    GROUP BY 
    ?subjectID ?englishName ?sex 
    ?locatedIn15Name ?dob ?dod ?dom 
    ?bornLocationName ?occupation 

risposta

12

Re il messaggio di errore: variabile chiave

non-gruppo in SELEZIONATE:? Occupazione

È possibile evitare questo utilizzando il SAMPLE() aggregata - questo vi permetterà di raggruppare semplicemente su ?subjectID ma selezionare ancora i valori per il resto delle variabili, a condizione che si abbia interesse a ottenere un solo valore per quelle altre variabili.

Ecco un semplice esempio di questo:

SELECT ?subjectID (SAMPLE(?dob) AS ?dateOfBirth) 
WHERE 
{ 
    ?person a hc:Person ; 
      hc:subjectID ?subjectID . 
    OPTIONAL { ?person hc:born ?dob } 
} 
GROUP BY ?subjectID 
+0

+1 per (IMHO) uso molto non ortodosso di CAMPIONE. –

+0

Grazie Rob, è davvero utile! Immagino che sia un campionamento un po 'non deterministico, quindi da usare con cautela? :) – Nava

+0

PS Will upvote una volta guadagnerò un po 'più di reputazione. – Nava

9

La prima cosa da notare è che non esiste una cosa come una chiave, in realtà, in RDF/SPARQL. Stai interrogando un grafico e ?subjectID potrebbe semplicemente avere diverse possibili combinazioni di valori per le altre variabili che stai selezionando. Questo è causato dalla forma del grafico che stai interrogando: forse la tua persona ha più di un nome inglese, o addirittura il contrario: lo stesso nome inglese può essere condiviso da più di una persona.

Una query SELECT SPARQL è una strana bestia: interroga una struttura di un grafico ma presenta il risultato come una tabella piatta (tecnicamente, è una sequenza di insiemi di associazioni di variabili, ma equivale alla stessa cosa). I duplicati si verificano perché è possibile trovare diverse combinazioni di valori per le variabili seguendo fondamentalmente i diversi percorsi del grafico.

Il fatto che si ottengano valori duplicati per ?subjectID nel risultato è quindi inevitabile, semplicemente perché questi sono, dal punto di vista del grafico RDF, soluzioni univoche alla query. Non è possibile filtrare i risultati senza perdere effettivamente le informazioni, quindi in generale è difficile dare una soluzione senza sapere più esattamente su che "duplicati" che si desidera eliminare: si desidera solo un possibile nome inglese per ciascun argomento, oppure una possibile data di nascita (anche se ce ne possono essere più di una nei tuoi dati)?

Tuttavia, ecco alcuni suggerimenti per la gestione/procesing tali risultati più facilmente:

Prima di tutto, si può scegliere di utilizzare una clausola ORDER BY sul variabile ?subjectID. Questo ti darà ancora diverse righe con lo stesso valore per ?subjectID, ma saranno tutte in ordine, quindi puoi elaborare i risultati in modo più efficiente.Un'altra soluzione è dividere la query in due: fare una prima query che solo seleziona tutti i soggetti unici (e possibilmente tutti gli altri valori per i quali si sa, in anticipo, che saranno univoci data l'argomento), quindi scorrere il risultato e fare una query separata per ottenere gli altri valori a cui sei interessato, per ogni singolo valore ID soggetto. Questa soluzione potrebbe sembrare un'eresia (specialmente se provieni da uno sfondo SQL), ma potrebbe essere in realtà più veloce e più facile che tentare di fare tutto in un'unica enorme query.

Un'altra soluzione è quella suggerita da RobV: utilizzando un aggregato SAMPLE su una particolare variabile per selezionare solo un valore univoco (casuale). Una variante su questo è usare l'aggregato GROUP_CONCAT, che crea un singolo valore concatenando tutti i possibili valori in una singola stringa.

+0

Wow, grazie, è immensamente utile. Ho imparato tanto a leggere la tua risposta. Mentre aspettavo, ho effettivamente refactored un po 'e diviso la query in due. Va contro il mio senso di efficienza, ma è una soluzione semplice e pulita. Non ho mai usato 'GROUP_CONCAT' in SQL, ma fondamentalmente questo risolve la mia domanda su cosa fare con la struttura grafica piatta. La mia prossima domanda, già anticipata! (come nel caso di RobV, in aumento rispetto a quando ho guadagnato un po 'più di reputazione) – Nava