Reputation: 1198
I build a query, it is very simple, but my problem is that i find myself repeating the same triples again and again.
I have a class called TemporalContext
, each instance of it has:
Either the property canBeRecommendedFrom
, (range datetime)
or the property canBeRecommendedUntil
(range datetime)
or both
Each instance could have as well:
Either the property weightIfContextMatched
or the property weightIfContextDoesNotMatch
or both
What I want to do is:
TemporalContext
has both canBeRecommendedFrom
and canBeRecommendedUtill
, then if it today is inside that range, select the value of weightIfContextMatched
, if not, select the value of weightIfontextDoesNotFound
. However, maybe the values weightIfContextMatched
and weightIfContextDoesNotMatch
are not set, so then I use a default value.TemporalContext
has just canBeRecommendFrom
and doesn't have canBeRecommendUntil
TemporalContext
has just canBeRecommendedUntill
and doesn't have canBeRecommendFrom
I did a query for the case in which the instance of TemporalContext
has both canBeRecommendedFrom
and canBeRecommendedUntil
with all the variation of weightIfContextMatched
and weightIfContextDoesNotMatch
Here you go the query
select ?item ?finalTemporalWeight where
{
values ?user {bo:ania}
#the items that have temporal context(s)
{
select ?item (SUM(?temporalWeight) as ?finalTemporalWeight) {
?item a rs:RecommendableClass .
#to be sure that the item belongs to the class
filter exists {
?item a ?itemClass
}
#the items that has both from and until temporal context
{
{
#this block is if today is inside the range
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that both until and from were set.
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
#check if today is before the until limit
filter (now () < ?untilLimit)
#check if today is after the from limit
filter (now () > ?fromLimit)
optional
{
?tempoalContext rs:hasWeightIfContextMatched ?weight
}
bind((if(bound(?weight), ?weight, 1)) as ?temporalWeight)
}
union
{
#this block is if today is after the until limit
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that both until and from were set.
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
#check if today is after the until limit
filter (now () > ?untilLimit)
optional
{
?tempoalContext rs:hasWeightIfContextDoesNotMatch ?weight
}
bind((if(bound(?weight), ?weight, 0.1)) as ?temporalWeight)
}
union
{
#this block is if today is before the from limit
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that both until and from were set.
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
#check if today is before the from limit
filter (now () < ?fromLimit)
optional
{
?tempoalContext rs:hasWeightIfContextDoesNotMatch ?weight
}
bind((if(bound(?weight), ?weight, 0.3)) as ?temporalWeight)
}
}
union
#the items that has just from temporal context
{
{
#this block is if today is before the from limit
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that the from limit is set.
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
#to be sure that the until limit is not set.
filter not exists {
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
}
#check if today is before the from limit
filter (now () < ?fromLimit)
optional
{
?tempoalContext rs:hasWeightIfContextDoesNotMatch ?weight
}
bind((if(bound(?weight), ?weight, 0.15)) as ?temporalWeight)
}
union
{
#this block is if today is after the from limit
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that the from limit is set.
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
#to be sure that the until limit is not set.
filter not exists {
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
}
#check if today is before the from limit
filter (now () > ?fromLimit)
optional
{
?tempoalContext rs:hasWeightIfContextMatched ?weight
}
bind((if(bound(?weight), ?weight, 0.25)) as ?temporalWeight)
}
}
union
#the items that has just until temporal context
{
{
#this block is if today is before the until limit
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that the until limit is set.
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
#to be sure that the from limit is not set.
filter not exists {
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
}
#check if today is before the until limit
filter (now () < ?untilLimit)
optional
{
?tempoalContext rs:hasWeightIfContextMatched ?weight
}
bind((if(bound(?weight), ?weight, 0.35)) as ?temporalWeight)
}
union
{
#this block is if today is after the until limit
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
#to be sure that the until limit is set.
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
#to be sure that the from limit is not set.
filter not exists {
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
}
#check if today is after the until limit
filter (now () > ?untilLimit)
optional
{
?tempoalContext rs:hasWeightIfContextDoesNotMatch ?weight
}
bind((if(bound(?weight), ?weight, 0.45)) as ?temporalWeight)
}
}
union
#the items that have temporal context, but that temporal context has no canBeRecommendedFrom nor canBeRecommendedUntil
{
select distinct ?item ?temporalWeight {
?item a rs:RecommendableClass .
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
?item a ?itemClass .
#to be sure that neight canBeRecommendFrom nor canBeRecommendedUntil is set
filter not exists {
?tempoalContext rs:canBeRecommendedFrom ?fromLimit .
}
filter not exists {
?tempoalContext rs:canBeRecommendedUntil ?untilLimit .
}
bind (4.4 as ?temporalWeight)
}
}
}group by ?item
}
union
#the items that don't have a temporal context, we will use the defalut value:
{
select distinct ?item ?finalTemporalWeight {
?item a rs:RecommendableClass .
?tempoalContext a rs:TemporalContext .
?tempoalContext rs:appliedOnItems ?itemClass .
filter not exists {
?item a ?itemClass
}
bind (2.3 as ?finalTemporalWeight)
}
}
}
order by ?item
the query is so easy but long, and i find myself repeating the same thing inside each union. and now i have to reapeat the same thing for the second and third case,
I thought before continuing in this long-but-easy-query i ask you first maybe you know a better way to reduce the size of it.
the query is working very well, i tested it
After the appreciate reply from @Joshua Taylor here is the result:
However, this is the result of my code:
You can see that the row number 6, the item doesn't have any value, the case of that item is: it is before the from limit. so the correct union is #this block is if today is before the from limit
. but there is no value for hasWeightIfContextDoenNotMatch
so we should use the default value, which is 0.3
, my code does that, my the code in the answer doesn't.
Now I finished (and updated the query) developing the boring-so-so-so boring query but i handled all the scenarios, I will tell you the scenarios:
1.1. the temporalClass has both canBeRecommendFrom and canBeRecommendUntill
1.1.1. the item is inside the range
1.1.1.1. the weightIfContextMatched exists.
1.1.1.2. the weightIfContextMatched doesn't exist.
1.1.2. the item is before the from limit.
1.1.2.1 the weightIfContextDoesNotMatch exists.
1.1.2.2. the weightIfContextDoesNotMatch doesn't exist.
1.1.3. the item is after the until limit.
1.1.3.1 the weightIfContextDoesNotMatch exists.
1.1.3.2. the weightIfContextDoesNotMatch doesn't exist.
1.2. the temporalClass has just canBeRecommendFrom
1.2.1 the item is after the from limit
1.2.1.1. the weightIfContextMatched exists.
1.2.1.2. the weightIfContextMatched doesn't exist.
1.2.2 the item is before the from limit
1.2.2.1 the weightIfContextDoesNotMatch exists.
1.2.2.2. the weightIfContextDoesNotMatch doesn't exist.
1.3. the temporalClass has just canBeRecommednFrom
1.3.1 the item is before the from limit
1.3.1.1 the weightIfContextDoesNotMatch exists.
1.3.1.2. the weightIfContextDoesNotMatch doesn't exist.
1.3.2 the item is after the from limit
1.3.2.1. the weightIfContextMatched exists.
1.3.2.2. the weightIfContextMatched doesn't exist.
1.4. the temporalClass has neither canBeRecommendFrom nor canBeRecommendUntil
use default value (be careful of duplicated)
use default value (be careful of duplicated)
Upvotes: 1
Views: 124
Reputation: 85913
You're always looking for a temporal context that is a TemporalContext, that is applied on an item class, and that has a from and until limit, so that can come out of the query. Then you're interested in optional weights to use depending on whether now() before, during, or after the interval. Then you want to set temporal weight as the matching weight (or 1) if we're in the interval, or else the unmatched weight (or 0.1) if we're after it, or else the unmatched weight (or 0.3) if we're before it. I'd do that with a bind that checks those conditions, and uses coalesce to select the optional value or the default:
SELECT ?item ?temporalContext ?itemClass ?weight ?temporalWeight
WHERE
{ VALUES ?user { bo:ania }
?item a rs:RecommendableClass .
?temporalContext a rs:TemporalContext ;
rs:appliedOnItems ?itemClass ;
rs:canBeRecommendedFrom ?fromLimit ;
rs:canBeRecommendedUntil ?untilLimit .
OPTIONAL {
?temporalContext rs:hasWeightIfContextMatched ?matchedWeight
}
OPTIONAL {
?temporalContext rs:hasWeightIfContextDoesNotMatch ?unmatchedWeight
}
bind(if(now() < ?fromLimit,
coalesce(?unmatchedWeight, 0.1),
if(?fromLimit <= now() && now() <= ?untilLimit,
coalesce(?matchedWeight, 1.0),
if(?untilLimit < now(),
coalesce(?unmatchedWeight, 0.3),
0.0))) #-- default here?
as ?temporalWeight)
}
ORDER BY ?item
I've used <= in checking whether now() is in the duration, since before if now() had been exactly equal to one of them, you might not have caught it. It it possible that you get to the "default here?" line, though? I think it's still possible if the data doesn't actually have comparable times there. as I see it, you can either use a default value there (like 0.0), or you can just assume that if the first two cases didn't match, then you just want the third, in which case you can skip the check altogether and just do:
bind(if(now() < ?fromLimit,
coalesce(?unmatchedWeight, 0.1),
if(?fromLimit <= now() && now() <= ?untilLimit,
coalesce(?matchedWeight, 1.0),
coalesce(?unmatchedWeight, 0.3)))
as ?temporalWeight)
Upvotes: 4