Spinrdf sp:now function is not returning anything - sparql

SPIN is a way to represent a wide range of business rules.
This is the official one line description for spin (spinrdf).
Spin enables users to represent their rules with sparqls in ontologies.
I needed to make these descriptions since there is no spinrdf tag.
I have been using spin about a week to write some rules. Now I'm writing some functions to simplify my sparqls in my rules. I have a written a simple date comparison function compareDates. When I call the function with the following sparql there is no errors and gives the expected result.
SELECT ?result
WHERE {
BIND(:compareDates("2015-03-03"^^xsd:date, "2015-06-09"^^xsd:date) as ?result)
}
I would like to use sp:now function comes with spin. When I use the following sparql I have no output.
SELECT ?result
WHERE {
BIND(:compareDates("2015-03-03"^^xsd:date, sp:now()) as ?result)
}
Then I tried the following, but no luck:
SELECT ?result
WHERE {
BIND(sp:now() as ?now)
BIND(:compareDates("2015-03-03"^^xsd:date, ?now) as ?result)
}
And then I decided to see what sp:now returns and I have runned the following sparql the result is null. This lead me to a conclusion that I won't be able to run this function.
SELECT ?now
WHERE {
BIND(sp:now() as ?now)
}
I would like to use that function or similar one but I don't get the problem. Any comment is appreciated.
UPDATE 1
As shown in the following screenshot, the function does not contain any body! This would be the problem but, why it's been placed in the related ontology if won't work.

After some research I have find out two alternative methods for having now datetime. In fact there exists a sparql implementaion of now() function documented here.
SELECT ?now
WHERE {
BIND(now() as ?now).
}
This sparql will return the following:
[now]
2015-03-24T22:12:29.183+02:00
There is an alternative method placed in spin ontology; afn:now() which is placed under spl:MiscFunctions class. This function will give the same result.
By the way, I have been using xsd:date as my functions argument but the both now function alternatives returns xsd:dateTime literals.
To convert these to xsd:date is another story.
There exists some cast functions but they convert only type but not trim the hour part of the xsd:dateTime which causes my comparison to fail.
Thus have come up with the following sparql which uses an indirect approach to convert xsd:dateTime to xsd:date :
SELECT ?nowDateTime ?nowDate
WHERE {
BIND(now() as ?nowDateTime).
BIND(spif:cast(spif:dateFormat(?nowDateTime, "yyyy-MM-dd"), xsd:date) as ?nowDate).
}
Which converted the successfully.
This could be a premature way to convert between to date literal types but this is what I have came up to solve my problem.
Any advice is appreciated.

Related

BigQuery : Returning timestamp from JS udf throwing "Failed to coerce output value to type TIMESTAMP"

I have a bigquery code.
CREATE TEMP FUNCTION to_struct_attributes(input STRING)
RETURNS STRUCT<status_code STRING, created_time TIMESTAMP>
LANGUAGE js AS """
let res = JSON.parse(input);
res['created_time'] = Date(res['created_time'])
return res;
""";
SELECT
5 AS ID,
to_struct_attributes(
TO_JSON_STRING(
STRUCT(
TIMESTAMP(PARSE_TIMESTAMP('%Y%m%d%H%M%S', '20220215175959','America/Los_Angeles')) AS created_time
)
)
) AS ATTRIBUTES;
When I execute this, I'm getting the following error:
Failed to coerce output value "2022-02-16 01:59:59+00" to type TIMESTAMP
I feel this is quite strange, since BigQuery should be able to interpret it correctly and I haven't had this issue with any other datatypes. Also, if I do:
SELECT TIMESTAMP("2022-02-16 01:59:59+00")
It returns:
2022-02-16 01:59:59 UTC
So BigQuery can indeed parse it correctly. I'm not sure why it doesn't happen for the UDF. On searching the internet, I found this question and as the answer suggests, if I change the return statement to:
return Date(res.created_time);
It resolves the issue. But for a project of mine, doing it for every timestamp is not feasible due to the high number of struct columns.
So, I wanted to know if someone has a better alternative to it?
PS : I have removed a lot of non-essential parts from the above example, so this might look a bit abstract. Also, the actual use-case is a bit different and complex that's why I need that JS udf.
The best way to do what you want is to implement the following code.
return Date(res.created_time);
This happens when you pass a TIMESTAMP to a UDF, it is represented as a DATE object, as stated in the documentation. This is like a return of a TIMESTAMP from a JavaScript UDF, where you need to construct and return a DATE object.

Is it possible to use variables as integers in SPARQL property paths?

I am currently trying to create pointers to datatype values as they cannot be linked directly. However, I would like to be able to evaluate the pointers from within the SPARQL environment, which raised specifically in the case that the desired value is part of an ordered rdf:List some questions for me. My approach is to use property paths within a SPARQL query in which I can use the defined individual, property and index of the ordered list that the pointer has attached to it.
Given the following example data with the shortened syntax for ordered lists by ttl:
ex:myObject ex:somePropery ("1" "2" "3") .
ex:myPointer ex:lookAtIndividual ex:myObject;
ex:lookAtProperty ex:someProperty ;
ex:lookAtIndex "3"^^xsd:integer .
Now I would like to create a SPARQL query that -- based on the pointer -- returns the value at the given index. To my understanding the query could/should look something like this:
SELECT ?value
WHERE {
ex:myPointer ex:lookAtIndividual ?individual ;
ex:lookAtProperty ?prop ;
ex:lookAtIndex ?index .
?individual ?prop/rdf:rest{?index-1}/rdf:first ?value .
}
But if I try to execute this query with TopBraid, it shows an error message that ?index has been found when <INTEGER> was expected. I also tried binding the index in the SPARQL query via BIND(?index-1 AS ?i), again without success. If the pointed value is not stored in a list, the query without property path works fine.
Is it in general possible to use a value that is connected via datatype property within a SPARQL query as path length for property paths?
This syntax: rdf:rest{<number>} is not standard SPARQL. So the short answer is, regrettably: no, you can't use variables as integers in SPARQL property paths, for the simple reason that you can't use integers in SPARQL property paths at all.
In an earlier draft of the SPARQL standard, there was a proposal to use this kind of syntax to allow specifying the min and max length of a property path, e.g. rdf:rest{1, 3} would match any paths using rdf:rest properties between length 1 and 3. But this was never fully standardized and most SPARQL engines don't implement it.
If you happen to use a SPARQL engine that does implement it, you will have to get in touch with the developers directly to ask if they can extend the mechanism to allow use of variables in this position (the error message suggests to me that it's currently just not possible).
As an aside: there's a SPARQL 1.2 community initiative going on. It only just got started but one of the proposals on the table is re-introducing this particular piece of functionality to the standard.

What is the benefit of defining datatypes for literals in an RDF graph?

I am using rdflib in Python to build my first rdf graph. However, I do not understand the explicit purpose of defining Literal datatypes. I have scraped over the documentation and did my due diligence with google and the stackoverflow search, but I cannot seem to find an actual explanation for this. Why not just leave everything as a plain old Literal?
From what I have experimented with, is this so that you can search for explicit terms in your Sparql query with BIND? Does this also help with FILTERing? i.e. FILTER (?var1 > ?var2), where var1 and var2 should represent integers/floats/etc? Does it help with querying speed? Or am I just way off altogether?
Specifically, why add the following triple to mygraph
mygraph.add((amazingrdf, ns['hasValue'], Literal('42.0', datatype=XSD.float)))
instead of just this?
mygraph.add((amazingrdf, ns['hasValue'], Literal("42.0")))
I suspect that there must be some purpose I am overlooking. I appreciate your help and explanations - I want to learn this right the first time! Thanks!
Comparing two xsd:integer values in SPARQL:
ASK { FILTER (9 < 15) }
Result: true. Now with xsd:string:
ASK { FILTER ("9" < "15") }
Result: false, because when sorting strings, 9 comes after 1.
Some equality checks with xsd:decimal:
ASK { FILTER (+1.000 = 01.0) }
Result is true, it’s the same number. Now with xsd:string:
ASK { FILTER ("+1.000" = "01.0") }
False, because they are clearly different strings.
Doing some maths with xsd:integer:
SELECT (1+1 AS ?result) {}
It returns 2 (as an xsd:integer). Now for strings:
SELECT ("1"+"1" AS ?result) {}
It returns "11" as an xsd:string, because adding strings is interpreted as string concatenation (at least in Jena where I tried this; in other SPARQL engines, adding two strings might be an error, returning nothing).
As you can see, using the right datatype is important to communicate your intent to code that works with the data. The SPARQL examples make this very clear, but when working directly with an RDF API, the same kind of issues crop up around object identity, ordering, and so on.
As shown in the examples above, SPARQL offers convenient syntax for xsd:string, xsd:integer and xsd:decimal (and, not shown, for xsd:boolean and for language-tagged strings). That elevates those datatypes above the rest.

ERROR: function regexp_matches(jsonb, unknown) does not exist in Tableau but works elsewhere

I have a column called "Bakery Activity" whose values are all JSONs that look like this:
{"flavors": [
{"d4js95-1cc5-4asn-asb48-1a781aa83": "chocolate"},
{"dc45n-jnsa9i-83ysg-81d4d7fae": "peanutButter"}],
"degreesToCook": 375,
"ingredients": {
"d4js95-1cc5-4asn-asb48-1a781aa83": [
"1nemw49-b9s88e-4750-bty0-bei8smr1eb",
"98h9nd8-3mo3-baef-2fe682n48d29"]
},
"numOfPiesBaked": 1,
"numberOfSlicesCreated": 6
}
I'm trying to extract the number of pies baked with a regex function in Tableau. Specifically, this one:
REGEXP_EXTRACT([Bakery Activity], '"numOfPiesBaked":"?([^\n,}]*)')
However, when I try to throw this calculated field into my text table, I get an error saying:
ERROR: function regexp_matches(jsonb, unknown) does not exist;
Error while executing the query
Worth noting is that my data source is PostgreSQL, which Tableau regex functions support; not all of my entries have numOfPiesBaked in them; when I run this in a simulator I get the correct extraction (actually, I get "numOfPiesBaked": 1" but removing the field name is a problem for another time).
What might be causing this error?
In short: Wrong data type, wrong function, wrong approach.
REGEXP_EXTRACT is obviously an abstraction layer of your client (Tableau), which is translated to regexp_matches() for Postgres. But that function expects text input. Since there is no assignment cast for jsonb -> text (for good reasons) you have to add an explicit cast to make it work, like:
SELECT regexp_matches("Bakery Activity"::text, '"numOfPiesBaked":"?([^\n,}]*)')
(The second argument can be an untyped string literal, Postgres function type resolution can defer the suitable data type text.)
Modern versions of Postgres also have regexp_match() returning a single row (unlike regexp_matches), which would seem like the better translation.
But regular expressions are the wrong approach to begin with.
Use the simple json/jsonb operator ->>:
SELECT "Bakery Activity"->>'numOfPiesBaked';
Returns '1' in your example.
If you know the value to be a valid integer, you can cast it right away:
SELECT ("Bakery Activity"->>'numOfPiesBaked')::int;
I found an easier way to handle JSONB data in Tableau.
Firstly, make a calculated field from the JSONB field and convert the field to a string by using str([FIELD_name]) command.
Then, on the calculated field, make another calculated field and use function:
REGEXP_EXTRACT([String_Field_Name], '"Key_to_be_extracted":"?([^\n,}]*)')
The required key-value pair will form the second caluculated field.

generate an urn/iri/uri dynamically

I need to generate dynamically the name of a graph depending on the time.
I've tough that some think like
select ?g where {
bind(concat("<urn:myNewGraph_",str(now()),">") as ?g)
}
would have done the trick, but with Stardog I get a null result.
If instead I run this
select ?g where {
bind(concat("urn:myNewGraph_",str(now())) as ?g)
}
i get urn:myNewGraph_2015-05-28T09:37:11.823Z
Any Ideas?
moreover I'm not sure that even if i can get somehow a string like <urn:myNewGraph_2015-05-28T09:37:11.823Z> would have worked as a valid argument for a graph name as can be seen from this not-working test:
INSERT {graph ?g {<urn:s> <urn:p> <urn:o>}
where {
?g="<rn:myNewGraph_2015-05-28T09:37:11.823Z>"
}
is there a proper way to generate an urn/iri/uri dynamically?
Your original query looks correct, and produces a valid result when I execute it using a different SPARQL engine (Sesame), so I guess that you might want to report this to the Stardog developers as a possible bug.
However, to be able to use the value thus obtained it needs to be an actual URI (or IRI) - whereas what you're producing is a literal string.
You need to change two things: first of all, get rid of the enclosing < and > (these brackets are not actually part of the IRI) - so actually your second query is better. Second, use the IRI function to convert your string value to an IRI:
INSERT {GRAPH ?g {<urn:s> <urn:p> <urn:o>} }
WHERE {
BIND( IRI(CONCAT("urn:myNewGraph_",STR(NOW()))) as ?g)
}
Not sure it's necessary in your case, but in general you may need to use the ENCODE_FOR_URI function in there somewhere, to make sure that any special characters in your string are properly encoded/escaped before turning it into an IRI.