Query to GraphDB's repository with custom functions SPARQL using Jena - java

I've implemented some custom functions SPARQL with Jena ARQ following the Property Function docs. Those functions work with a local dataset using a model:
Model model = ModelFactory.createDefaultModel();
model.read(new FileInputStream("data/data.ttl"), null, "TTL");
Query query = QueryFactory.create(queryString) ; // the queryString contains a custom property function defined with Jena
try (QueryExecution qexec = QueryExecutionFactory.create(query, model)) {
...
}
However, I need to apply these property functions for queries on a dataset on my Graphdb Repository, so I tried to connect program to GraphDB using Jena.
I've tried following Using GraphDB with Jena but it seems out of date and cannot be implemented because SailRepository.initialize(); was deprecated and SesameDataset doesn't longer exist to initialize my model.
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import com.ontotext.jena.SesameDataset;
...
RepositoryConnection connection = repository.getConnection();
// finally, create the DatasetGraph instance
SesameDataset dataset = new SesameDataset(connection);
I've also tried RDFConnection of Jena but it doesn't work with my custom functions since there's no model backend to apply queries.
Can anyone tell me where can I find the SesameDataset to import or whether there is other way to query a GraphDB's repository with custom functions?

You would probably make your life a lot easier by using RDF4J to communicate with GraphDB, instead of Jena - it is the recommended Java API for this purpose by the GraphDB developers.
You can implement custom SPARQL functions in RDF4J/GraphDB by following this tutorial - in summary it's a matter of implementing the org.eclipse.rdf4j.query.algebra.evaluation.function.Function interface and making sure your implementation is on the classpath of GraphDB and registered as an SPI implementation.

Jeen (the creator of rdf4j) pointed how you can create custom functions.
However, as AndyS (the creator of Jena) points out, you seem to need magic predicates (custom property functions). For that I think that you need to create a plugin and implement pattern interpretation as described here: http://graphdb.ontotext.com/documentation/standard/plug-in-api.html#pattern-interpretation.
Most plugins are open source at https://github.com/Ontotext-AD, so you can see many examples. I know for sure that https://github.com/Ontotext-AD/graphdb-geosparql-plugin uses magic predicates, eg
?x geo:sfWithin ?y is a predicate that checks (or returns) all features where ?x is within ?y
geof:sfWithin(?x,?y) (note the different namespace) is a function that checks the same condition, but must be called with bound params: it cannot find features satisfying the condition.
See this search and then see IRI GEO_SF_WITHIN, search with GEO_SF_WITHIN, and you find com/ontotext/trree/geosparql/GeoSparqlFunction.java and com/useekm/geosparql/algebra/PropertyToFunctionOptimizer.java

Related

How to check if a process definition key exist in camunda using services?

I am trying to know if a process definition key exists in Camunda using its services.
I am aware of the rest api to fetch the details which is - GET /process-definition/key/{key}.
But instead of using rest calls, I would like to use the service's methods to achieve in my Java code.
Checke the RepositoryService. It will give you the createProcessDefinitionQuery method, which creates a Query builder that (among other attributes) accepts the process definition key.
Solution-
RepositoryService RS= execution.getProcessEngineServices().getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = RS.createProcessDefinitionQuery().processDefinitionKey("sample_key");
long count= processDefinitionQuery.count();

Create a custom Aggregate Function with jOOQ

Context
I am working with jOOQ against a PostgreSQL database.
I want to use jsonb_object_agg(name, value) onto the resultset of a LEFT OUTER JOIN.
Problem
The join being an OUTER one, sometimes the name component of the aggregation function is simply null: that can't work. I would then go for:
COALESCE(
json_object_agg(table.name, table.value) FILTER (WHERE table.name IS NOT NULL),
'{}'
)::json
As of now, the code I use to call jsonb_object_agg is (not exactly, but boils down to) the following:
public static Field<?> jsonbObjectAgg(final Field<?> key, final Select<?> select) {
return DSL.field("jsonb_object_agg({0}, ({1}))::jsonb", JSON_TYPE, key, select);
}
... where JSON_TYPE is:
private static final DataType<JsonNode> JSON_TYPE = SQLDataType.VARCHAR.asConvertedDataType(/* a custom Converter */);
Incomplete solution
I would love to leverage jOOQ's AggregateFilterStep interface, and in particular, to be able to use its AggregateFilterStep#filterWhere(Condition... conditions).
However, the org.jooq.impl.Function class that implements AggregateFilterStep (indirectly via AgregateFunction and ArrayAggOrderByStep) is restricted in visibility to its package, so I can't just recycle blindly the implementation of DSL#ArrayAggOrderByStep:
public static <T> ArrayAggOrderByStep<T[]> arrayAgg(Field<T> field) {
return new org.jooq.impl.Function<T[]>(Term.ARRAY_AGG, field.getDataType().getArrayDataType(), nullSafe(field));
}
Attempts
The closest I got to something reasonable is... building my own coalesceAggregation function that specifically coalesces aggregated fields:
// Can't quite use AggregateFunction there
// v v
public static <T> Field<T> coalesceAggregation(final Field<T> agg, final Condition coalesceWhen, #NonNull final T coalesceTo) {
return DSL.coalesce(DSL.field("{0} FILTER (WHERE {1})", agg.getType(), agg, coalesceWhen), coalesceTo);
}
public static <T> Field<T> coalesceAggregation(final Field<T> agg, #NonNull final T coalesceTo) {
return coalesceAggregation(agg, agg.isNotNull(), coalesceTo);
}
... But I then ran into issues with my T type being JsonNode, where DSL#coalesce seems to CAST my coalesceTo to varchar.
Or, you know:
DSL.field("COALESCE(jsonb_object_agg({0}, ({1})) FILTER (WHERE {0} IS NOT NULL), '{}')::jsonb", JSON_TYPE, key, select)
But that'd be the very last resort: it'd feel like I'd merely be one step away from letting the user inject any SQL they want into my database 🙄
In short
Is there a way in jOOQ to "properly" implement one's own aggregate function, as an actual org.jooq.AgregateFunction?
I'd like to avoid having it generated by jooq-codegen as much as possible (not that I don't like it – it's just our pipeline that's horrible).
Starting with jOOQ 3.14.0
The JSON_OBJECTAGG aggregate function is supported natively in jOOQ now:
DSL.jsonObjectAgg(TABLE.NAME, TABLE.VALUE).filterWhere(TABLE.NAME.isNotNull());
Support for the FILTER clause was added in jOOQ 3.14.8.
Starting with jOOQ 3.14.8 and 3.15.0
If jOOQ doesn't implement a specific aggregate function, you can now specify DSL.aggregate() to make use of custom aggregate functions.
DSL.aggregate("json_object_agg", SQLDataType.JSON, TABLE.NAME, TABLE.VALUE)
.filterWhere(TABLE.NAME.isNotNull());
This was implemented with https://github.com/jOOQ/jOOQ/issues/1729
Pre jOOQ 3.14.0
There's a missing feature in the jOOQ DSL API, namely to create plain SQL aggregate functions. The reason why this is not available yet (as of jOOQ 3.11) is because there are a lot of delicate internals to specifying a vendor agnostic aggregate function that supports all of the vendor-specific options including:
FILTER (WHERE ...) clause (as you mentioned in the question), which has to be emulated using CASE
OVER (...) clause to turn an aggregate function into a window function
WITHIN GROUP (ORDER BY ...) clause to support ordered set aggregate functions
DISTINCT clause, where supported
Other, vendor-specific extensions to aggregate functions
The easy workaround in your specific case is to use plain SQL templating all the way as you mentioned in your question as well:
DSL.field("COALESCE(jsonb_object_agg({0}, ({1})) FILTER (WHERE {0} IS NOT NULL), '{}')::jsonb", JSON_TYPE, key, select)
Or you do the thing you've mentioned previously. Regarding that concern:
... But I then ran into issues with my T type being JsonNode, where DSL#coalesce seems to CAST my coalesceTo to varchar.
That's probably because you used agg.getType() which returns Class<?> instead of agg.getDataType() which returns DataType<?>.
But that'd be the very last resort: it'd feel like I'd merely be one step away from letting the user inject any SQL they want into my database
I'm not sure why that is an issue here. You will still be able to control your plain SQL API usage yourself, and users won't be able to inject arbitrary things into key and select because you control those elements as well.

How to create a simple plugin in Neo4j?

I configured Maven and managed to run example-Plugins like FullTextIndex (https://github.com/neo4j-contrib/neo4j-rdf/blob/master/src/main/java/org/neo4j/rdf/fulltext/FulltextIndex.java).
Still I struggle to create a simple Function by myself. I want to have a java-function that can find a node by ID and return its properties.
I know I can do this in Cypher, but the target is to understand the logic of plugins for Neo4j.
So after importing the plugin i should be able to type in:
INPUT ID
call example.function(217)
OUTPUT e. g.
name = Tree, age = 85, label = Plant, location = Munich
Thanks a lot!
In Neo4j, user-defined procedures are simple .jar files that you will put in the $NEO4J_HOME/plugins directory. Logically, to create a new user-defined procedure you will need to generate this jar file. You can do it configuring a new maven project or using the repository Neo4j Procedure Template.
User-defined procedures are simply Java classes with methods annotated with #Procedure. If the procedure writes in the database then mode = WRITE should be defined (not your case).
Also you will need query the database to get the node by ID and return the properties. To do it you will need inject in your Java class the GraphDatabaseService class using the #Context annotation.
To achieve your goal, I believe that you will need to use the getNodeById() method from GraphDatabaseService and the getProperties() in the returned Node.
What you are looking for is User Defined Functions / Procedures. There is a dedicated section in the neo4j documentation :
https://neo4j.com/developer/procedures-functions/#_extending_cypher
http://neo4j.com/docs/developer-manual/current/extending-neo4j/procedures/#user-defined-procedures
You can also look at APOC which contains hundreds of such examples used in real life.
https://github.com/neo4j-contrib/neo4j-apoc-procedures

search using two filters in spring-data-elasticsearch java api

I'm trying to use filters in spring-data-elasticsearch java api. I understand that I can use andFilter to search based on two fields like this
builder.withFilter(FilterBuilders.andFilter(FilterBuilders.rangeFilter("DATE").gte(startDate).lt(endDate), FilterBuilders.boolFilter().mustNot(FilterBuilders.termFilter("STATUS", "ACTIVE"))));
but in the code i have some if conditions and thus I cannot use andFilter directly to search ... take a look at this example
if("MSGSTAT".equals("SENT")) {
builder.withFilter(FilterBuilders.rangeFilter("DATE").gte(startDate).lt(endDate));
}
if("STATUS".equals("ACTIVE")) {
builder.withFilter(FilterBuilders.boolFilter().mustNot(FilterBuilders.termFilter("STATUS", "ACTIVE")));
}
When I use filters in the above mentioned way it doesn't applies the and keyword and the result received is incorrect. I also tried to do it this way but it didn't help either
builder.withFilter(FilterBuilders.andFilter(FilterBuilders.rangeFilter("DATE").gte(startDate).lt(endDate)));
builder.withFilter(FilterBuilders.andFilter(FilterBuilders.boolFilter().mustNot(FilterBuilders.termFilter("STATUS", "ACTIVE"))));
How should I do it making sure that the AND aggregation is always applied when using if conditions
Got an answer ...
I created a reference variable of type AndFilterBuilder and added all my filters to it using the add() and then built the Query Builder
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
AndFilterBuilder filters = null;
filters = new AndFilterBuilder(<your filter>);
filters.add(<your filter>);
builder.withFilter(filters);
builder.build()

Using Jena Rules File on inferred model to create a validator for an ontology

What I want to do: Create a validator for an ontology in Java. For this I want to use Jena Rules on a inferred model. Unfortunately I can't use both the standard reasoner (ReasonerRegistry.getOWLReasoner()) and after this my own reasoner (new GenericRuleReasoner(Rule.rulesFromURL("file:rulefile.txt"))). Is this possible somehow?
The default ontological reasoning within Jena should provide decent validation of standard owl ontologies. The following explains how to use that same mechansism for domains that may skirt outside of what owl provides.
In order to have domain-specific conflicts be generated when using the GnericRuleReasoner, one needs to stimulate the generation of a domain-specific ValidityReport when FBRuleInfGraph.validate() is called.
This method introduces a triple to the inference graph:
728 Triple validateOn = new Triple(NodeFactory.createAnon(),
729 ReasonerVocabulary.RB_VALIDATION.asNode();
730 Functor.makeFunctorNode("on", new Node[] {}));
The idea behind this is that rules within the domain will be sensitive to the existance of this triple, and then generate a RB_VALIDATE_REPORT when a constraint of the domain fails.
Treating the existing OWL domain as an example of this, we can search for rules that signal a violation of OWL's domains-specific constraints (from etc/owl-fb.rules):
[validationIndiv2: (?v rb:validation on()) (?X owl:disjointWith ?Y) ->
[validationIndiv: (?I rb:violation error('conflict', 'Individual a member of disjoint classes', ?X, ?Y))
<- (?I rdf:type ?X), (?I rdf:type ?Y) noValue(?T rb:prototype ?I)] ]
This forward-chaining rule introduces a backward-chaining rule that expresses a rb:violation when an individual is a member of disjoint classes.
The answer from #Joshua is absolutely correct. The only thing you need to know is that you can parse the rdf reasoner to GenericRuleReasoner or the owl reasoner to OWLFBRuleReasoner. From GenericRuleReasoner/OWLFBRuleReasoner you can get the list of the rules.
List<Rule> rules = new ArrayList<>((OWLFBRuleReasoner)ReasonerRegistry.getOWLReasoner().getRules());
rules.addAll(Rule.rulesFromURL("file:JENA_RULES_FILE"));
GenericRuleReasoner completeReasoner = new GenericRuleReasoner(rules);

Categories