OWL - associate transitive child with great-parent - owl

I would like to simplify my SHACL definitions by reversing the relations between shapes, properties and groups.
A typical NodeShape looks like this. Two properties in a group:
<>
a sh:NodeShape ;
sh:property
[
sh:name "Property 1" ;
sh:order 1 ;
sh:group <#Group> ;
] ,
[
sh:name "Property 2" ;
sh:order 2 ;
sh:group <#Group> ;
] ;
.
It becomes a little unwieldy when there are multiple groups and many properties because all of them are tangled in the sh:property list of objects.
What I would like to achieve is to revers the relations a little using OWL rules so that I could type the RDF differently, but retain the equivalence with the above using reasoning.
<>
a sh:NodeShape ;
ex:group <#Group> ;
.
<#Property1>
sh:name "Property 1" ;
sh:order 1 ;
.
<#Property2>
sh:name "Property 2" ;
sh:order 2 ;
.
<#Group>
ex:property <#Property1>, <#Property2>
.
Is there a way to define ex:group and ex:property to infer the triples from first snippet?

Related

Jena Model Validation OntModel

I have created an Ontology which i want use for validating instances, following is the test setup i have, couldnt get validation report one of uid is zero. which is xsd:minExclusive "0"^^xsd:unsignedLong.
Can anyone help m eunderstand best practice to use Jena, i am inteding to sue default model to recieve an input validating aginast ontModel and the merging in TDB backed model.
:Book rdf:type owl:Class ;
rdfs:subClassOf Model .
and data Property
:uid rdf:type owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:domain :Model ;
rdfs:range [ rdf:type rdfs:Datatype ;
owl:onDatatype xsd:unsignedLong ;
owl:withRestrictions ( [ xsd:minExclusive "0"^^xsd:unsignedLong
]
)
] .
Trying to use this ontology to validate data
OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RDFS_INF);
ontModel.read(getClass().getClassLoader().getResource("model.owl").toExternalForm(), NS);
// ontModel.write(System.out);
Reasoner reasoner = ontModel.getReasoner().bindSchema(ontModel);
Model data = createTestData();
//data.write(System.out);
InfModel infModel = ModelFactory.createInfModel(reasoner, data);
ValidityReport report = infModel.validate();
if (report.isValid())
System.out.println("valid");
and in the following code //(index - 1) ensure at least one id of 0
public static Model createTestData() {
Model instances = ModelFactory.createDefaultModel();
instances.setNsPrefix("rdfs", RDFS.getURI());
instances.setNsPrefix("rdf", RDF.getURI());
instances.setNsPrefix("a", NS);
instances.setNsPrefix("", NS + "#");
Property UID_PROPERTY = ResourceFactory.createProperty(NS + "#uid");
IntStream.of(1, 2, 3).forEach(index -> {
Resource r = instances.createResource(NS + "/item/" + (index - 1));
r.addProperty(UID_PROPERTY, ResourceFactory.createTypedLiteral((index - 1)));
});
return instances;
}

using lookup tables to plot a ggplot and table

I'm creating a shiny app and i'm letting the user choose what data that should be displayed in a plot and a table. This choice is done through 3 different input variables that contain 14, 4 and two choices respectivly.
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
selectInput(inputId = "DataSource", label = "Data source", choices =
c("Restoration plots", "all semi natural grasslands")),
selectInput(inputId = "Variabel", label = "Variable", choices =
choicesVariables)),
#choicesVariables definition is omitted here, because it's very long but it
#contains 14 string values
selectInput(inputId = "Factor", label = "Factor", choices = c("Company
type", "Region and type of application", "Approved or not approved
applications", "Age group" ))
),
dashboardBody(
plotOutput("thePlot"),
tableOutput("theTable")
))
This adds up to 73 choices (yes, i know the math doesn't add up there, but some choices are invalid). I would like to do this using a lookup table so a created one with every valid combination of choices like this:
rad1<-c(rep("Company type",20), rep("Region and type of application",20),
rep("Approved or not approved applications", 13), rep("Age group", 20))
rad2<-choicesVariable[c(1:14,1,4,5,9,10,11, 1:14,1,4,5,9,10,11, 1:7,9:14,
1:14,1,4,5,9,10,11)]
rad3<-c(rep("Restoration plots",14),rep("all semi natural grasslands",6),
rep("Restoration plots",14), rep("all semi natural grasslands",6),
rep("Restoration plots",27), rep("all semi natural grasslands",6))
rad4<-1:73
letaLista<-data.frame(rad1,rad2,rad3, rad4)
colnames(letaLista) <- c("Factor", "Variabel", "rest_alla", "id")
Now its easy to use subset to only get the choice that the user made. But how do i use this information to plot the plot and table without using a 73 line long ifelse statment?
I tried to create some sort of multidimensional array that could hold all the tables (and one for the plots) but i couldn't make it work. My experience with these kind of arrays is limited and this might be a simple issue, but any hints would be helpful!
My dataset that is the foundation for the plots and table consists of dataframe with 23 variables, factors and numerical. The plots and tabels are then created using the following code for all 73 combinations
s_A1 <- summarySE(Samlad_info, measurevar="Dist_brukcentrum",
groupvars="Companytype")
s_A1 <- s_A1[2:6,]
p_A1=ggplot(s_A1, aes(x=Companytype,
y=Dist_brukcentrum))+geom_bar(position=position_dodge(), stat="identity") +
geom_errorbar(aes(ymin=Dist_brukcentrum-se,
ymax=Dist_brukcentrum+se),width=.2,position=position_dodge(.9))+
scale_y_continuous(name = "") + scale_x_discrete(name = "")
where summarySE is the following function, burrowed from cookbook for R
summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=TRUE,
conf.interval=.95, .drop=TRUE) {
# New version of length which can handle NA's: if na.rm==T, don't count them
length2 <- function (x, na.rm=FALSE) {
if (na.rm) sum(!is.na(x))
else length(x)
}
# This does the summary. For each group's data frame, return a vector with
# N, mean, and sd
datac <- ddply(data, groupvars, .drop=.drop,
.fun = function(xx, col) {
c(N = length2(xx[[col]], na.rm=na.rm),
mean = mean (xx[[col]], na.rm=na.rm),
sd = sd (xx[[col]], na.rm=na.rm)
)
},
measurevar
)
# Rename the "mean" column
datac <- rename(datac, c("mean" = measurevar))
datac$se <- datac$sd / sqrt(datac$N) # Calculate standard error of the mean
# Confidence interval multiplier for standard error
# Calculate t-statistic for confidence interval:
# e.g., if conf.interval is .95, use .975 (above/below), and use df=N-1
ciMult <- qt(conf.interval/2 + .5, datac$N-1)
datac$ci <- datac$se * ciMult
return(datac)
}
The code in it's entirety is a bit to large but i hope this may clarify what i'm trying to do.
Well, thanks to florian's comment i think i might have found a solution my self. I'll present it here but leave the question open as there is probably far neater ways of doing it.
I rigged up the plots (that was created as lists by ggplot) into a list
plotList <- list(p_A1, p_A2, p_A3...)
tableList <- list(s_A1, s_A2, s_A3...)
I then used subset on my lookup table to get the matching id of the list to select the right plot and table.
output$thePlot <-renderPlot({
plotValue<-subset(letaLista, letaLista$Factor==input$Factor &
letaLista$Variabel== input$Variabel & letaLista$rest_alla==input$DataSource)
plotList[as.integer(plotValue[1,4])]
})
output$theTable <-renderTable({
plotValue<-subset(letaLista, letaLista$Factor==input$Factor &
letaLista$Variabel== input$Variabel & letaLista$rest_alla==input$DataSource)
skriva <- tableList[as.integer(plotValue[4])]
print(skriva)
})

Mongoose - update object from double nested array [duplicate]

This question is closely related to this one and I will consider the advice given with respect to schema design in a NoSQL context, yet I'm curious to understand this:
Actual questions
Suppose you have the following document:
_id : 2 abcd
name : 2 unittest.com
paths : 4
0 : 3
path : 2 home
queries : 4
0 : 3
name : 2 query1
url : 2 www.unittest.com/home?query1
requests: 4
1 : 3
name : 2 query2
url : 2 www.unittest.com/home?query2
requests: 4
Basically, I'd like to know
if it is possible to use MongoDB's positional $ operator (details) multiple times, or put differently, in update scenarios that involve array/document structures with a "degree of nestedness" greater than 1:
{ <update operator>: { "paths.$.queries.$.requests" : value } } (doesn't work)
instead of "only" be able to use $ once for a top-level array and being bound to use explicit indexes for arrays on "higher levels":
{ <update operator>: { "paths.$.queries.0.requests" : value } }) (works)
if possible at all, how the corresponding R syntax would look like.
Below you'll find a reproducible example. I tried to be as concise as possible.
Code example
Database connection
require("rmongodb")
db <- "__unittest"
ns <- paste(db, "hosts", sep=".")
# CONNCETION OBJECT
con <- mongo.create(db=db)
# ENSURE EMPTY DB
mongo.remove(mongo=con, ns=ns)
Example document
q <- list("_id"="abcd")
b <- list("_id"="abcd", name="unittest.com")
mongo.insert(mongo=con, ns=ns, b=b)
q <- list("_id"="abcd")
b <- list("$push"=list(paths=list(path="home")))
mongo.update(mongo=con, ns, criteria=q, objNew=b)
q <- list("_id"="abcd", paths.path="home")
b <- list("$push"=list("paths.$.queries"=list(
name="query1", url="www.unittest.com/home?query1")))
mongo.update(mongo=con, ns, criteria=q, objNew=b)
b <- list("$push"=list("paths.$.queries"=list(
name="query2", url="www.unittest.com/home?query2")))
mongo.update(mongo=con, ns, criteria=q, objNew=b)
Update of nested arrays with explicit position index (works)
This works, but it involves an explicit index for the second-level array queries (nested in a subdoc element of array paths):
q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1")
b <- list("$push"=list("paths.$.queries.0.requests"=list(time="2013-02-13")))
> mongo.bson.from.list(b)
$push : 3
paths.$.queries.0.requests : 3
time : 2 2013-02-13
mongo.update(mongo=con, ns, criteria=q, objNew=b)
res <- mongo.find.one(mongo=con, ns=ns, query=q)
> res
_id : 2 abcd
name : 2 unittest.com
paths : 4
0 : 3
path : 2 home
queries : 4
0 : 3
name : 2 query1
requests : 4
0 : 3
time : 2 2013-02-13
url : 2 www.unittest.com/home?query1
1 : 3
name : 2 query2
url : 2 www.unittest.com/home?query2
Update of nested arrays with positional $ indexes (doesn't work)
Now, I'd like to substitute the explicit 0 with the positional $ operator just like I did in order to have the server find the desired subdoc element of array paths (paths.$.queries).
AFAIU the documentation, this should work as the crucial thing is to specify a "correct" query selector:
The positional $ operator, when used with the update() method and acts as a placeholder for the first match of the update query selector:
I think I specified a query selector that does find the correct nested element (due to the paths.queries.name="query1" part):
q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1")
I guess translated to "plain MongoDB" syntax, the query selector looks somewhat like this
{ _id: abcd, paths.path: home, paths.queries.name: query1 }
which seems like a valid query selector to me. In fact it does match the desired element/doc:
> !is.null(mongo.find.one(mongo=con, ns=ns, query=q))
[1] TRUE
My thought was that if it works on the top-level, why shouldn't it work for higher levels as well (as long as the query selector points to the right nested components)?
However, the server doesn't seem to like a nested or multiple use of $:
b <- list("$push"=list("paths.$.queries.$.requests"=list(time="2013-02-14")))
> mongo.bson.from.list(b)
$push : 3
paths.$.queries.$.requests : 3
time : 2 2013-02-14
> mongo.update(mongo=con, ns, criteria=q, objNew=b)
[1] FALSE
I'm not sure if it doesn't work because MongoDB doesn't support this or if I didn't get the R syntax right.
The positional operator only supports one level deep and only the first matching element.
There is a JIRA trackable for the sort of behaviour you want here: https://jira.mongodb.org/browse/SERVER-831
I am unsure if it will allow for more than one match but I believe it will due to the dynamics of how it will need to work.
In case you can execute your query from the MongoDB shell you can bypass this limitation by taking advantage of MongoDB cursor's forEach function (http://docs.mongodb.org/manual/reference/method/cursor.forEach/)
Here is an example with 3 nested arrays:
var collectionNameCursor = db.collection_name.find({...});
collectionNameCursor.forEach(function(collectionDocument) {
var firstArray = collectionDocument.firstArray;
for(var i = 0; i < firstArray.length; i++) {
var secondArray = firstArray[i].secondArray;
for(var j = 0; j < secondArray.length; j++) {
var thirdArray = secondArray[j].thirdArray;
for(var k = 0; k < thirdArray.length; k++) {
//... do some logic here with thirdArray's elements
db.collection_name.save(collectionDocument);
}
}
}
});
Note that this is more of a one time solution then a production code but it's going to do the job if you have to write a fix-up script.
As #FooBar mentioned in the comments of the accepted answer, this feature was implemented in 2017 with MongoDB 3.6.
To do so, you must to use positional filters with arrayFilters conditions.
Applied to your example:
updateOne(
{ "paths.home": "home" },
{ $push : {
"paths.$.queries.$[q].requests": { time: "2022-11-15" }
}
},
{ arrayFilters: [{ "q.name": "name" }] }
)
The postional operator $ refers to the filter { "paths.home": "home" }. Then, the positional filter $[q] refers to the arrayFilter { "q.name": "name" }.
Using this method, you can add as many positional filters as needed, as long as you put the condition in arrayFilters.
However, looking through the documentation of rmongodb, using arrayFilters is not possible at the moment. Alternatively, you could use another R package that has this feature implemented, such as Mongolite.

Jena TDB/Fuseki indexing for text search: Customize the URI location for each field

I have triple store of a relatively small size, which I store and access via Jena Fuseki. Here is a snippet of my data, though more optional fields can occur:
<http://example.com/#org1>
a pers:family ;
pers:name [ pers:lang "de" ;
pers:occurence "XX" ;
pers:surname "NN" ;
pers:type "std" ;
pers:var_id <http://example.com/#org1.01>
] ;
pers:org_type "Family" .
<http://example.com/#per1>
a pers:person ;
pers:first_mentions [ pers:first_mention "1234" ;
pers:occurence "XX"
] ;
pers:name [ pers:forename "Maria" ;
pers:id <http://example.com/#per1a> ;
pers:lang "de" ;
pers:occurence "XX" ;
pers:org_id <http://example.com/#org1> ;
pers:type "std"
] ;
pers:name [ pers:forename "Marie" ;
pers:lang "fr" ;
pers:occurence "XX" ;
pers:org_var_id <http://example.com/#org1.01> ;
pers:type "orig" ;
pers:var_id <http://example.com/#per1a.01>
] ;
pers:org_id <http://example.com/#org1> ;
pers:sex "1" .
Planning to implement faceted search, I have just indexed my triple store.
It was indexed OK and I have access to the index via Solr.
I configured my the indexing in my config.ttl based on the few examples found around the web.
Here is the part of my config that I have questions about:
<#entMap> a text:EntityMap ;
text:entityField "uri" ;
text:defaultField "text" ;
text:map (
[ text:field "text" ; text:predicate rdfs:label ]
[text:field "forename" ; text:predicate pers:forename ]
[text:field "surname" ; text:predicate pers:surname ]
[text:field "orgtype" ; text:predicate pers:org_type ]
[text:field "occur" ; text:predicate pers:occurence ]
[text:field "lang" ; text:predicate pers:lang ]
[text:field "description" ; text:predicate pers:description ]
[text:field "sex" ; text:predicate pers:sex ]
[text:field "marital" ; text:predicate pers:marital_status ]
[text:field "role" ; text:predicate pers:rolename ]
) .
When I query the Solr, sending this query:
http://localhost:8983/solr/project/select?q=*Mari*&wt=json&indent=true
it outputs smth like this:
{
"responseHeader":{
"status":0,
"QTime":16,
"params":{
"q":"*Mari*",
"indent":"true",
"wt":"json"}},
"response":{"numFound":39,"start":0,"docs":[
{
"uri":["_:6fdab61c39c226f305e6419d6aa5f5e9"],
"forename":["Maria"],
"id":"c3f82e8c-9650-4a18-b6c3-1eaebff9830c",
"_version_":1515091600962748416} }}
A blank node is referenced as URI. So, I understood that according to my config file, the data was indexed in such a way that "text:entityField "uri"" would look for the subject of the "text:predicate". When I was querying the index for "Mari" and the occurence was found in the field "forename", it's subject was a blank node. But for a future work with index, i.e. for facets, I need the URI of the entity (e.g. http://example.com/#per1), because I cannot use the blank nodes IDs for querying, so I cannot find out to which entry they refer.
How can I index my data, so that I could tell Solr differently for each field, where is it's URI? For example, if the indexed field is "forename", it's URI would be found somehow like this:
[text:field "forename" ; text:predicate pers:forename ; text:entityField <pattern for finding URI of the forename field>]
<pattern for finding URI of the forename field>
URI pers:name [text:field "forename"]

SWRL rules in protege 3.4.8

I created an ontology that contains the class Blood_Sugar
this class contains 4 subclasses: Normal_BS, High_BS, Low_BS and Dangerous_BS.
I would like to execute a SWRL rule on Protege 3.4.8 which permit to classify individuals of the supere class Blood_Sugar in subclasses according to their values.
Blood_Pressure(?x) ∧ hasLevelvalue(?x, ?y) ∧ swrlb:greaterThan(?y, 126) ∧ swrlb:lessThan(?y, 500) → High_BS(?x)
knowing that hasLevelValue is a DataType proprety, its domain is Blood_Sugar class and its range is INT
On the Blood_Sugar class and thier subclasses class, I created the restriction (hasLevelvalue only int)
I created som individuals that have diffrent values but they are not classified in the sub classes (High_BS, Low_BS...) the swrl rule does not give an erreur but it does not give a result :( I dont know what end wher is the problem?!!!!!
Possible problems
Your question is a bit unclear, and I'm not sure whether there are just typographical errors, or if there are genuine modeling errors. You said that you were looking at the class Blood_Sugar, and four subclasses, but then the rule that you showed starts with a Blood_Pressure atom (pressure, not sugar), and that could be the problem right there:
Blood_Pressure(?x) ∧ hasLevelvalue(?x, ?y) ∧ swrlb:greaterThan(?y, 126) ∧ swrlb:lessThan(?y, 500) → High_BS(?x)
If that's just a typo in the question, though, you could be having problems with the datatypes. Rather than using xsd:int, you should probably be using xsd:integer (so that you don't have to worry about issues with overflow, etc.) Not to mention, if you use one in your data, but declare the range differently, you could run into inconsistencies there.
Using Rules
To get you going, I've reconstructed a very minimal part of your ontology in Protégé 4.x, and using the Pellet reasoner, I've demonstrated the results that you're looking for:
I've included the ontology in N3 format toward the end of this answer.
Using Restrictions
Now, even though you can do this using SWRL rules, you can also do this using simple OWL restriction classes, and that might be a better option, because it might work with more reasoners. If nothing else, it's one less dependency, so it might be a more attractive solution. The trick is to either define Blood_HS as equivalent to the intersection of Blood_Sugar and things with a level in the desired range, or you could use an general class axiom. In both of these cases, you can get the desired result using the Pellet reasoner, and you don't need any SWRL rule.
Using an Equivalent Class Axiom
You can simply say that (using the class names that I've been using in mine ontology):
HighBloodSugar ≡ BloodSugar and (hasLevelValue some integer[>120,<600])
In Protégé that looks a little bit different, but it's pretty close:
Using a Subclass Axiom
Now, if you you don't want to make that an equivalent class axiom, you can use a general axiom like the following.
BloodSugar and (hasLevelValue some integer[>120,<600]) &sqsubseteq; HighBloodSugar
This only looks a little bit different in Protégé. This is the closest to the SWRL version, since anything that is a blood sugar and has a level in the specified range will be classified as a high blood sugar, but it's still possible that there are other high blood sugars, too. (You don't get this with the equivalent class axiom.)
Ontology with Rules
#prefix : <http://stackoverflow.com/q/21243879/1281433/blood-pressure.owl#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix swrl: <http://www.w3.org/2003/11/swrl#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix swrlb: <http://www.w3.org/2003/11/swrlb#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix blood-pressure: <http://stackoverflow.com/q/21243879/1281433/blood-pressure.owl#> .
<http://stackoverflow.com/q/21243879/1281433/blood-pressure.owl>
a owl:Ontology .
blood-pressure:HighBloodSugar
a owl:Class .
blood-pressure:bs1 a owl:NamedIndividual , blood-pressure:BloodSugar ;
blood-pressure:hasLevelValue 200 .
<urn:swrl#bp> a swrl:Variable .
<urn:swrl#bs> a swrl:Variable .
blood-pressure:BloodSugar
a owl:Class .
blood-pressure:hasLevelValue
a owl:DatatypeProperty ;
rdfs:domain blood-pressure:BloodSugar ;
rdfs:range xsd:integer .
[ a swrl:Imp ;
swrl:body [ a swrl:AtomList ;
rdf:first [ a swrl:ClassAtom ;
swrl:argument1 <urn:swrl#bs> ;
swrl:classPredicate blood-pressure:BloodSugar
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:DatavaluedPropertyAtom ;
swrl:argument1 <urn:swrl#bp> ;
swrl:argument2 <urn:swrl#level> ;
swrl:propertyPredicate blood-pressure:hasLevelValue
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:BuiltinAtom ;
swrl:arguments [ a rdf:List ;
rdf:first <urn:swrl#level> ;
rdf:rest [ a rdf:List ;
rdf:first 126 ;
rdf:rest ()
]
] ;
swrl:builtin swrlb:greaterThan
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:BuiltinAtom ;
swrl:arguments [ a rdf:List ;
rdf:first <urn:swrl#level> ;
rdf:rest [ a rdf:List ;
rdf:first 500 ;
rdf:rest ()
]
] ;
swrl:builtin swrlb:lessThan
] ;
rdf:rest ()
]
]
]
] ;
swrl:head [ a swrl:AtomList ;
rdf:first [ a swrl:ClassAtom ;
swrl:argument1 <urn:swrl#bs> ;
swrl:classPredicate blood-pressure:HighBloodSugar
] ;
rdf:rest ()
]
] .
<urn:swrl#level> a swrl:Variable .

Resources