csvsparqlrdflinked-datarml-rdf

RML and FnO fails to run together


I am trying to use FnO functions in RML mapper (I like to do a string_split like here). This is how my folder looks like:

enter image description here

I am executing java -jar "rmlmapper.jar" -m mapping-cuisines.ttl -o output-cuisines.ttl -s turtle

However, when I try implementing a <#FunctionMap> i get the following error message:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
        at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
        at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
        at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
        at java.base/java.util.Objects.checkIndex(Objects.java:372)
        at java.base/java.util.ArrayList.get(ArrayList.java:458)
        at be.ugent.rml.functions.DynamicMultipleRecordsFunctionExecutor.execute(DynamicMultipleRecordsFunctionExecutor.java:66)
        at be.ugent.rml.functions.AbstractSingleRecordFunctionExecutor.execute(AbstractSingleRecordFunctionExecutor.java:17)
        at be.ugent.rml.termgenerator.LiteralGenerator.generate(LiteralGenerator.java:42)
        at be.ugent.rml.Executor.generatePredicateObjectGraphs(Executor.java:157)
        at be.ugent.rml.Executor.executeWithFunction(Executor.java:115)
        at be.ugent.rml.Executor.execute(Executor.java:76)
        at be.ugent.rml.cli.Main.main(Main.java:206)

Nothing makes sense to me. According to the git repo, the functions are loaded dynamically from where i execute the rmlmapper.

Dataset: https://mega.nz/file/LsJAQRaR#84lfASPXVA08zm0RbuRfNvR7tx-vklS82D1KBGhhdA8

My Code:

@base <http://example.org/data> .
@prefix ex: <http://example.org/ns#> .
@prefix rr: <http://www.w3.org/ns/r2rml#> .
@prefix rml: <http://semweb.mmlab.be/ns/rml#> .
@prefix ql: <http://semweb.mmlab.be/ns/ql#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix csvw: <http://www.w3.org/ns/csvw#> .
@prefix fnml: <http://semweb.mmlab.be/ns/fnml#> .
@prefix fno: <https://w3id.org/function/ontology#> .
@prefix grel: <http://users.ugent.be/~bjdmeest/function/grel.ttl#> .


<#LogicalSource>
    a rml:LogicalSource;
    rml:source "dataworld-restaurants-cuisines.csv";
    rml:referenceFormulation ql:CSV.


<#MyTriplesMap>
    a rr:TriplesMap;
    rml:logicalSource <#LogicalSource>;

    rr:subjectMap [
        rr:template "http://example.org/{id}";
    ];

    rr:predicateObjectMap [
        rr:predicate ex:aProperty;
        rr:objectMap <#FunctionMap>;
    ].

<#FunctionMap>
    fnml:functionValue [
        rml:logicalSource <#LogicalSource> ;
        rr:predicateObjectMap [
            rr:predicate fno:executes ;
            rr:objectMap [ rr:constant grel:toUpperCase ]
        ] ;
        rr:predicateObjectMap [
            rr:predicate grel:valueParameter ;                  
            rr:objectMap [
                rml:reference "spicy"                           
            ]
        ]
    ] .

My functions.ttl:

@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix doap:    <http://usefulinc.com/ns/doap#> .
@prefix fno:     <https://w3id.org/function/ontology#> .
@prefix fnoi:    <https://w3id.org/function/vocabulary/implementation#> .
@prefix fnom:    <https://w3id.org/function/vocabulary/mapping#> .
@prefix grel:    <http://users.ugent.be/~bjdmeest/function/grel.ttl#> .
@prefix grelm:   <http://fno.io/grel/rmlmapping#> .
@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .

grel:toUpperCase a fno:Function ;
  fno:name "to Uppercase" ;
  rdfs:label "to Uppercase" ;
  dcterms:description "Returns the input with all letters in upper case." ;
  fno:expects ( grel:valueParam ) ;
  fno:returns ( grel:stringOut ) .

grelm:javaString
    a                  fnoi:JavaClass ;
    doap:download-page "GrelFunctions.jar" ;
    fnoi:class-name    "io.fno.grel.StringFunctions" .

grelm:uppercaseMapping
    a                    fnoi:Mapping ;
    fno:function         grel:toUpperCase ;
    fno:implementation   grelm:javaString ;
    fno:methodMapping    [ a                fnom:StringMethodMapping ;
                           fnom:method-name "toUppercase" ] .

Solution

  • I tried out your mapping file and it works correctly. Your current mapping file transforms the data in the spicy to upper case and generates the specified RDF triples. Since the function grel:toUpperCase is included in the RMLMapper by default, you don't need to functions.ttl to specify these functions. This is only necessary if you want to add your own custom functions. An overview of all included functions in the RMLMapper can be found here: https://rml.io/docs/rmlmapper/default-functions/

    Given example

    1. Download the latest RMLMapper from our Github repository: https://github.com/RMLio/rmlmapper-java/releases
    2. Run it as: java -jar <path to jar> -m mapping.rml.ttl
    3. I get the output which is listed below.

    mapping.rml.ttl

    @base <http://example.org/data> .
    @prefix ex: <http://example.org/ns#> .
    @prefix rr: <http://www.w3.org/ns/r2rml#> .
    @prefix rml: <http://semweb.mmlab.be/ns/rml#> .
    @prefix ql: <http://semweb.mmlab.be/ns/ql#> .
    @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
    @prefix owl: <http://www.w3.org/2002/07/owl#> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix csvw: <http://www.w3.org/ns/csvw#> .
    @prefix fnml: <http://semweb.mmlab.be/ns/fnml#> .
    @prefix fno: <https://w3id.org/function/ontology#> .
    @prefix grel: <http://users.ugent.be/~bjdmeest/function/grel.ttl#> .
    
    
    <#LogicalSource>
        a rml:LogicalSource;
        rml:source "dataworld-restaurants-cuisines.csv";
        rml:referenceFormulation ql:CSV.
    
    
    <#MyTriplesMap>
        a rr:TriplesMap;
        rml:logicalSource <#LogicalSource>;
    
        rr:subjectMap [
            rr:template "http://example.org/{id}";
        ];
    
        rr:predicateObjectMap [
            rr:predicate ex:aProperty;
            rr:objectMap <#FunctionMap>;
        ].
    
    <#FunctionMap>
        fnml:functionValue [
            rml:logicalSource <#LogicalSource> ;
            rr:predicateObjectMap [
                rr:predicate fno:executes ;
                rr:objectMap [ rr:constant grel:toUpperCase ]
            ] ;
            rr:predicateObjectMap [
                rr:predicate grel:valueParameter ;                  
                rr:objectMap [
                    rml:reference "spicy"                           
                ]
            ]
        ] .
    

    Output (truncated)

    <http://example.org/afghani> <http://example.org/ns#aProperty> "NO".
    <http://example.org/african> <http://example.org/ns#aProperty> "YES".
    <http://example.org/african_portuguese> <http://example.org/ns#aProperty> "YES".
    <http://example.org/american> <http://example.org/ns#aProperty> "NO".
    <http://example.org/andhra> <http://example.org/ns#aProperty> "YES".
    <http://example.org/arabian> <http://example.org/ns#aProperty> "NO".
    <http://example.org/arabian_lebanese> <http://example.org/ns#aProperty> "NO".
    <http://example.org/arabian_mexican> <http://example.org/ns#aProperty> "NO".
    <http://example.org/arabian_middle_eastern> <http://example.org/ns#aProperty> "YES".
    <http://example.org/asian> <http://example.org/ns#aProperty> "YES".
    <http://example.org/assamese> <http://example.org/ns#aProperty> "NO".
    <http://example.org/australian> <http://example.org/ns#aProperty> "YES".
    <http://example.org/awadhi> <http://example.org/ns#aProperty> "YES".
    <http://example.org/awadhi_mughlai> <http://example.org/ns#aProperty> "NO".
    <http://example.org/bakery> <http://example.org/ns#aProperty> "NO".
    

    FnO string_split

    If you want to use a FnO's string_split in RML, you can achieve it like this:

    1. fno:executes: grel:string_split to use the GREL split function.
    2. grel:valueParameter: the input string you want to split. I referenced here to the CSV column cuisines.
    3. grel:p_string_sep: the string separator on which the GREL split function must split the input string. I used , here to separate the different cuisines for each restaurant.

    mapping.rml.ttl

    @base <http://example.org> .
    @prefix rml: <http://semweb.mmlab.be/ns/rml#> .
    @prefix rr: <http://www.w3.org/ns/r2rml#> .
    @prefix ql: <http://semweb.mmlab.be/ns/ql#> .
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix fnml: <http://semweb.mmlab.be/ns/fnml#> .
    @prefix fno: <https://w3id.org/function/ontology#> .
    @prefix grel: <http://users.ugent.be/~bjdmeest/function/grel.ttl#> .
    @prefix ex: <http://example.org/ns#> .
    
    <#LogicalSource>
        a rml:LogicalSource;
        rml:source "dataworld-restaurants-cuisines.csv";
        rml:referenceFormulation ql:CSV.
    
    
    <#MyTriplesMap>
        a rr:TriplesMap;
        rml:logicalSource <#LogicalSource>;
    
        rr:subjectMap [
            rr:template "http://example.org/{id}";
        ];
    
        rr:predicateObjectMap [
            rr:predicate ex:cuisine;
            rr:objectMap <#FunctionMap>;
        ];
    .
    
    <#FunctionMap>
        fnml:functionValue [
            rml:logicalSource <#LogicalSource>;
            rr:predicateObjectMap [
                rr:predicate fno:executes; 
                rr:objectMap [ 
                    rr:constant grel:string_split 
                ];
            ];
            rr:predicateObjectMap [
                rr:predicate grel:valueParameter;
                rr:objectMap [ 
                    rml:reference "cuisines" 
                ];
            ];
            rr:predicateObjectMap [
                rr:predicate grel:p_string_sep;
                rr:objectMap [ 
                    rr:constant ", ";
                ];
            ];
        ].
    
    

    Output (truncated)

    <http://example.org/afghani> <http://example.org/ns#cuisine> "Afghani".
    <http://example.org/african> <http://example.org/ns#cuisine> "African".
    <http://example.org/african_portuguese> <http://example.org/ns#cuisine> "African".
    <http://example.org/african_portuguese> <http://example.org/ns#cuisine> "Portuguese".
    <http://example.org/american> <http://example.org/ns#cuisine> "american".
    <http://example.org/andhra> <http://example.org/ns#cuisine> "Andhra".
    <http://example.org/arabian> <http://example.org/ns#cuisine> "Arabian".
    <http://example.org/arabian_lebanese> <http://example.org/ns#cuisine> "Arabian".
    <http://example.org/arabian_lebanese> <http://example.org/ns#cuisine> "Lebanese".
    <http://example.org/arabian_mexican> <http://example.org/ns#cuisine> "Arabian".
    <http://example.org/arabian_mexican> <http://example.org/ns#cuisine> "Mexican".
    <http://example.org/arabian_middle_eastern> <http://example.org/ns#cuisine> "Arabian".
    <http://example.org/arabian_middle_eastern> <http://example.org/ns#cuisine> "Middle Eastern".
    <http://example.org/asian> <http://example.org/ns#cuisine> "Asian".
    <http://example.org/assamese> <http://example.org/ns#cuisine> "Assamese".
    <http://example.org/australian> <http://example.org/ns#cuisine> "Australian".
    <http://example.org/awadhi> <http://example.org/ns#cuisine> "Awadhi".
    <http://example.org/awadhi_mughlai> <http://example.org/ns#cuisine> "Awadhi".
    <http://example.org/awadhi_mughlai> <http://example.org/ns#cuisine> "Mughlai".
    <http://example.org/bakery> <http://example.org/ns#cuisine> "bakery".
    <http://example.org/bar_food> <http://example.org/ns#cuisine> "Bar Food".
    <http://example.org/bar_food_brazilian> <http://example.org/ns#cuisine> "Bar Food".
    <http://example.org/bar_food_brazilian> <http://example.org/ns#cuisine> "Brazilian".
    

    Note: I work on RML and FnO technologies