简体   繁体   中英

SPARQL query for individuals with same properties

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, ie 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, ie 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 |
--------------------

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM