Hi,
I finally got the whole test working properly
To summarize:
1) Deploy the custom functions classes on fuseki server
2) Modify the fuseki config :
add [] ja:loadClass "io.bdrc.ldsearch.query.functions.MyFilter"
where MyFilter implementation is :
import org.apache.jena.sparql.expr.NodeValue;
import org.apache.jena.sparql.function.FunctionBase1;
public class MyFilter extends FunctionBase1 {
public MyFilter() { super() ; }
public NodeValue exec(NodeValue value1){
int d = value1.asString().length();
return NodeValue.makeInteger(new Integer(d));
}
}
3) add the following prefix to the context:
PREFIX f: <java:io.bdrc.ldsearch.query.functions.>
Note that "io.bdrc.ldsearch.query.functions is the package of MyFilter
class, not the class itself --> this means that you never call a class
method in sparql queries but only a class that implements
org.apache.jena.sparql.function.FunctionBaseX where X is the number of
argument of your filter function
4) Write (for instance) the query like this:
SELECT DISTINCT ?l
WHERE { ?x skos:prefLabel ?l .
FILTER (f:MyFilter(?l) < 20)
}
Thanks to Adam and Andy
Marc
Le mardi 26 décembre 2017 à 19:44 +0000, Andy Seaborne a écrit :
> > Exception in thread "main" HttpException: 404 at
> > org.apache.jena.sparql.engine.http.HttpQuery.execGet(HttpQuery.java
> > :328
> > )
>
> 404 - HTTP not found - when trying to call Fuseki - i.e. the query
> service URL is wrong. A server is running at the address (host:port)
> but
> the path does not name an HTTP resource.
>
> Andy
>
>
> On 26/12/17 19:00, ajs6f wrote:
> > I don't understand how that config is getting parsed at all. It's
> > not valid Turtle.
> >
> > > ja:loadClass
> > > "io.bdrc.ldsearch.query.functions.CustomARQFunctions" .
> >
> > is not a triple at all. It should probably be:
> >
> > [] ja:loadClass
> > "io.bdrc.ldsearch.query.functions.CustomARQFunctions" .
> >
> > Riot gives "Expected IRI for predicate: got:
> > [STRING:io.bdrc.ldsearch.query.functions.CustomARQFunctions]"
> >
> > It's not clear to me how you could be successfully loading your
> > extension function with invalid config.
> >
> > Adam Soroka
> >
> >
> > > On Dec 26, 2017, at 1:42 PM, Marc Agate <[email protected]>
> > > wrote:
> > >
> > > Well...
> > >
> > > Here is the query
> > >
> > > PREFIX : <http://purl.bdrc.io/ontology/core/>
> > > PREFIX adm: <http://purl.bdrc.io/ontology/admin/>
> > > PREFIX bdr: <http://purl.bdrc.io/resource/>
> > > PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
> > > PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
> > > PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
> > > PREFIX tbr: <http://purl.bdrc.io/ontology/toberemoved/>
> > > PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
> > > PREFIX f:
> > > <java:io.bdrc.ldsearch.query.functions.CustomARQFunctions.>
> > >
> > > SELECT DISTINCT ?l
> > > WHERE {
> > > ?x skos:prefLabel ?l .
> > > FILTER (f:myFilter(?l) < 100)
> > > }
> > >
> > > Note that whene I change FILTER (f:myFilter(?l) < 100) to FILTER
> > > (STRLEN(?l) < 100), I don't get the 404 exception...
> > > Therefore it's not a connection issue. I thing it's more like a
> > > unresolved URI or so.
> > >
> > > Now, since you'are asking for it, here is the full fuseki config:
> > >
> > > ################################################################
> > > # Fuseki configuration for BDRC, configures two endpoints:
> > > # - /bdrc is read-only
> > > # - /bdrcrw is read-write
> > > #
> > > # This was painful to come up with but the web interface
> > > basically
> > > allows no option
> > > # and there is no subclass inference by default so such a
> > > configuration
> > > file is necessary.
> > > #
> > > # The main doc sources are:
> > > # - https://jena.apache.org/documentation/fuseki2/fuseki-configu
> > > ration
> > > .html
> > > # - https://jena.apache.org/documentation/assembler/assembler-ho
> > > wto.ht
> > > ml
> > > # - https://jena.apache.org/documentation/assembler/assembler.tt
> > > l
> > > #
> > > # See https://jena.apache.org/documentation/fuseki2/fuseki-layout
> > > .html
> > > for the destination of this file.
> > >
> > > @prefix fuseki: <http://jena.apache.org/fuseki#> .
> > > @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
> > > @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
> > > @prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
> > > # @prefix tdb2: <http://jena.apache.org/2016/tdb#> .
> > > @prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
> > > @prefix : <http://base/#> .
> > > @prefix text: <http://jena.apache.org/text#> .
> > > @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
> > > @prefix adm: <http://purl.bdrc.io/ontology/admin/> .
> > > @prefix bdd: <http://purl.bdrc.io/data/> .
> > > @prefix bdo: <http://purl.bdrc.io/ontology/core/> .
> > > @prefix bdr: <http://purl.bdrc.io/resource/> .
> > > @prefix f:
> > > <java:io.bdrc.ldsearch.query.functions.CustomARQFunctions.>
> > > .
> > >
> > > ja:loadClass
> > > "io.bdrc.ldsearch.query.functions.CustomARQFunctions" .
> > > # [] ja:loadClass "org.seaborne.tdb2.TDB2" .
> > > # tdb2:DatasetTDB2 rdfs:subClassOf ja:RDFDataset .
> > > # tdb2:GraphTDB2 rdfs:subClassOf ja:Model .
> > >
> > > [] rdf:type fuseki:Server ;
> > > fuseki:services (
> > > :bdrcrw
> > > # :bdrcro
> > > ) .
> > >
> > > :bdrcrw rdf:type fuseki:Service ;
> > > fuseki:name "bdrcrw" ; # name of
> > > the
> > > dataset in the url
> > > fuseki:serviceQuery "query" ; # SPARQL
> > > query
> > > service
> > > fuseki:serviceUpdate "update" ; # SPARQL
> > > update
> > > service
> > > fuseki:serviceUpload "upload" ; # Non-SPARQL
> > > upload
> > > service
> > > fuseki:serviceReadWriteGraphStore "data" ; # SPARQL
> > > Graph store
> > > protocol (read and write)
> > > fuseki:dataset :bdrc_text_dataset ;
> > > .
> > >
> > > # :bdrcro rdf:type fuseki:Service ;
> > > # fuseki:name "bdrc" ;
> > > # fuseki:serviceQuery "query" ;
> > > # fuseki:serviceReadGraphStore "data" ;
> > > # fuseki:dataset :bdrc_text_dataset
> > > ;
> > > # .
> > >
> > > # using TDB
> > > :dataset_bdrc rdf:type tdb:DatasetTDB ;
> > > tdb:location "/etc/fuseki/databases/bdrc" ;
> > > tdb:unionDefaultGraph true ;
> > > .
> > >
> > > # # try using TDB2
> > > # :dataset_bdrc rdf:type tdb2:DatasetTDB2 ;
> > > # tdb2:location "/etc/fuseki/databases/bdrc" ;
> > > # tdb2:unionDefaultGraph true ;
> > > # .
> > >
> > > :bdrc_text_dataset rdf:type text:TextDataset ;
> > > text:dataset :dataset_bdrc ;
> > > text:index :bdrc_lucene_index ;
> > > .
> > >
> > > # Text index description
> > > :bdrc_lucene_index a text:TextIndexLucene ;
> > > text:directory <file:/etc/fuseki/lucene-bdrc> ;
> > > text:storeValues true ;
> > > text:multilingualSupport true ;
> > > text:entityMap :bdrc_entmap ;
> > > text:defineAnalyzers (
> > > [ text:addLang "bo" ;
> > > text:analyzer [
> > > a text:GenericAnalyzer ;
> > > text:class "io.bdrc.lucene.bo.TibetanAnalyzer" ;
> > > text:params (
> > > [ text:paramName "segmentInWords" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue false ]
> > > [ text:paramName "lemmatize" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue true ]
> > > [ text:paramName "filterChars" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue false ]
> > > [ text:paramName "fromEwts" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue false ]
> > > )
> > > ] ;
> > > ]
> > > [ text:addLang "bo-x-ewts" ;
> > > text:analyzer [
> > > a text:GenericAnalyzer ;
> > > text:class "io.bdrc.lucene.bo.TibetanAnalyzer" ;
> > > text:params (
> > > [ text:paramName "segmentInWords" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue false ]
> > > [ text:paramName "lemmatize" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue true ]
> > > [ text:paramName "filterChars" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue false ]
> > > [ text:paramName "fromEwts" ;
> > > text:paramType text:TypeBoolean ;
> > > text:paramValue true ]
> > > )
> > > ] ;
> > > ]
> > > ) ;
> > > .
> > >
> > > # Index mappings
> > > :bdrc_entmap a text:EntityMap ;
> > > text:entityField "uri" ;
> > > text:uidField "uid" ;
> > > text:defaultField "label" ;
> > > text:langField "lang" ;
> > > text:graphField "graph" ; ## enable graph-specific
> > > indexing
> > > text:map (
> > > [ text:field "label" ;
> > > text:predicate skos:prefLabel ]
> > > [ text:field "altLabel" ;
> > > text:predicate skos:altLabel ; ]
> > > [ text:field "rdfsLabel" ;
> > > text:predicate rdfs:label ; ]
> > > [ text:field "chunkContents" ;
> > > text:predicate bdo:chunkContents ; ]
> > > [ text:field "eTextTitle" ;
> > > text:predicate bdo:eTextTitle ; ]
> > > [ text:field "logMessage" ;
> > > text:predicate adm:logMessage ; ]
> > > [ text:field "noteText" ;
> > > text:predicate bdo:noteText ; ]
> > > [ text:field "workAuthorshipStatement" ;
> > > text:predicate bdo:workAuthorshipStatement ; ]
> > > [ text:field "workColophon" ;
> > > text:predicate bdo:workColophon ; ]
> > > [ text:field "workEditionStatement" ;
> > > text:predicate bdo:workEditionStatement ; ]
> > > [ text:field "workPublisherLocation" ;
> > > text:predicate bdo:workPublisherLocation ; ]
> > > [ text:field "workPublisherName" ;
> > > text:predicate bdo:workPublisherName ; ]
> > > [ text:field "workSeriesName" ;
> > > text:predicate bdo:workSeriesName ; ]
> > > ) ;
> > > .
> > > #################################################################
> > > ##
> > >
> > > It would be wonderful to have the java:URI scheme thing working
> > > (all
> > > custom functions in a single class and method calls done directly
> > > in
> > > the sparql query : sounds like a dream !)
> > >
> > > Marc
> > >
> > > Le mardi 26 décembre 2017 à 13:22 -0500, ajs6f a écrit :
> > > > That exception doesn't appear to have anything to do with
> > > > extension
> > > > functions. It indicates a problem between client and server.
> > > >
> > > > Please show at _least_ your actual query execution code, your
> > > > complete Fuseki config, and a complete stacktrace.
> > > >
> > > >
> > > > ajs6f
> > > >
> > > > > On Dec 26, 2017, at 1:17 PM, Marc Agate <[email protected]
> > > > > >
> > > > > wrote:
> > > > >
> > > > > I forgot to mention that according to
> > > > > https://jena.apache.org/documentation/query/java-uri.html
> > > > > I tried for testing purpose to set a PREFIX f:
> > > > > <java:io.bdrc.ldsearch.query.functions.CustomARQFunctions.>an
> > > > > d
> > > > > added
> > > > > the following to fuseki config :
> > > > > ja:loadClass
> > > > > "io.bdrc.ldsearch.query.functions.CustomARQFunctions"
> > > > > .
> > > > > where CustomARQFunctions is :
> > > > > public class CustomARQFunctions { public
> > > > > static
> > > > > NodeValue myFilter(NodeValue value1){
> > > > > int i
> > > > > =
> > > > > value1.asString().length(); return
> > > > > NodeValue.makeInteger(i); }
> > > > > }
> > > > > since according to
> > > > > https://jena.apache.org/documentation/query/writing_functions
> > > > > .html
> > > > > using the java:URI scheme "dynamically loads the code, which
> > > > > must
> > > > > be on
> > > > > the Java classpath. With this scheme, the function URI gives
> > > > > the
> > > > > class
> > > > > name. There is automatic registration of a wrapper into the
> > > > > function
> > > > > registry. This way, no explicit registration step is needed
> > > > > by the
> > > > > application and queries issues with the command line tools
> > > > > can load
> > > > > custom functions."
> > > > > but no luck: I keep getting the following exception:
> > > > > Exception in thread "main" HttpException: 404 at
> > > > > org.apache.jena.sparql.engine.http.HttpQuery.execGet(HttpQuer
> > > > > y.java
> > > > > :328
> > > > > ) at
> > > > > org.apache.jena.sparql.engine.http.HttpQuery.exec(HttpQuery.j
> > > > > ava:28
> > > > > 8)
> > > > > at
> > > > > org.apache.jena.sparql.engine.http.QueryEngineHTTP.execResult
> > > > > SetInn
> > > > > er(Q
> > > > > ueryEngineHTTP.java:348) at
> > > > > org.apache.jena.sparql.engine.http.QueryEngineHTTP.execSelect
> > > > > (Query
> > > > > Engi
> > > > > neHTTP.java:340)
> > > > > I am stuck !
> > > > > Marc
> > > > > Le mardi 26 décembre 2017 à 18:56 +0100, Marc Agate a écrit :
> > > > > > Hi,
> > > > > > Adam's gave me the right direction.
> > > > > > I managed to load my function class in fuseki config using
> > > > > > ja:loadClass
> > > > > > but now remains the following issue (the function is not
> > > > > > registered)seefuseki logs :
> > > > > > [2017-12-26 16:10:13] exec WARN URI <http://purl.bdr
> > > > > > c.io/f
> > > > > > unct
> > > > > > ions#MyFilterFunction> has no registered function factory
> > > > > > How can I register this function now that I have the code
> > > > > > available
> > > > > > onthe endpoint side ?
> > > > > > Thanks for helping
> > > > > > Marc.
> > > > > >
> > > > > > Le mardi 26 décembre 2017 à 17:43 +0000, Andy Seaborne a
> > > > > > écrit :
> > > > > > > As well s Adam's point (and all the libraries your
> > > > > > > function
> > > > > > > needs, transitively)
> > > > > > > What is in the Fuseki log file?How was the data loaded
> > > > > > > into
> > > > > > > Fuseki?
> > > > > > > >> I printed out the >> FunctionRegistry
> > > > > > > And
> > > > > > > On 26/12/17 14:51, ajs6f wrote:
> > > > > > > > I'm not as familiar with the extension points of ARQ as
> > > > > > > > I
> > > > > > > > wouldlike to be, but as I understand what you are
> > > > > > > > doing, you
> > > > > > > > areregistering a new function with your _local_
> > > > > > > > registry,
> > > > > > > > then
> > > > > > > > firinga query at a _remote_ endpoint (which has a
> > > > > > > > completely
> > > > > > > > independentregistry in a different JVM in a different
> > > > > > > > process,
> > > > > > > > potentially ina different _system_).
> > > > > > > > The query is getting interpreted and executed by that
> > > > > > > > remoteservice, not locally. So you need to register the
> > > > > > > > function
> > > > > > > > _there_.
> > > > > > > > Take a look at this thread:
> > > > > > > > https://lists.apache.org/thread.html/1cda23332af4264883
> > > > > > > > e88697
> > > > > > > > d994
> > > > > > > > 605770edcde2f93ddea51240e4b8@%3Cusers.jena.apache.org%3
> > > > > > > > E
> > > > > > > > It should get you started as to how to register
> > > > > > > > extensionfunctionality in Fuseki.
> > > > > > > >
> > > > > > > > Adam Soroka
> > > > > > > > > On Dec 26, 2017, at 9:34 AM, Marc Agate <agate.marc@g
> > > > > > > > > mail.c
> > > > > > > > > om>
> > > > > > > > > wrote:
> > > > > > > > >
> > > > > > > > > Hi !
> > > > > > > > >
> > > > > > > > > I successfully implemented sparql queries using
> > > > > > > > > custom ARQ
> > > > > > > > > functions
> > > > > > > > > using the following (custom function code):
> > > > > > > > >
> > > > > > > > > ****************
> > > > > > > > > public class LevenshteinFilter extends FunctionBase2
> > > > > > > > > {
> > > > > > > > >
> > > > > > > > > public LevenshteinFilter() { super() ; }
> > > > > > > > >
> > > > > > > > > public NodeValue exec(NodeValue value1,
> > > > > > > > > NodeValue
> > > > > > > > > value2){
> > > > > > > > > LevenshteinDistance LD=new
> > > > > > > > > LevenshteinDistance();
> > > > > > > > > int i = LD.apply(value1.asString(),
> > > > > > > > > value2.asString());
> > > > > > > > > return NodeValue.makeInteger(i);
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > > ***************
> > > > > > > > >
> > > > > > > > > it works fine when I query against a Model loaded
> > > > > > > > > from a
> > > > > > > > > turtle
> > > > > > > > > file,
> > > > > > > > > like this:
> > > > > > > > >
> > > > > > > > > ***************
> > > > > > > > > InputStream input =
> > > > > > > > > QueryProcessor.class.getClassLoader().getResourceAsSt
> > > > > > > > > ream("
> > > > > > > > > full
> > > > > > > > > .t
> > > > > > > > > tl");
> > > > > > > > > model =
> > > > > > > > > ModelFactory.createMemModelMaker().createModel("defau
> > > > > > > > > lt");
> > > > > > > > > model.read(input,null,"TURTLE"); //
> > > > > > > > > null base
> > > > > > > > > URI,
> > > > > > > > > since
> > > > > > > > > model URIs are absolute
> > > > > > > > > input.close();
> > > > > > > > > ***************
> > > > > > > > >
> > > > > > > > > with the query being sent like this :
> > > > > > > > >
> > > > > > > > > ***************
> > > > > > > > > String functionUri = "http://www.example1.org/Levensh
> > > > > > > > > teinFu
> > > > > > > > > ncti
> > > > > > > > > on
> > > > > > > > > ";
> > > > > > > > > FunctionRegistry.get().put(functionUri ,
> > > > > > > > > LevenshteinFilter.class);
> > > > > > > > >
> > > > > > > > > String s = "whatever you want";
> > > > > > > > > String sparql = prefixes+" SELECT DISTINCT
> > > > > > > > > ?l
> > > > > > > > > WHERE {
> > > > > > > > > ?x
> > > > > > > > > rdfs:label ?l . "
> > > > > > > > > + "FILTER(fct:LevenshteinFunction(?l,
> > > > > > > > > \"" +
> > > > > > > > > s
> > > > > > > > > + "\")
> > > > > > > > > < 4) }";
> > > > > > > > > Query query = QueryFactory.create(sparql);
> > > > > > > > > QueryExecution qexec =
> > > > > > > > > QueryExecutionFactory.create(query,
> > > > > > > > > model);
> > > > > > > > > ResultSet rs = qexec.execSelect();
> > > > > > > > > ***************
> > > > > > > > >
> > > > > > > > > However, if i use a working fuseki endpoint for the
> > > > > > > > > same
> > > > > > > > > dataset
> > > > > > > > > (full.ttl) like this :
> > > > > > > > >
> > > > > > > > > ***************
> > > > > > > > > fusekiUrl="http://localhost:3030/ds/query";
> > > > > > > > > ***************
> > > > > > > > >
> > > > > > > > > sending the query like this (using
> > > > > > > > > QueryExecutionFactory.sparqlService(fusekiUrl,query)
> > > > > > > > > instead of
> > > > > > > > > QueryExecutionFactory.create(query,model) ):
> > > > > > > > >
> > > > > > > > > ***************
> > > > > > > > > String functionUri = "http://www.example1.org/Levensh
> > > > > > > > > teinFu
> > > > > > > > > ncti
> > > > > > > > > on
> > > > > > > > > ";
> > > > > > > > > FunctionRegistry.get().put(functionUri ,
> > > > > > > > > LevenshteinFilter.class);
> > > > > > > > >
> > > > > > > > > String s = "whatever you want";
> > > > > > > > > String sparql = prefixes+" SELECT DISTINCT
> > > > > > > > > ?l
> > > > > > > > > WHERE {
> > > > > > > > > ?x
> > > > > > > > > rdfs:label ?l . " +
> > > > > > > > > "FILTER(fct:LevenshteinFunction(?l, \""
> > > > > > > > > + s
> > > > > > > > > +
> > > > > > > > > "\")
> > > > > > > > > < 4) }";
> > > > > > > > > Query query = QueryFactory.create(sparql);
> > > > > > > > > QueryExecution qexec =
> > > > > > > > > QueryExecutionFactory.sparqlService(fusekiUrl,query);
> > > > > > > > > ResultSet rs = qexec.execSelect();
> > > > > > > > > ***************
> > > > > > > > >
> > > > > > > > > Then I don't get any results back. In both cases I
> > > > > > > > > printed
> > > > > > > > > out
> > > > > > > > > the
> > > > > > > > > FunctionRegistry and they contain exactly the same
> > > > > > > > > entries,
> > > > > > > > > especially
> > > > > > > > > :
> > > > > > > > >
> > > > > > > > > key=http://www.example1.org/LevenshteinFunction
> > > > > > > > > value:
> > > > > > > > > org.apache.jena.sparql.function.FunctionFactoryAuto@5
> > > > > > > > > a45133
> > > > > > > > > e
> > > > > > > > >
> > > > > > > > > Any clue ?
> > > > > > > > >
> > > > > > > > > Thanks
> > > >
> > > >