Filtering SPARQL Results - sparql

I have following example triples
r1 -> property -> resourceA
r1 -> property -> resourceB
r1 -> property -> resourceC
resourceA -> name -> word1
resourceB -> name -> word2
resourceC -> name -> word4
r2 -> property -> resourceD
r2 -> property -> resourceE
r2 -> property -> resourceF
resourceD -> name -> word1
resourceE -> name -> word2
resourceF -> name -> word3
r3 -> property -> resourceG
r3 -> property -> resourceH
r3 -> property -> resourceI
resourceG -> name -> word5
resourceH -> name -> word6
resourceI -> name -> word7
As parameter i use word1 and word2. I want to get all words incl. word1 and word2, which occurrence with the word1 and word2 together.
The result from this example must be:
word1
word2
word3
word4
I have really no idea, how to make this :(

Assuming the predicate name is the same for all words and there are no other triples with the name predicate:
SELECT DISTINCT ?w {
?s <name> ?w
}
ORDER BY ?w
Edited after the question was edited:
SELECT DISTINCT ?w { # select each word only once
# match three properties under the same resource
?r <property> ?p1, ?p2, ?p3.
# two of the properties must have names "word1" and "word2"
?p1 <name> "word1" .
?p2 <name> "word2" .
# third property name may be anything, including "word1" and "word2"
?p3 <name> ?w .
}
ORDER BY ?w # return words in sorted order

Related

How can I use CONCAT with results from GROUP_CONCAT in SPARQL?

I have trouble with a SPARQL query. I have two graphs: Discipline and Professor. The graph Discipline contains different disciplines and is linked with the Professor thanks to his id. For example, I have:
<http://www.rdcproject.com/graph/disciplines> {
<http://www.rdfproject.com/77803>
a <http://www.rdfproject.com/Discipline> ;
<http://www.rdfproject.com/cfu>
"6" ;
<http://www.rdfproject.com/disciplineAbbreviation>
"SE" ;
<http://www.rdfproject.com/disciplinename>
"Software Engineering" ;
<http://www.rdfproject.com/hasCourseof>
<http://www.rdfproject.com/8028> ;
<http://www.rdfproject.com/idDiscipline>
"77803" ;
<http://www.rdfproject.com/isTaughtBy>
<http://www.rdfproject.com/0009004> ,
<http://www.rdfproject.com/0004003> ;
<http://www.rdfproject.com/obligatory>
"false" ;
<http://www.rdfproject.com/semester>
"1" ;
<http://www.rdfproject.com/totalhours>
"50" ;
<http://www.rdfproject.com/weekhours>
"5" ;
<http://www.rdfproject.com/year>
"1" .
}
This course is taught by two professors:
<http://www.rdfproject.com/0009004>
a <http://www.rdfproject.com/Teacher> ;
<http://www.rdfproject.com/firstName>
"Koby" ;
<http://www.rdfproject.com/idProfessor>
"0009004" ;
<http://www.rdfproject.com/lastName>
"Bryant" ;
<http://www.rdfproject.com/role>
"contratto" .
<http://www.rdfproject.com/0004003>
a <http://www.rdfproject.com/Teacher> ;
<http://www.rdfproject.com/firstName>
"Lebron" ;
<http://www.rdfproject.com/idProfessor>
"0004003" ;
<http://www.rdfproject.com/lastName>
"James" ;
<http://www.rdfproject.com/role>
"associato" .
Now I want all professors for all disciplines. I have created this query:
PREFIX uni: <http://www.rdfproject.com/>
PREFIX un: <http://www.w3.org/2007/ont/unit#>
SELECT ?idDiscipline ?disciplineName
(CONCAT('[',GROUP_CONCAT(?idProf;separator=","),', ',GROUP_CONCAT(?firstName;separator=","),', ',GROUP_CONCAT(?lastName;separator=","),', ',GROUP_CONCAT(?role;separator=","),']') as ?professors)
FROM <http://www.rdcproject.com/graph/disciplines>
FROM <http://www.rdcproject.com/graph/professor>
WHERE
{
{
?x a uni:Discipline;
uni:disciplinename ?disciplineName;
uni:idDiscipline ?idDiscipline;
uni:disciplineAbbreviation ?sigleDiscipline;
uni:cfu ?cfu;
uni:hasCourseof ?hasCourseof;
uni:obligatory ?obligatory;
uni:semester ?semester;
uni:totalhours ?totalhours;
uni:weekhours ?weekhours;
uni:year ?year;
uni:isTaughtBy ?isTaughtBy.
?isTaughtBy a uni:Teacher;
uni:idProfessor ?idProf;
uni:firstName ?firstName;
uni:role ?role;
uni:lastName ?lastName.
}
}
GROUP BY ?idDiscipline ?disciplineName
This query works fine if a discipline contains only one professor, but in this case the result is:
ID -> 77803"
NAME -> "Software Engineering"
PROFESSOR -> "[0009004,0004003, Kobe,Lebron, Bryant ,James,
contract,contract]"
How can I get this result?
ID -> 77803"
NAME -> "Software Engineering"
PROFESSOR -> "[0009004, Kobe, Bryant, contract]
[0004003, Lebron,James, contract]
Thanks
EDIT:
Thanks to #AKSW
My new Query is:
PREFIX uni: <http://www.rdfproject.com/>
PREFIX un: <http://www.w3.org/2007/ont/unit#>
SELECT ?idDiscipline ?sigleDiscipline ?disciplineName ?cfu ?hasCourseof ?obligatory ?semester ?totalhours ?weekhours ?year
(GROUP_CONCAT(DISTINCT ?prof_str;separator=",") AS ?Professor)
FROM <http://www.rdcproject.com/graph/disciplines>
FROM <http://www.rdcproject.com/graph/professor>
WHERE
{
{
?x a uni:Discipline;
uni:disciplinename ?disciplineName;
uni:idDiscipline ?idDiscipline;
uni:disciplineAbbreviation ?sigleDiscipline;
uni:cfu ?cfu;
uni:hasCourseof ?hasCourseof;
uni:obligatory ?obligatory;
uni:semester ?semester;
uni:totalhours ?totalhours;
uni:weekhours ?weekhours;
uni:year ?year;
uni:isTaughtBy ?isTaughtBy.
?isTaughtBy a uni:Teacher;
uni:idProfessor ?idProf;
uni:firstName ?firstName;
uni:lastName ?lastName;
uni:role ?role.
}
BIND(CONCAT('[',?idProf,',',?firstName,',',?lastName,',',?role,']') AS ?prof_str)
}
GROUP BY ?idDiscipline ?sigleDiscipline ?disciplineName ?cfu ?hasCourseof ?obligatory ?semester ?totalhours ?weekhours ?year

Sequence Http.get in Elm

Below I have a button that attempts to load remote content ...
import Post exposing (Post)
import Html exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as Decode
type alias Model =
{ posts : List Post }
type Msg
= Search String
| PostsReceived (Result Http.Error (List Post))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search s ->
let
cmd =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ s)
|> Http.send PostsReceived
in
( model, cmd )
PostsReceived (Ok posts) ->
{ model | posts = posts }
! []
PostsReceived (Err error) ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
button
[ onClick (Search "amelia") ]
[ text "Read posts by Amelia" ]
This is a valid Elm program, only there's one little problem: The API doesn't allow me to search by string. This is not allowed
/posts?author=amelia => Malformed Request Error
However, this is allowed
/posts?author=2 => [ {...}, {...}, ... ]
So I must first fetch an author to get his/her id, and then I can fetch posts using the author's id...
/author?name=amelia => { id: 2, name: "amelia", ... }
/posts?author=2
How can I sequence one request after the next? Ideally I'd like to cache the authors somewhere in the model so we're only requesting ones that we haven't seen before.
You can use Task.andThen to chain two tasks together. Assuming that the /posts response includes the author ID, you can then add that author ID into you model when you handle the response.
Search s ->
let
getAuthor =
Author.decode
|> Http.get ("/author?name=" ++ s)
|> Http.toTask
getPosts author =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ author.id)
|> Http.toTask
cmd =
getAuthor
|> Task.andThen getPosts
|> Task.attempt PostsReceived
in
( model, cmd )
I've got this compiling at https://ellie-app.com/DBJc6Kn3G6a1 if that helps
You can chain together tasks using Task.andThen. You'll first have to convert the web requests to tasks using Http.toTask:
postsByAuthorName : String -> Cmd Msg
postsByAuthorName name =
Http.get ("/author?name=" ++ name) (Decode.field "id" Decode.int)
|> Http.toTask
|> Task.andThen (\id ->
Http.get ("/posts?author=" ++ toString id) (Decode.list decodePost)
|> Http.toTask)
|> Task.attempt PostsReceived
A a dictionary and a couple more Msg options should do it.
You'll have to write the decoder for the Author response, but other than that this should work
type alias Model =
{ posts : List Post
, authors : Dict String Int }
type Msg
= Search String
| SearchAuthor String
| AuthorReceived (Result Http.Error Int String)
| PostsReceived (Result Http.Error (List Post))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search author ->
case (Dict.get author model.authors) of
Nothing ->
let
cmd =
(Decode.list Post.decode)
|> Http.get ("/author?name=" ++ author)
|> Http.send AuthorReceived
in
(model,cmd)
Just num ->
let
cmd =
(Decode.list Author.decode)
|> Http.get ("/posts?author=" ++ num)
|> Http.send PostsReceived
in
( model, cmd )
AuthorReceived (Ok number name) ->
let
updatedAuthors = Dict.inster name number model.authors
cmd =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ number)
|> Http.send PostsReceived
in
{model | authors = updatedAuthors } ! [cmd]
AuthorReceived (Err error) ->
(mode, Cmd.none )
PostsReceived (Ok posts) ->
{ model | posts = posts }
! []
PostsReceived (Err error) ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
button
[ onClick (Search "amelia") ]
[ text "Read posts by Amelia" ]

Elm 0.17: Task.perform and Maybe

I'm hoping someone could help me with Task.perform as I don't really understand how to handle a Maybe response - and the docs aren't making things clearer for me.
In my model I have results which Maybe a list of items or Nothing.
-- model
type alias Item =
{ name : String}
type alias Model =
{ results : Maybe (List Item) }
model = {
results = Nothing
}
I perform a Task and decode it like so:
-- Task
fetch : String -> Cmd Msg
fetch query =
let url =
"https://some_url" ++ query
in
Task.perform FetchFail FetchSuccess (Http.get decode url)
-- decoder
decoder: Json.Decoder (List Item)
decoder =
Json.at ["data"] (Json.list nestedListDecoder)
-- nestedListDecoder
nestedListDecoder : Json.Decoder Item
nestedListDecoder =
Json.object1 Item
("name" := Json.string)
I then handle the response in update:
-- update
type Msg
= FetchSuccess (Maybe (List Item))
| FetchFail Http.Error
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
FetchSuccess results ->
case results of
Nothing ->
( { model | results = Nothing}, Cmd.none)
Just res ->
( { model | results = res }, Cmd.none)
FetchFail err ->
-- ... handle error
And cater for the Maybe in the view:
-- view
result : Item -> Html Msg
result item =
li [] [ text item.name ]
view : Model -> Html Msg
view model =
ul [ ] (List.map result (Maybe.withDefault [] model.results))
I am getting this error when dealing with Maybe of results.
198| Task.perform FetchFail FetchSuccess (Http.get repos url)
^^^^^^^^^^^^^^^^^^
Function `perform` is expecting the 3rd argument to be:
Task Http.Error (Maybe (List Repo))
But it is:
Task Http.Error (List Repo)
Can anyone advise where else I need to cater for the Maybe ?
A simple tweak to your decoder should fix it. The decoder just needs to use Json.Decode.maybe:
decoder: Json.Decoder (Maybe (List Item))
decoder =
Json.maybe <| Json.at ["data"] (Json.list nestedListDecoder)

Sparql : To display the name in the last of the sorted list if its firstname is empty

In my code i have bound first,middle and lastname into a single name and i sort it using name.
I want to sort the bound names in ascending and the name which doesnt have 1st name should be displayed at the end of the sorted list.
Please share your ideas for solving this issue.
My code:
bind ( COALESCE(?firstName, "") As ?firstName1).
bind ( COALESCE(?middleName, "") As ?middleName1).
bind ( COALESCE(?lastName, "") As ?lastName1).
bind (concat(str(?firstName1),str(?middleName1),str(?lastName1)) as ?name).
}
order by (regex(" " ,?firstName1) && bound (?name))
In the output though the name whose 1st name is empty appears in the end yet the rest of the names are not sorted in asc order.
As I understand it, you want to sort the names in lexicographic order (order by first name, then by middle name, then by last name) with one exception: instead of putting entries with no first name at the beginning, you want to put them at the end. If this is correct, you want an ordering condition like:
ORDER BY DESC( bound( ?firstName )) ?firstName ?middleName ?lastName
This is some RDF to work with in which :fn, :mn, and :ln stand for for first name, middle name, and last name, respectively:
#prefix : <http://www.example.org/>.
:aaa :fn "A"; :mn "A"; :ln "A".
:aab :fn "A"; :mn "A"; :ln "B".
:aba :fn "A"; :mn "B"; :ln "A".
:_aa :mn "A"; :ln "A".
:_ab :mn "A"; :ln "B".
:_ba :mn "B"; :ln "A".
This SPARQL for the data that binds ?firstName optionally, and orders as I described above:
PREFIX : <http://www.example.org/>
SELECT ?firstName ?middleName ?lastName
WHERE {
?x :mn ?middleName .
?x :ln ?lastName .
OPTIONAL { ?x :fn ?firstName . }
}
ORDER BY DESC( bound( ?firstName )) ?firstName ?middleName ?lastName
Calling the data names.n3 and the query names.sparql, here are the results I get when I run the query on the data with Jena's ARQ:
$ /usr/local/lib/apache-jena-2.10.0/bin/arq --data names.n3 --query names.sparql
-------------------------------------
| firstName | middleName | lastName |
=====================================
| "A" | "A" | "A" |
| "A" | "A" | "B" |
| "A" | "B" | "A" |
| | "A" | "A" |
| | "A" | "B" |
| | "B" | "A" |
-------------------------------------
You can still do the sort this way even if you're projecting ?name and not any of ?firstName, ?middleName, or ?lastName. For instance, the query
PREFIX : <http://www.example.org/>
SELECT ?name
WHERE {
?x :mn ?middleName .
?x :ln ?lastName .
OPTIONAL { ?x :fn ?firstName . }
bind ( concat( str(coalesce(?firstName, "_")), str(?middleName), str(?lastName) ) as ?name).
}
ORDER BY DESC( bound( ?firstName )) ?firstName ?middleName ?lastName
produces
---------
| name |
=========
| "AAA" |
| "AAB" |
| "ABA" |
| "_AA" |
| "_AB" |
| "_BA" |
---------

Dynamic SQL Parameters with Anorm and Scala Play Framework

Is it possible to dynamically create a list for anorm's "on" method?
I have a form with optional inputs and currently I check each Option and create a list with the defined Options and am trying to pass this through to anorm. Currently I get this compilation error
type mismatch; found : List[java.io.Serializable] required: (Any, anorm.ParameterValue[_])
I'm not sure how I would go about creating this list.
Current code :
val onList = List(
'school_id = input.school,
if(input.rooms isDefined) ('rooms -> input.rooms) else "None" ,
if(input.bathrooms isDefined) ('bathrooms -> input.bathrooms) else "None" ,
if(input.houseType isDefined) ('houseType -> input.houseType) else "None" ,
if(input.priceLow isDefined) ('priceLow -> input.priceLow) else "None" ,
if(input.priceHigh isDefined) ('priceHigh -> input.priceHigh) else "None" ,
if(input.utilities isDefined) ('utilities -> input.utilities) else "None"
).filter(_!="None")
SQL("SELECT * FROM Houses WHERE " + whereString).on(onList).as(sqlToHouse *)
I've tried doing this because initially I thought it would be the same as
.on('rooms -> input.rooms, 'bathroom -> input.bathrooms... etc)
EDIT:
Code is now:
val onList = Seq(
('school_id -> input.school),
if(input.rooms isDefined) ('rooms -> input.rooms.get) else None ,
if(input.bathrooms isDefined) ('bathrooms -> input.bathrooms.get) else None ,
if(input.houseType isDefined) ('houseType -> input.houseType.get) else None ,
if(input.priceLow isDefined) ('priceLow -> input.priceLow.get) else None ,
if(input.priceHigh isDefined) ('priceHigh -> input.priceHigh.get) else None ,
if(input.utilities isDefined) ('utilities -> input.utilities.get) else None
).filter(_!=None).asInstanceOf[Seq[(Any,anorm.ParameterValue[_])]]
using SQL command:
SQL("SELECT * FROM Houses WHERE " + whereString).on(onList:_*).as(sqlToHouse *)
Now getting the exception
[ClassCastException: java.lang.Integer cannot be cast to anorm.ParameterValue]
The important thing is that you have to create values of type ParameterValue.
This is normally done using the toParameterValue() function.
One way would be to create a sequence of Options that you flatten:
val onList = Seq(
Some('school_id -> input.school),
input.rooms.map('rooms -> _),
input.bathrooms.map('bathrooms -> _)
).flatten
This sequence can then be mapped to correct values:
SQL(
"SELECT * FROM Houses WHERE " + whereString
).on(
onList.map(v => v._1 -> toParameterValue(v._2)): _*
)
This can be simplified like this:
val onList = Seq(
Some('school_id -> input.school),
input.rooms.map('rooms -> _),
input.bathrooms.map('bathrooms -> _)
).flatMap(_.map(v => v._1 -> toParameterValue(v._2)))
SQL(
"SELECT * FROM Houses WHERE " + whereString
).on(
onList: _*
)
Or maybe the simplest solution would be this:
val onList = Seq(
Some('school_id -> toParameterValue(input.school)),
input.rooms.map('rooms -> toParameterValue(_)),
input.bathrooms.map('bathrooms -> toParameterValue(_))
).flatten
SQL(
"SELECT * FROM Houses WHERE " + whereString
).on(
onList: _*
)
So I ended up just calling on multiple times.
var query = SQL("SELECT * FROM Houses WHERE " + whereString).on('school_id -> input.school)
if(input.rooms isDefined) query= query.on('rooms -> input.rooms.get)
if(input.bathrooms isDefined) query= query.on('bathrooms -> input.bathrooms.get)
if(input.houseType isDefined) query= query.on('houseType -> input.houseType.get)
if(input.priceLow isDefined) query= query.on('priceLow -> input.priceLow.get)
if(input.priceHigh isDefined) query= query.on('priceHigh -> input.priceHigh.get)
if(input.utilities isDefined) query= query.on('utilities -> input.utilities.get)
query.as(sqlToHouse *)
You can have a look at multivalue parameter is next Anorm (coming Play 2.3/master).