- From: Aidan Hogan <aidhog@gmail.com>
- Date: Mon, 9 Aug 2021 02:46:04 -0400
- To: joylix <joylix@126.com>
- Cc: "public-sparql-dev@w3.org" <public-sparql-dev@w3.org>
Oops! The name of the function is simply "bound", not "isBound". PREFIX : <http://example.org/#> SELECT ?student ?test ?grade WHERE { ?student :tookTest ?test . ?test :score ?score . ?range a :range . ?range :grade ?grade . { ?range :maxInclusive ?maxInc } UNION { ?range :maxExclusive ?maxExc } { ?range :minInclusive ?minInc } UNION { ?range :minExclusive ?minExc } FILTER( (!bound(?minInc) || (?score >= ?minInc)) && (!bound(?minExc) || (?score > ?minExc)) && (!bound(?maxInc) || (?score <= ?maxInc)) && (!bound(?maxExc) || (?score < ?maxExc)) ) } This time I tested it. :) Regarding other ways to specify the rule, there have been quite a lot of proposals for this on the Semantic Web: Notation3: https://www.w3.org/TeamSubmission/n3/ SWRL: http://www.daml.org/rules/proposal/ SPIN: https://spinrdf.org/ RIF: https://www.w3.org/TR/rif-overview/ SHACL Rules (as you saw) As well as SPARQL. If you wanted to turn the query into a rule that infers new RDF data, you could use construct: PREFIX : <http://example.org/#> CONSTRUCT { ?test :grade ?grade . } WHERE { ?student :tookTest ?test . ?test :score ?score . ?range a :range . ?range :grade ?grade . { ?range :maxInclusive ?maxInc } UNION { ?range :maxExclusive ?maxExc } { ?range :minInclusive ?minInc } UNION { ?range :minExclusive ?minExc } FILTER( (!bound(?minInc) || (?score >= ?minInc)) && (!bound(?minExc) || (?score > ?minExc)) && (!bound(?maxInc) || (?score <= ?maxInc)) && (!bound(?maxExc) || (?score < ?maxExc)) ) } You could also define similar logic using ontologies rather than rules. OWL 2 has datatype facets that could be used (with some additional definitions) to infer the grades for your example: https://www.w3.org/TR/owl2-quick-reference/#Built-in_Datatypes_and_Facets Best, Aidan On 2021-08-08 21:14, joylix wrote: > Hi, Aidan, The first Sparql statement about integer types works > perfectly! It's amazing. > The operation on the decimal query appears to have failed: > / ---------------------------------------------------/ > > /@base <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#> ./ > /@prefix : <http://example.org/#> ./ > /:range1 a :range;/ > / :grade "A";/ > / :minInclusive 90.0;/ > / :maxInclusive 100.0 ./ > /:range2 a :range;/ > / :grade "B";/ > / :minInclusive 75.0;/ > / :maxExclusive 90.0 ./ > /:range3 a :range;/ > / :grade "C";/ > / :minInclusive 60.0;/ > / :maxExclusive 75.0 ./ > > /:range4 a :range;/ > / :grade "D";/ > / :minInclusive 0;/ > / :maxExclusive 60.0 ./ > /:Bob a :Student;/ > / :tookTest :Test0,:Test1,:Test2, :Test3 ./ > > /:Test0 :score 91.2 ./ > /:Test1 :score 75.5 ./ > /:Test2 :score 73.2 ./ > /:Test3 :score 59.5 ./ > /---------------------------------------------------/ > / > / > > But it gave me a clear direction and a great idea. > I'm also trying to do this with shACL, which might be simpler. But I'm > not familiar with SH :rule yet, I don't know if that's possible: > https://w3c.github.io/shacl/shacl-af/#rules > <https://w3c.github.io/shacl/shacl-af/#rules> > Another approach I think might be useful: > https://henrietteharmse.com/category/inferencing/ > <https://henrietteharmse.com/category/inferencing/> > > Thank you for your prompt reply and kind help. > > Kind regards, > Joylix > > > > > > > > > At 2021-08-09 08:39:38, "Aidan Hogan" <aidhog@gmail.com> wrote: >>Hi Joylix, >> >>I think that the solution gets a bit more difficult, but if you are >>working with integers, you could try to query the values like this: >> >>PREFIX : <http://example.org/#> >>SELECT ?student ?test ?grade >>WHERE { >> ?student :tookTest ?test . >> ?test :score ?score . >> ?range a :range . >> ?range :grade ?grade . >> { ?range :maxInclusive ?max } >> UNION >> { ?range :maxExclusive ?maxExc . BIND(?maxExc - 1 AS ?max) } >> { ?range :minInclusive ?min } >> UNION >> { ?range :minExclusive ?minExc . BIND(?minExc + 1 AS ?min) } >> FILTER(?score >= ?min && ?score <= ?max) >>} >> >>Another option (that would work also for non-integer values) would be to >>expand the FILTER. >> >>PREFIX : <http://example.org/#> >>SELECT ?student ?test ?grade >>WHERE { >> ?student :tookTest ?test . >> ?test :score ?score . >> ?range a :range . >> ?range :grade ?grade . >> { ?range :maxInclusive ?maxInc } >> UNION >> { ?range :maxExclusive ?maxExc } >> { ?range :minInclusive ?minInc } >> UNION >> { ?range :minExclusive ?minExc } >> FILTER( >> (!isBound(?minInc) || (?score >= ?minInc)) && >> (!isBound(?minExc) || (?score > ?minExc)) && >> (!isBound(?maxInc) || (?score <= ?maxInc)) && >> (!isBound(?maxExc) || (?score < ?maxExc)) >> ) >>} >> >>Best, >>Aidan >> >>On 2021-08-08 11:42, joylix wrote: >>> Dear Aidan, Thank you very much for the solution. >>> Also, in this case, I still don't know how to deal with the limit of >>> boundary. >>> If I need to consider the inclusive and exclusive values of limit as: >>> :range1 a :range ; >>> :grade "A" ; >>> :minInclusive 90 ; >>> :maxInclusive 100. >>> :range2 a :range ; >>> :grade "B" ; >>> :minInclusive 75 ; >>> :maxExclusive 90 . >>> :range3 a :range ; >>> :grade "C" ; >>> :minInclusive 60 ; >>> :maxExclusive 75 . >>> :range4 a :range ; >>> :grade "D" ; >>> :minInclusive 0 ; >>> :maxExclusive 60 . >>> How can I write logical operators in A SPARQL statement based on >>> different predicates (inclusive or exclusive)? >>> FILTER(?score >= ?lower && ?score <= ?upper) >>> So this part of the SPARQ statement ">=" is sometimes ">", "<=" can >>> also be "<". Is there an easy way to deal with this situation? >>> I thought it might be easy to implement this example with shacl, but I >>> didn't know how. >>> Thanks again for your reply and help. >>> >>> Kind regards, >>> Joylix >>> >>> >>> >>> >>> >>> At 2021-08-07 06:11:22, "Aidan Hogan" <aidhog@gmail.com> wrote: >>>>Hi Joylix, >>>> >>>>You could try something like: >>>> >>>>PREFIX : <http://example.org/#> >>>>SELECT ?student ?test ?grade >>>>WHERE { >>>> ?student :tookTest ?test . >>>> ?test :score ?score . >>>> ?range a :range . >>>> ?range :grade ?grade . >>>> ?range :lowerLimit ?lower . >>>> ?range :upperLimit ?upper . >>>> FILTER(?score >= ?lower && ?score <= ?upper) >>>>} >>>> >>>>Not tested, but I think this should work. >>>> >>>>Best, >>>>Aidan >>>> >>>>P.S., if you want to express rules over RDF (in RDF) and like to use >>>>SPARQL for that, you might be interested in SPIN: >>>> >>>>https://www.w3.org/Submission/spin-sparql/ >>>> >>>> >>>>On 2021-08-06 4:23, joylix wrote: >>>>> Dear all, I have some data on students' test scores as follows: >>>>> >>>>> >>>>> /@prefix : <http://example.org/#> ./ >>>>> >>>>> /:Bob a :Student;/ >>>>> >>>>> / :tookTest :Test0,:Test1,:Test2 ,:Test3 ./ >>>>> >>>>> /:Test0 :score 90 ./ >>>>> >>>>> /:Test1 :score 81 ./ >>>>> >>>>> /:Test2 :score 62 ./ >>>>> >>>>> /:Test3 :score 32 ./ >>>>> >>>>> The rules for grading based on scores are as follows: >>>>> >>>>> [90-100] --> A >>>>> >>>>> [75-90) --> B >>>>> >>>>> [60-75) --> C >>>>> >>>>> [0-60) --> D >>>>> >>>>> So I used the following SPARQL query to get the grade of the student's Test: >>>>> >>>>> >>>>> /prefix : <http://example.org/#>/ >>>>> >>>>> /select ?student ?test ?grade/ >>>>> >>>>> / WHERE { / >>>>> >>>>> / ?student :tookTest ?test ./ >>>>> >>>>> / ?test :score ?score ./ >>>>> >>>>> / BIND ( IF ( ?score >= 90 , "A", IF ( ?score>=75, "B", IF ( >>>>> ?score>=60, "C", "D" ) ) ) AS ?grade )/ >>>>> >>>>> / }/ >>>>> >>>>> And I got the right result as such: >>>>> >>>>> >>>>> student, test, grade >>>>> >>>>> http://example.org/#Bob, http://example.org/#Test3, D >>>>> >>>>> http://example.org/#Bob, http://example.org/#Test2, C >>>>> >>>>> http://example.org/#Bob, http://example.org/#Test1, B >>>>> >>>>> http://example.org/#Bob, http://example.org/#Test0, A >>>>> >>>>> Now my question is how to store this rule data in RDF (along with >>>>> the score) rather than in SPARQL, so that the rule data can be defined >>>>> and modified by the user, The server side reads the rule data to >>>>> generate the appropriate SPARQL query. >>>>> >>>>> My initial thoughts are as follows: >>>>> >>>>> >>>>> / :range1 a :range ;/ >>>>> >>>>> / :grade "A" ;/ >>>>> >>>>> / :lowerLimit 90 ;/ >>>>> >>>>> / :upperLimit 100./ >>>>> >>>>> /:range2 a :range ;/ >>>>> >>>>> / :grade "B" ;/ >>>>> >>>>> / :lowerLimit 75 ;/ >>>>> >>>>> / :upperLimit 89 ./ >>>>> >>>>> /:range3 a :range ;/ >>>>> >>>>> / :grade "C" ;/ >>>>> >>>>> / :lowerLimit 60 ;/ >>>>> >>>>> / :upperLimit 74 ./ >>>>> >>>>> /:range4 a :range ;/ >>>>> >>>>> / :grade "D" ;/ >>>>> >>>>> / :lowerLimit 0 ;/ >>>>> >>>>> / :upperLimit 59 ./ >>>>> >>>>> /:rule1 :hasRange :range1,:range2, :range3, :range4 ./ >>>>> >>>>> >>>>> But how do I now write the right SPARQL to read the rule and complete >>>>> the grade transformation? >>>>> >>>>> And how to handle with inclusive and exclusive of the boundary of limit? >>>>> Thank you for any suggestion. >>>>> >>>>> Kind regards, >>>>> Joylix >>>>> >>>>> >>>>> >>>>> >>> >>> >>> > > >
Received on Monday, 9 August 2021 06:47:19 UTC