How to use the MONTH() function from SPARQL to extract the month of a date in rdf4j?

158 views
Skip to first unread message

Vaishali R

unread,
May 24, 2021, 11:14:20 AM5/24/21
to RDF4J Users
Hi,

I've also posted this question on stackoverflow, apologies for asking twice, but it's quite an urgent problem and I just wanted to post to see wherever i could get an answer first! :)

I wish to replicate the following filter from SPARQL in java using rdf4j but I'm not quite sure how to.

FILTER(?endDate > NOW() && ?startDate < NOW() && MONTH(?endDate) = MONTH(NOW()))

I have initialised expressions for MONTH() and NOW() as follows, and a graph pattern called 'pattern', but don't know how to use them to extract the month from variable ?endDate and from the NOW() function

Expression<?> nowFunc = Expressions.function(SparqlFunction.NOW ); 
Expression<?> month = Expressions.function(SparqlFunction.MONTH); 
Expression<?> endDateGreaterThan = Expressions.gt(endDate, nowFunc); 
Expression<?> startDateLessThan = Expressions.lt(startDate, nowFunc);

The query I have so far is as follows, but I can't figure out how to implement the final part (****) of the filter into the query.

SelectQuery query = Queries.SELECT().prefix(ex).select(letter).where(pattern.filter(Expressions. and(endDateGreaterThan, startDateLessThan, ****)

Any help would be appreciated! Thank you so much :)

Jeen Broekstra

unread,
May 24, 2021, 11:20:52 PM5/24/21
to RDF4J Users


On Tue, 25 May 2021, at 01:14, Vaishali R wrote:
I wish to replicate the following filter from SPARQL in java using rdf4j but I'm not quite sure how to.
FILTER(?endDate > NOW() && ?startDate < NOW() && MONTH(?endDate) = MONTH(NOW()))

I have initialised expressions for MONTH() and NOW() as follows, and a graph pattern called 'pattern', but don't know how to use them to extract the month from variable ?endDate and from the NOW() function

Expression<?> nowFunc = Expressions.function(SparqlFunction.NOW ); 
Expression<?> month = Expressions.function(SparqlFunction.MONTH); 
Expression<?> endDateGreaterThan = Expressions.gt(endDate, nowFunc); 
Expression<?> startDateLessThan = Expressions.lt(startDate, nowFunc);

The query I have so far is as follows, but I can't figure out how to implement the final part (****) of the filter into the query.

SelectQuery query = Queries.SELECT().prefix(ex).select(letter).where(pattern.filter(Expressions. and(endDateGreaterThan, startDateLessThan, ****)

Any help would be appreciated! Thank you so much :)

It's no different from how you have set up your other expressions. You want an equals comparison operation between two value expressions (let's call them leftArg and rightArg), so:

Expression monthEquals = Expressions.equals(leftArg, right);

Your leftArg and rightArg are both also functions, both with a single operand. The leftArg has a simple variable as its function operand:

Expression leftArg = Expressions.function(SparqlFunction.MONTH, endDate);

The rightArg has a function as its operand:

Expression rightArg = Expressions.function(SparqlFunction.MONTH, Expressions.function(SparqlFunction..NOW));

Just put it all together and you're done.

Cheers,

Jeen



Vaishali R

unread,
May 25, 2021, 6:02:55 AM5/25/21
to RDF4J Users
Great thank you so much!

Vaishali R

unread,
May 25, 2021, 10:25:50 AM5/25/21
to RDF4J Users
I actually have another question, I also wish to replicate this filter from SPARQL in java but can't figure out how to:

FILTER(?endDate < NOW() + "P3M"^^xsd:duration && ?endDate >= NOW() && ?startDate < NOW())

I have initialised the following expressions:

ValueFactory x = SimpleValueFactory.getInstance();
Literal threeMonths = x.createLiteral("P3M", XSD.DURATION);

Variable endDate = SparqlBuilder.var("endDate");
Variable startDate = SparqlBuilder.var("startDate");
Expression<?> nowFunc = Expressions.function(SparqlFunction.NOW);
Expression<?> startDateLessThan = Expressions.lt(startDate, nowFunc);
Expression<?> endDateGreaterEqual = Expressions.gte(endDate, nowFunc);
Expression<?> endDateThreeMonths = Expressions.plus(nowFunc, threeMonths);

The last expression: endDateThreeMonths doesn't compile and returns the error: 'plus(org.eclipse.rdf4j.sparqlbuilder.constraint.Operand)' in 'org.eclipse.rdf4j.sparqlbuilder.constraint.Expressions' cannot be applied to '(org.eclipse.rdf4j.sparqlbuilder.constraint.Expression<capture<?>>, org.eclipse.rdf4j.model.Literal)'

I may have initialised the ValueFactory and Literal completely wrong so any help would be appreciated!

Thanks,
Vaishali

Jeen Broekstra

unread,
May 25, 2021, 12:20:44 PM5/25/21
to RDF4J Users
You want Expressions.add instead of Expressions.plus. As the javadoc explains (though perhaps not as clearly as it should), Expressions.plus is the unary plus operator (which is not used for addition but for changing the sign of a number).

Jeen 
--
You received this message because you are subscribed to the Google Groups "RDF4J Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rdf4j-users...@googlegroups.com.

Vaishali R

unread,
May 26, 2021, 11:04:46 AM5/26/21
to RDF4J Users
Hey Jeen,

Thanks for the reply, I really appreciate it. Again though, there is still an error, completely my fault as I'm still quite new to java, so I'm sorry about all the questions. For the same filter as above:

FILTER(?endDate < NOW() + "P3M"^^xsd:duration && ?endDate >= NOW() && ?startDate < NOW())

I've now initialised the expression as: 

ValueFactory x = SimpleValueFactory.getInstance();
Literal threeMonths = x.createLiteral("P3M", XSD.DURATION);
Variable endDate = SparqlBuilder.var("endDate");
Expression<?> nowFunc = Expressions.function(SparqlFunction.NOW);
Expression<?> endDateGreaterEqual = Expressions.gte(endDate, nowFunc);
Expression<?> endDateThreeMonths = Expressions.add(nowFunc, threeMonths);

And I now get the following error: 'add(org.eclipse.rdf4j.sparqlbuilder.constraint.Operand...)' in 'org.eclipse.rdf4j.sparqlbuilder.constraint.Expressions' cannot be applied to '(org.eclipse.rdf4j.sparqlbuilder.constraint.Expression<capture<?>>, org.eclipse.rdf4j.model.Literal)'

From what I understand, the threeMonths expression has not been initialised properly. What I am trying to achieve is to add 3 months on to NOW() whenever the SPARQL query is sent.

Any help would be appreciated.
Thanks,
Vaishali

Jeen Broekstra

unread,
May 26, 2021, 10:09:19 PM5/26/21
to RDF4J Users


On Thu, 27 May 2021, at 01:04, Vaishali R wrote:
Hey Jeen,

Thanks for the reply, I really appreciate it. Again though, there is still an error, completely my fault as I'm still quite new to java, so I'm sorry about all the questions.


it's absolutely ok to ask questions - that's what this forum is for. 


ValueFactory x = SimpleValueFactory.getInstance();
Literal threeMonths = x.createLiteral("P3M", XSD.DURATION);

Variable endDate = SparqlBuilder.var("endDate");
Expression<?> nowFunc = Expressions.function(SparqlFunction.NOW);
Expression<?> endDateGreaterEqual = Expressions.gte(endDate, nowFunc);
Expression<?> endDateThreeMonths = Expressions.add(nowFunc, threeMonths);

And I now get the following error: 'add(org.eclipse.rdf4j.sparqlbuilder.constraint.Operand...)' in 'org.eclipse.rdf4j.sparqlbuilder.constraint.Expressions' cannot be applied to '(org.eclipse.rdf4j.sparqlbuilder.constraint.Expression<capture<?>>, org.eclipse.rdf4j.model.Literal)'

From what I understand, the threeMonths expression has not been initialised properly. What I am trying to achieve is to add 3 months on to NOW() whenever the SPARQL query is sent.

Ah. Look at the error message, it gives you a clue. It is not expecting an instance of org.eclipse.rdf4j.model.Literal in that place. 

The problem here is that the SparqlBuilder accepts RDF4J model objects (such as org.eclipse.rdf4j.model.Literal) in most places, but in other places (such as here) it can only work with its own internal value types. This is a known issue in the SparqlBuilder.

The workaround is simple: instead of using an RDF4J Model object for the literal, use the SparqlBuilder's own factory method to create a literal value:

StringLiteral threeMonths = Rdf.literalOfType("P3M", XSD.DURATION);

Cheers,

Jeen

Vaishali R

unread,
May 27, 2021, 5:53:44 AM5/27/21
to RDF4J Users
Amazing thank you so much! It all compiles and does exactly what I need it to do now. 

Much appreciated! :)

Reply all
Reply to author
Forward
0 new messages