问题
I have the following DBpedia SPARQL that shows philosophers that influenced philosophers. However, it returns duplicates when the philosopher has more than one foaf:name
:
SELECT ?name ?influencedName
WHERE {
?philosopher a dbpedia-owl:Philosopher ;
dbpedia-owl:influenced ?influenced ;
foaf:name ?name .
?influenced a dbpedia-owl:Philosopher ;
foaf:name ?influencedName .
}
SPARQL results
How can I return a single name if there are multiple values for ?name
and ?includedName
. I would be happy with the first one, or the least number of characters to pick which to keep.
Here is another example for just Plato influencing Bertrand Russell. I would like this to return one row, but I get four:
SELECT ?name ?influencedName
WHERE {
?philosopher a dbpedia-owl:Philosopher ;
dbpedia-owl:influenced ?influenced ;
foaf:name ?name , "Plato"@en .
?influenced a dbpedia-owl:Philosopher ;
foaf:name ?influencedName, "Bertrand Arthur William Russell, 3rd Earl Russell"@en .
}
SPARQL results
回答1:
The Queries
It sounds like you want a query something like:
SELECT ?philosopher ?pName ?influence (SAMPLE(?iName) as ?iName)
WHERE {
# This subquery selects all the philosophers and
# selects just one of their names .
{
SELECT ?philosopher (SAMPLE(?pName) as ?pName) WHERE {
?philosopher a dbpedia-owl:Philosopher ;
foaf:name ?pName .
}
GROUP BY ?philosopher
}
# This main query selects the influence of the
# philosophers and select their names. The GROUP
# BY on the outer query puts all the
# (?philosopher,?pName,?influence,?iName) tuples
# that have the same ?philosopher, ?pName, and
# influence together, and the (SAMPLE(?iName) as ?iName)
# in the outer SELECT combines them all, choosing an
# arbitrary representative ?iName.
?influence dbpedia-owl:influenced ?philosopher ;
a dbpedia-owl:Philosopher ;
foaf:name ?iName .
}
GROUP BY ?philosopher ?pName ?influence
SPARQL results
If you are only interested in the names, and do not care about selecting the actual resources, you do not need ?philosopher
and ?influence
in the outermost SELECT
and can make it
SELECT ?pName (SAMPLE(?iName) as ?iName)
WHERE { …
SPARQL results
You also might want to add an ORDER BY
at the end to make the results a little bit easier to check:
…
GROUP BY ?philosopher ?pName ?influence
ORDER BY ?pName
SPARQL results
These last results include, for Plato, the following rows:
"Plato"@en "Socrates"@en
"Plato"@en "Parmenides"@en
"Plato"@en "Zeno of Elea"@en
"Plato"@en "Pythagoras"@en
"Plato"@en "Gorgias"@en
"Plato"@en "Protagoras"@en
"Plato"@en "Heraclitus"@en
In the query I've written here, I've used SAMPLE to pick one of the foaf:name
s of a philosopher arbitrarily, but there are other functions in the aggregate algebra that you can use to select a value. Min might be interest to you if you want the ‘first‘ value in order.
Subqueries, GROUP BY, and SAMPLE, MIN, etc.
This is actually very similar to the example given for subqueries in Section 12, Subqueries of the SPARQL specification. In that example, the following query is used to select the people that Alice knows, and for each one, select just one of the names of the people:
PREFIX : <http://people.example/>
SELECT ?y ?minName
WHERE {
:alice :knows ?y .
{
SELECT ?y (MIN(?name) AS ?minName)
WHERE {
?y :name ?name .
} GROUP BY ?y
}
}
This was not to hard to adapt for the philosophical influence problem. The philosophers problem began by selecting all the philosophers and their names, grouping by the actual philosopher resource, and picking a representative name for each philosopher using sample. The outer query does the same, but rather than selecting philosophers, it is selecting the entities that influenced each philosopher. The results are grouped and a representative name for the influence is selected.
回答2:
I have determined how I want to select the unique name for a philosopher, see sparql below that returns one name for each philosopher.
However, I don't see a why to incorporate this in the larger query that returns a name both for philosopher and for influenced philosopher without running this code once for each philosopher which would be a large and unwieldy query. My sense is that my code will be more readable if I run the philosopher names and the influensed by queries separatly and look up the names in code rather than sparql. Perhaps I am missing some sparql feature that will make this easy. Please Advice
Here is the description of how I am getting unique names:
Get all names for a Philosopher from foaf:names and dbprop:names Filter to include only names that contain at least one Latin letter character ( A-Z ) Find the length of the shortest names Pick the minimum of all of the names that are shortest
PREFIX dbpedia: <http://dbpedia.org/>
PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dbpprop: <http://dbpedia.org/property/>
SELECT ?philosopher (min(?name) as ?minName)
WHERE {{
?philosopher foaf:name ?name .
} UNION {
?philosopher dbpprop:name ?name .
}
FILTER( strlen(?name) = ?minLength ) . # get the shortest names
FILTER( REGEX( str(?name) , "[A-Z]" )) . # exlude names with no latin charachters
{
SELECT ?philosopher (min(strlen(?name)) as ?minLength)
WHERE {{
?philosopher a dbpedia-owl:Philosopher ;
foaf:name ?name .
} UNION {
?philosopher a dbpedia-owl:Philosopher ;
dbpprop:name ?name .
}
FILTER( REGEX( str(?name) , "[A-Z]" )) .
}
GROUP BY ?philosopher
}
}
GROUP BY ?philosopher
ORDER BY ?philosopher
来源:https://stackoverflow.com/questions/17129225/how-to-return-a-single-foafname