SPARQL query for individuals with same properties - sparql

I'd like to identify all individuals, that have the same properties as some other individuals. Imagine having different shopping lists with different items on them one can either buy or rent (object properties). To make things more complex, I also want to pay an exact amount for the parking and travel a certain distance (data properties). At the same time, there exist different stores offering different items.
Being a lazy person, I would like to identify the stores for each list, that offer all the items on the list.
I believe this is a generalization of this question but I somehow cannot wrap my head around how to do this.
I created some sample individuals:
#prefix : <http://www.shopping.org/model#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix xml: <http://www.w3.org/XML/1998/namespace> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#base <http://www.shopping.org/model> .
<http://www.shopping.org/model> rdf:type owl:Ontology .
# Object Properties
:buy rdf:type owl:ObjectProperty .
:rent rdf:type owl:ObjectProperty .
# Data properties
:distance rdf:type owl:DatatypeProperty .
:parking rdf:type owl:DatatypeProperty .
# Classes
:Product rdf:type owl:Class .
:ShoppingList rdf:type owl:Class .
:Store rdf:type owl:Class .
# Individuals
:Apples rdf:type owl:NamedIndividual ,
:Product .
:Cereal rdf:type owl:NamedIndividual ,
:Product .
:List1 rdf:type owl:NamedIndividual ,
:ShoppingList ;
:buy :Apples ,
:Milk ;
:distance "9.0"^^xsd:float ;
:parking "10.0"^^xsd:float .
:List2 rdf:type owl:NamedIndividual ,
:ShoppingList ;
:buy :Cereal ,
:Milk ;
:rent :TV ;
:distance "5.0"^^xsd:float ;
:parking "10.0"^^xsd:float .
:Milk rdf:type owl:NamedIndividual ,
:Product .
:Store1 rdf:type owl:NamedIndividual ,
:Store ;
:buy :Apples ,
:Cereal ,
:Milk ,
:TV ;
:distance "9.0"^^xsd:float ;
:parking "10.0"^^xsd:float .
:Store2 rdf:type owl:NamedIndividual ,
:Store ;
:buy :Cereal ,
:Milk ;
:rent :TV ;
:distance "5.0"^^xsd:float ;
:parking "10.0"^^xsd:float .
:TV rdf:type owl:NamedIndividual ,
:Product .
# General axioms
[ rdf:type owl:AllDisjointClasses ;
owl:members ( :Product
:ShoppingList
:Store
)
] .
and also tried some first queries. This is the best I have:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX : <http://www.shopping.org/model#>
SELECT DISTINCT ?list ?store ?prop
WHERE {
?list a :ShoppingList .
?store a :Store .
?list ?prop [] .
FILTER NOT EXISTS {
?list ?prop ?value .
FILTER NOT EXISTS {
?store ?prop ?value .
}
}
}
ORDER BY ?list ?store
However, this query returns all combinations of stores and lists, since every store charges 10.0f for parking.
How can I filter only those stores, which meet all the requirements of a list?
An additional assumption is, that there may exist other business models than buy and rent, as well as other criteria, i.e. data properties, which are of interest, too. This is why I do not want to specify these properties, but want to use variables instead.
This query did what I intended to do:
PREFIXES [as above]
PREFIX : <http://www.shopping.org/model#>
SELECT DISTINCT ?list ?store
WHERE {
?list a :ShoppingList .
?store a :Store .
FILTER NOT EXISTS {
?compat a owl:DatatypeProperty
FILTER NOT EXISTS {
?list ?compat ?value .
?store ?compat ?value .
}
}
FILTER NOT EXISTS {
?subset a owl:ObjectProperty .
?list ?subset ?value .
FILTER NOT EXISTS {
?store ?subset ?value .
}
}
}
ORDER BY ?list ?store
My mistake was actually just that I defined the ?prop outside of the filters. This resulted in them being part of the solution, i.e. I was was unable to remove whole stores through the filter(s).

If you're willing to specific about the particular property that the things need to have in common, you can do something like this. I've cleaned up your data, because it didn't actually have the necessary prefix declarations. Please include complete data if you expect people to be able to work with what you're providing. I didn't add correct prefixes, but just enough to get things working.
Sample Data
#prefix : <urn:ex:> .
#prefix owl: <file:///home/taylorj/tmp/data.ttl> .
#prefix xsd: <file:///home/taylorj/tmp/data.ttl> .
:Store1 a owl:NamedIndividual , :Store ;
:buy :Apples , :Cereal , :Milk , :TV ;
:distance "9.0"^^owl:float ;
:parking "10.0"^^owl:float .
:List2 a owl:NamedIndividual , :ShoppingList ;
:buy :Cereal , :Milk ;
:distance "5.0"^^owl:float ;
:parking "10.0"^^owl:float ;
:rent :TV .
:List1 a owl:NamedIndividual , :ShoppingList ;
:buy :Apples , :Milk ;
:distance "9.0"^^owl:float ;
:parking "10.0"^^owl:float .
:Store2 a owl:NamedIndividual , :Store ;
:buy :Cereal , :Milk ;
:distance "5.0"^^owl:float ;
:parking "10.0"^^owl:float ;
:rent :TV .
Specific Solution
First, we can address the specific case where we need one individual to have a subset of the property values of another for one property (buy), and to have intersecting values for other properties (distance, parking).
Query
prefix : <urn:ex:>
select ?list ?store {
#-- For each list and store
?list a :ShoppingList .
?store a :Store .
#-- Check that they have the same distance and parking.
?distance ^:distance ?list, ?store .
?parking ^:parking ?list, ?store .
#-- Check that every item to buy (or rent) on the list is also
#-- in the store to buy (or rent).
filter not exists {
values ?get { :buy :rent }
?list ?get ?item .
filter not exists {
?store ?get ?item
}
}
}
Results
--------------------
| list | store |
====================
| :List1 | :Store1 |
| :List2 | :Store2 |
--------------------
General Approach
Often times it's helpful to think in terms of eliminating the results that you don't want. In this case, you have two kinds of properties: (i) properties where the individuals must have a compatible value, and (ii) properties where one individual must have a superset of the values of the other individual. Checking if either of those conditions doesn't hold is not too hard:
prefix : <urn:ex:>
select ?list ?store {
#-- For each list and store
?list a :ShoppingList .
?store a :Store .
#-- Check that for each "compatible property" ?compat,
#-- there must be some value that the ?list and the
#-- ?store have in common.
filter not exists {
values ?compat { :distance :parking }
filter not exists {
?list ?compat ?value .
?store ?compat ?value .
}
}
#-- Check that for each "subset property" ?subset,
#-- there is no value that the ?list contains that
#-- the store does not.
filter not exists {
values ?subset { :buy :rent }
?list ?subset ?value
filter not exists {
?store ?subset ?value
}
}
}
Results (the same)
--------------------
| list | store |
====================
| :List1 | :Store1 |
| :List2 | :Store2 |
--------------------

Related

How do I deduce all of a person's descendants?

Here is my example.owl:
#prefix : <#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#base <http://ex.org> .
<http://ex.org> rdf:type owl:Ontology .
:hasChild rdf:type owl:ObjectProperty ;
rdfs:subPropertyOf :hasDescendant .
:hasDaughter rdf:type owl:ObjectProperty ;
rdfs:subPropertyOf :hasChild ;
owl:propertyDisjointWith :hasSon .
:hasDescendant rdf:type owl:ObjectProperty .
:hasSon rdf:type owl:ObjectProperty ;
rdfs:subPropertyOf :hasChild .
:Person rdf:type owl:Class .
:Bob rdf:type owl:NamedIndividual , :Person ;
:hasDaughter :Mary ;
:hasSon :John .
:LittleBoy rdf:type owl:NamedIndividual , :Person .
:LittleGirl rdf:type owl:NamedIndividual , :Person .
:John rdf:type owl:NamedIndividual , :Person ;
:hasSon :LittleBoy .
:Mary rdf:type owl:NamedIndividual , :Person ;
:hasDaughter :LittleGirl .
I want to get all of a Bob's descendants or Bob's child by a Sparql query,
How do I write this SPARQL statement?
Thanks for help.

querying child data-properties on RDF-store

I have, in my ontology, an entity named "person" that has a class child named "member". Some like this (indenting for indicate the hierarchy),
person
member
Also, I have some attributes (dataProperty), associated with "person", and another attributes associated with "member". Specifically, that attributes could be phone numbers. I propose a hierarchy of attributes in this way,
phone (domain: person)
office-phone (domain: member)
office-phone-1 (domain: member)
office-phone-2 (domain: member)
personal-phone (domain: person)
I'm doing the following,
SELECT ?s ?attr ?data
WHERE
{
value ?attr {:phone} .
?s rdf:type :member .
?s ?attr ?data .
}
to get all phone-numbers,
instance-member :phone "value-of-personal-phone"
instance-member :phone "value-of-office-phone-1"
instance-member :phone "value-of-office-phone-2"
but,
how could I ONLY to get the two office-phone WITHOUT USE the specific attribute ":office-phone"?? Some owl: restriction or definition??
Thanks!
First, you have to use the property hierarchy in your data, otherwise, this can't work (it would be good if you provide proper sample data next time...):
#prefix : <http://example.org/> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema/> .
:officePhone rdfs:subPropertyOf :phone .
:officePhone1 rdfs:subPropertyOf :officePhone .
:officePhone2 rdfs:subPropertyOf :officePhone .
:personalPhone rdfs:subPropertyOf :phone .
:instance-member rdf:type :member .
:instance-member :personalPhone "value-of-personal-phone" .
:instance-member :officePhone1 "value-of-office-phone-1" .
:instance-member :officePhone2 "value-of-office-phone-2" .
Regarding the querying, there are at least two options:
1) The triple store supports reasoning, RDFS would be enough in your example - then your query would be sufficient.
2) You rewrite your query such that the property hierarchy is taken into account using SPARQL 1.1 property paths:
prefix : <http://example.org/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema/>
SELECT ?s ?attr ?data
WHERE
{
values ?p {:officePhone}
?s rdf:type :member .
?attr rdfs:subPropertyOf* ?p .
?s ?attr ?data .
}
Result:
----------------------------------------------------------------
| s | attr | data |
================================================================
| :instance-member | :officePhone1 | "value-of-office-phone-1" |
| :instance-member | :officePhone2 | "value-of-office-phone-2" |
----------------------------------------------------------------
...I got it in a similar way, showing the superproperty, restrincting the domain and including a distinct...
SELECT distinct ?s ?attr_father ?data
WHERE
{
values ?attr_father {:phone} .
?s rdf:type :member .
?attr rdfs:subPropertyOf* ?attr_father .
?attr rdfs:domain :member .
?s ?attr ?data .
}
In this way, we get,
instance-member :phone "value-of-office-phone-1" .
instance-member :phone "value-of-office-phone-2" .
Regards!

SPARQL - Query based on some property

I want to get all the pizza names which has cheese toppings but the result shows (_:b0) which is kind of an owl restriction following is my query
PREFIX pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#>
SELECT ?X WHERE {
?X rdfs:subClassOf* [
owl:onProperty pizza:hasTopping ;
owl:someValuesFrom pizza:CheeseTopping
]
}
using Pizza ontology from stanford
This works (Without reasoning enabled)
PREFIX pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#>
SELECT ?X ?topping WHERE {
?X rdfs:subClassOf ?Y .
?Y owl:someValuesFrom ?topping .
?topping rdfs:subClassOf* pizza:CheeseTopping
}
ORDER BY ?X
Some are listed more than once as they could contain more than one CheeseTopping. To remove duplicates:
PREFIX pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#>
SELECT DISTINCT ?X WHERE {
?X rdfs:subClassOf ?Y .
?Y owl:someValuesFrom ?topping .
?topping rdfs:subClassOf* pizza:CheeseTopping
}
ORDER BY ?X
This works if you enable a reasoner:
PREFIX pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#>
SELECT DISTINCT ?X WHERE {
?X rdfs:subClassOf pizza:CheeseyPizza
}
Ref:
Used the pizza ontology from here: http://protege.stanford.edu/ontologies/pizza/pizza.owl
That query works but is really complex and might be incomplete because some pizzas use complex OWL constructs:
PREFIX pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#>
SELECT DISTINCT ?pizza WHERE {
{
?pizza rdfs:subClassOf* pizza:Pizza .
?pizza owl:equivalentClass|rdfs:subClassOf [
rdf:type owl:Restriction ;
owl:onProperty pizza:hasTopping ;
owl:someValuesFrom/rdfs:subClassOf* pizza:CheeseTopping
]
} UNION {
?pizza owl:equivalentClass _:b0 .
_:b0 rdf:type owl:Class ;
owl:intersectionOf _:b1 .
_:b1 (rdf:rest)*/rdf:first ?otherClass.
?otherClass rdf:type owl:Restriction ;
owl:onProperty pizza:hasTopping ;
owl:someValuesFrom/rdfs:subClassOf* pizza:CheeseTopping
}
}

sparql query: get several values from a List

My query returns result dependent on which one of two sparql OPTIONS clauses come first for a List of Images. Although using Jena ARQ is not an option at this point, and I'd like to solve this with a pure SPARQL query, still I'd like to know how it could be solved with Jena as well.
My data presentation is attached below, the data may contain a list of images. My image representation is also below. I'm attaching my query as well.
The sprql query has two variables urlX, and urlY declared in the 2 OPTIONS blocks, if a List of images exists. Depending on which of the OPTIONS comes first, I get the value for that one variable, while the other one doesn't get reached. It seems the issue has to do with using OPTIONS clause. I'm not sure what else I can try instead, I'm far from being an expert on sparql queries. I want the query to do the following: if a collection of images is present, I want to see if both image sizes (dc:conformsTo) are present and get both urlX and urlY values, or get the ones that exist. Much appreciate your time.
My data representation:
#prefix dc: <http://purl.org/dc/terms/> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix lews: <http://lews.com/content/> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
lews:26331340 lews:name "the Human Good Luck Charm is Back"^^xsd:token ;
dc:created "2014-10-20T17:14:55.357-07:00"^^xsd:dateTime ;
dc:identifier "26331340"^^xsd:int ;
dc:modified "2016-08-04T13:43:00.897-07:00"^^xsd:dateTime ;
dc:title "the Human Good Luck Charm is Back" ;
dc:hasPart <http://lews.com/content/26331340#Images> ;
dc:abstract "As the World Series gets underway..." ;
dc:description "The super fan who rooted for the Royals is back to boost morale." ;
dc:subject "hoping for a World Series victory".
<http://lews.com/content/26331340#Images> dc:identifier "Images"^^xsd:token ;
rdf:first lews:26331375 ;
rdf:rest _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331376 ;
rdf:li <http://lews.com/content/26331340#Images> , _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331376 , _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331377 , _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331378 , _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331379 , _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331380 ;
a rdf:List .
_:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331376 rdf:first lews:26331376 ;
rdf:rest _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331377 .
_:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331377 rdf:first lews:26331377 ;
rdf:rest _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331378 .
_:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331378 rdf:first lews:26331378 ;
rdf:rest _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331379 .
_:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331379 rdf:first lews:26331379 ;
rdf:rest _:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331380 .
_:genid-15e530b0195547d9ac3f8e5e6785a747-x26331340Images26331380 rdf:first lews:26331380 ;
rdf:rest rdf:nil .
My image representation:
#prefix dc: <http://purl.org/dc/terms/> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix lews: <http://abcnews.com/content/> .
#prefix mrss: <http://search.yahoo.com/mrss/> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
lews:26331376 lews:name "141020_wn_donvan0_704x396.jpg"^^xsd:token ;
lews:section "wnt"^^xsd:token ;
lews:type "Image"^^xsd:token ;
dc:conformsTo "704x396"^^xsd:token ;
dc:created "2014-10-20T17:15:09.637-07:00"^^xsd:dateTime ;
dc:hasFormat <http://lews.go.com/images/WNT/141020_wn_donvan0_704x396.jpg> ;
dc:identifier "26331376"^^xsd:int ;
dc:isPartOf <http://lews.go.com/WNT> ;
dc:modified "2014-10-20T17:15:09.947-07:00"^^xsd:dateTime ;
dc:type "StillImage"^^xsd:token ;
mrss:height "396"^^xsd:int ;
mrss:width "704"^^xsd:int ;
xsd:date "2014-10-20"^^xsd:date ;
xsd:gMonthDay "--10-20"^^xsd:gMonthDay ;
xsd:gYear "2014"^^xsd:gYear ;
xsd:gYearMonth "2014-10"^^xsd:gYearMonth .
My query:
PREFIX dc: <http://purl.org/dc/terms/>
PREFIX mrss: <http://search.yahoo.com/mrss/>
PREFIX search: <http://www.openrdf.org/contrib/lucenesail#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX lews: <http://abcnews.com/content/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?id ?title ?description ?urlX ?urlY ?section ?imgName
?subject dc:identifier ?id.
OPTIONAL {?subject dc:title ?title.}
OPTIONAL {?subject dc:description ?description.}
OPTIONAL {?subject dc:isPartOf ?section.}
OPTIONAL {
?subject dc:hasPart ?imageCol.
?imageCol dc:identifier "Images"^^xsd:token.
OPTIONAL{
?imageCol rdf:li ?bnode.
?bnode rdf:first ?image.
?image lews:name ?imgName;
dc:conformsTo "4x3";
dc:hasFormat ?urlX.
}
OPTIONAL{
?imageCol rdf:li ?bnode.
?bnode rdf:first ?image.
?image lews:name ?imgName;
dc:conformsTo "16x9";
dc:hasFormat ?urlY.
}
}
}
LIMIT ${limit}
If I understood correctly what it is you want, you just need to group the optionals differently:
PREFIX dc: <http://purl.org/dc/terms/>
PREFIX mrss: <http://search.yahoo.com/mrss/>
PREFIX search: <http://www.openrdf.org/contrib/lucenesail#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX lews: <http://abcnews.com/content/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?id ?title ?description ?urlX ?urlY ?section ?imgName {
?subject dc:identifier ?id.
OPTIONAL { ?subject dc:title ?title. }
OPTIONAL { ?subject dc:description ?description. }
OPTIONAL { ?subject dc:isPartOf ?section. }
OPTIONAL {
?subject dc:hasPart ?imageCol.
?imageCol dc:identifier "Images"^^xsd:token.
OPTIONAL {
?imageCol rdf:li ?bnode.
?bnode rdf:first ?image.
?image lews:name ?imgName;
# Here we optionally bind ?urlX and/or ?urlY
OPTIONAL {
?image dc:conformsTo "4x3";
dc:hasFormat ?urlX.
}
OPTIONAL {
?image dc:conformsTo "16x9";
dc:hasFormat ?urlY.
}
}
}
}

How to do a COUNT in SPARQL

Given this very simple model:
#prefix : <http://example.org/tags#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
:tag rdf:type rdf:Property .
:item1
rdf:type owl:Thing ;
:tag "a"^^xsd:string .
:item2
rdf:type owl:Thing ;
:tag "a"^^xsd:string , "b"^^xsd:string .
:item3
rdf:type owl:Thing ;
:tag "a"^^xsd:string , "b"^^xsd:string , "c"^^xsd:string .
I am trying to get a list of the items and the count of tags that each has:
item tagCount
===== ========
item1 1
item2 2
item3 3
Here is my query:
SELECT ?item (count(?tag) as ?tagcount)
WHERE {
?item :tag ?tag
}
However it is returning:
item tagCount
===== ========
6
From what I have read, this should work. I am using Jena 2.6.4
I haven't tried this, but try adding GROUP BY ?item to the end of the query. I think without GROUP BY it just counts the total number of rows.
For the binding to appear in the results you do need to use the group by keyword so this becomes
SELECT ?item (count(?tag) as ?tagcount)
WHERE {
?item :tag ?tag
} group by ?item
If you want to count something in the middle of the query you would do the following, note how you must put the inner select query into its own block {}
SELECT * {
?item a owl:Thing .
{
SELECT ?item (count(?tag) as ?tagcount)
WHERE {
?item :tag ?tag
} group by ?item
}
}
The sub-select by #user2316243 is unnecessary, therefore the following query is equivalent:
SELECT ?item (count(?tag) as ?tagcount)
WHERE {
?item a owl:Thing .
?item :tag ?tag .
} GROUP BY ?item