Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function term map alternative #45

Closed
wants to merge 15 commits into from
Closed

Conversation

bjdmeest
Copy link
Member

No description provided.

FNML/definitions.md Outdated Show resolved Hide resolved
FNML/overview.md Outdated

<a>FnO</a> consists of -- among others -- <a>function descriptions</a> and <a>execution</a> descriptions.
We describe these <a>executions</a> -- which link to specific <a>function descriptions</a> -- within the <a>RML mapping</a>.

The <a>RML processor</a> then needs to interpret these <a>executions</a> correctly to know which values to assign to the parameters of the function.
After executing the correct function, the <a>RML processor</a> SHOULD return the resulting value, to be used for further processing by the <a>RML processor</a>.
A [=triples map=] is a rule that maps each iteration in the logical source to a number of RDF triples.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

restating the definition here is unnecessary

FNML/ontology.md Outdated
<dfn class="lint-ignore">fnml:function</dfn> connects the [fnml:Execution] with an FnO [=function description=].
It has domain [=fnml:Execution=] and range [fno:Function](https://w3id.org/function/ontology#Function).

### fnml:predicate
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why fnml:predicate? I see the symmetry between the naming in FnO, but I think something like fnml:parameter or fnml:paramName would be clearer and also less coupled to FnO.

within the `<#NameMapping>`
After execution, the `grel:stringOutput` result of that function is returned to generate the object
within the `<#NameMapping>`.
We make use of an intermediate `<#ExecutionTermMap>` so that we can reuse the output of an execution in multiple TermMaps.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does reusing the output of an execution entail?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or do you mean the mapping definition of the execution?

Copy link
Member Author

@bjdmeest bjdmeest Mar 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both: if an execution returns multiple outputs (eg, a result and a status code), by referring to the same execution, you can use both outputs in different locations of the same mapping. If you don't reuse, you can't specify the difference between 'using 2 outputs from one execution' vs 'use a different output from 2 executions'. See example below for both cases (the latter one quite artificial, I know)

ex:parseNameToFirstAndLastName a fno:Function ;
    fno:name "parses a name into first name and last name, e.g. 'Ben De Meester' becomes {firstname: 'Ben', lastname: 'De Meester'}" ;
    fno:expects ( [ fno:predicate grel:stringInput ] ) ;
    fno:output ( [ fno:predicate grel:firstnameOutput ] [ fno:predicate grel:firstnameOutput ] ) .

<#Person_Mapping>
    rml:logicalSource <#LogicalSource> ;
    rr:subjectMap <#SubjectMap> ;
    rr:predicateObjectMap <#FirstNameMapping> , <#LastNameMapping>, <#RandomWordMapping1> , <#RandomWordMapping2> ,

<#FirstNameMapping>
    rr:predicate foaf:firstname ;
    rr:objectMap <#ExecutionTermMapFirst> .

<#LastNameMapping>
    rr:predicate foaf:lastname ;
    rr:objectMap <#ExecutionTermMapLast> .

<#RandomWordMapping1>
    rr:predicate ex:randomWord1 ;
    rr:objectMap <#ExecutionRandom1> .

<#RandomWordMapping2>
    rr:predicate ex:randomWord2 ;
    rr:objectMap <#ExecutionRandom2> .
    

<#ExecutionTermMapFirst> a fnml:ExecutionTermMap ;
    fnml:execution <#Execution> ;                    # By referring to the same execution, I can specify to reuse the result of one execution
    fnml:output ex:firstnameOutput .

<#ExecutionTermMapFirst> a fnml:ExecutionTermMap ;
    fnml:execution <#Execution> ;
    fnml:output ex:lastnameOutput .

<#Execution> a fnml:Execution ;
    fnml:function ex:parseNameToFirstAndLastName ;
    fnml:inputParameters
        [
            a fnml:ParameterTermMap ;
            fnml:predicate grel:stringInput ;
            rr:reference "name" .
        ] .

<#ExecutionTermRandom1> a fnml:ExecutionTermMap ;
    fnml:execution <#ExecutionRandom1> ;                    # Without an Execution, I cannot specify I want to execute `ex:take2RandomWords` twice
    fnml:output ex:out1 .

<#ExecutionTermRandom2> a fnml:ExecutionTermMap ;
    fnml:execution <#ExecutionRandom2> ;
    fnml:output ex:out2 .

<#ExecutionRandom1> a fnml:Execution ;
    fnml:function ex:take2RandomWords ;
    fnml:inputParameters
        [
            a fnml:ParameterTermMap ;
            fnml:predicate grel:stringInput ;
            rr:reference "name" .
        ] .

<#ExecutionRandom2> a fnml:Execution ;
    fnml:function ex:take2RandomWords ;
    fnml:inputParameters
        [
            a fnml:ParameterTermMap ;
            fnml:predicate grel:stringInput ;
            rr:reference "name" .
        ] .

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see.
Hmm, but so in this approach we would need to use IRI of the Execution(Map) to identify a specific execution. I don't think the name (IRI / blanknode id) of a mapping construct is used liked this anywhere else in the language. I also don't think we should assign meaning to the naming of mapping constructs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we support the 'use a different output from 2 executions' in another way? Or should we not overanalyze?

Note: I made a typo in the example, I now clarified the difference between eg ExecutionTermRandom1 and ExecutionRandom1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is that in your initial clarification <#Execution> has no subject map, but you seem to imply that the IRI / BNode id of the mapping construct <#Execution> should be used to indicate that the function execution is the same.

So, if you were to generate FNO execution triples, how do you determine the subject of those triples?

Ah yeah, didn't come to that part yet, you can probably extend to that

Another concern with such an approach is that it impedes generic RDF to Object mapping approaches where information such as node IRIs/BNode ids might get lost.

You mean, in the code of an RML engine software? I have the feeling that an approach that loses node IRIs is a bad approach, but I don't understand fully what you're saying here

I'm not sure I understand the difference between 'You use the actual IRI of the execution to differentiate between executions' and 'You use the subjectmap of the execution to differentiate between executions' (except that you can reuse the latter for the execution triples, and that your RML can be prettier bc you can use blank nodes for executions)

So: I'm totally ok with a construct that adds a subject(map) to an execution :D

If that was the last hurdle, we are now in Official Agreement™

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is that in your initial clarification <#Execution> has no subject map, but you seem to imply that the IRI / BNode id of the mapping construct <#Execution> should be used to indicate that the function execution is the same.
So, if you were to generate FNO execution triples, how do you determine the subject of those triples?

Ah yeah, didn't come to that part yet, you can probably extend to that

Another concern with such an approach is that it impedes generic RDF to Object mapping approaches where information such as node IRIs/BNode ids might get lost.

You mean, in the code of an RML engine software? I have the feeling that an approach that loses node IRIs is a bad approach, but I don't understand fully what you're saying here

Yep analogous to mapping from JSON/YAML to objects. e.g. how would this work in YARRRML?

I'm not sure I understand the difference between 'You use the actual IRI of the execution to differentiate between executions' and 'You use the subjectmap of the execution to differentiate between executions' (except that you can reuse the latter for the execution triples, and that your RML can be prettier bc you can use blank nodes for executions)

One is part of the mapping structure, and the other is expressed using the mapping structure.
Also i feel it makes more sense to use the IRI of the FNO execution conceptually.

So: I'm totally ok with a construct that adds a subject(map) to an execution :D

If that was the last hurdle, we are now in Official Agreement™

OK 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another concern with such an approach is that it impedes generic RDF to Object mapping approaches where information such as node IRIs/BNode ids might get lost.

You mean, in the code of an RML engine software? I have the feeling that an approach that loses node IRIs is a bad approach, but I don't understand fully what you're saying here

Yep analogous to mapping from JSON/YAML to objects. e.g. how would this work in YARRRML?

I would say similar to how logicalsources work in YARRRML: you can either include it inline (similar to a blank node), or refer to a key that is part of top-level construct (similar to a named node). That allows to make that overhead only necessary in cases it would be needed (see examples 11 and 15 at https://rml.io/yarrrml/spec/#examples)

One is part of the mapping structure, and the other is expressed using the mapping structure. Also i feel it makes more sense to use the IRI of the FNO execution conceptually.

I agree on the conceptual idea of being able to specify the FnO Execution identifier. But considering your first part: isn't this similar to referring to a parenttriplesmap? I think spec-wise, it should be possible to refer to a parenttriplesmap fully using blanknodes, what's the difference with that and functions?

<#DeptTriplesMap>
    rr:logicalTable [ rr:tableName "DEPT" ];
    rr:subjectMap [
        rr:template "department/{DEPTNO}";
        rr:class ex:Department;
    ];
    rr:predicateObjectMap [
        rr:predicate ex:location;
        rr:objectMap [ rr:parentTriplesMap <#SiteTriplesMap> ];
    ].

<#SiteTriplesMap>
    rr:logicalTable [ rr:tableName "DEPT" ];
    rr:subjectMap [
        rr:template "site/{LOC}";
        rr:class ex:Site;
    ];
    rr:predicateObjectMap [
        rr:predicate ex:siteName;
        rr:objectMap [ ex:column "LOC" ];
    ].

should be equivalent to

<#DeptTriplesMap>
    rr:logicalTable [ rr:tableName "DEPT" ];
    rr:subjectMap [
        rr:template "department/{DEPTNO}";
        rr:class ex:Department;
    ];
    rr:predicateObjectMap [
        rr:predicate ex:location;
        rr:objectMap [ rr:parentTriplesMap [
            rr:logicalTable [ rr:tableName "DEPT" ];
            rr:subjectMap [
                rr:template "site/{LOC}";
                rr:class ex:Site;
            ];
            rr:predicateObjectMap [
                rr:predicate ex:siteName;
                rr:objectMap [ ex:column "LOC" ];
            ].
        ] ];
    ].

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but this is an example of inlining and reusing a mapping construct, not the result of a(n intermediate) mapping (which in this case produces the fno triples), which is subtly different. Or am I missing something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it depends on whether you see fnml:Execution as a special (new) mapping construct or a type of triplesmap. I'm fine with either option though :D

FNML/ontology.md Outdated Show resolved Hide resolved
FNML/ontology.md Outdated
<dfn class="lint-ignore">fnml:Execution</dfn> is a new class to denote an [=FnML execution=].
It is refered from a [=fnml:ExecutionTermMap=] via the predicate `fnml:execution`.
It refers to an FnO [=function description=] via the predicate `fnml:function`,
and to zero or more input parameters via the predicate `fnml:inputParameters`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the singular fnml:inputParameter. This is more in line with the rest of the language and fits the triple model better IMO.

FNML/ontology.md Outdated
that generates an <a>execution</a> description.
### fnml:ParameterTermMap

<dfn>fnml:ParameterTermMap</dfn> is a subclass of [rr:TermMap](http://www.w3.org/ns/r2rml#TermMap).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to define this as a TermMap? Looking at what the intent is of this construct, it is to generate something along the lines of:

_:some-function-execution ex:some-param "some value" .

In that sense it is actually closer to a PredicateObjectMap which is of course how it was conceived in the original FnML/FnO.

I think we need to decide: Is this approach syntax sugar for the original approach? Or are they actually new constructs.

In the latter case, I would name this construct fnml:ParameterMap. We can then decide if this is an intersection of PredicateObjectMap and ObjectMap or just a special ExpressionMap.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, you're totally right. I tried to refine based on your comments, and the result isn't that far off of the original, see
image

With the added advantage of the original approach that you can dynamically generate function and parameter IRIs. Maybe just replacing rr:TriplesMap in the original approach with a newly introduced concept (e.g. fnml:Execution) and adding the right kind of syntax sugar would be enough.

FNML/ontology.md Outdated
then each result of each iteration of the function execution triples map should be used by the knowledge graph generating triples map
(i.e., a full join).
For an example on joining values across data sources, without join conditions, see test case [RMLFNOTC009](https://github.com/RMLio/rml-fno-test-cases/tree/master/RMLFNOTC0009-CSV).
The logical source of the [=fnml:ParameterTermMap=]s are determined by the logical source of the triples map that refers to the [=fnml:Execution=].
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the fnml:ParameterTermMaps? What about the fnml:Execution?

What happens when an fnml:Execution is reused accross multiple TriplesMaps?

This could be read as though the logical sources of all those triples maps should be used simultaneously, which of course is not the intent.

FNML/ontology.md Outdated
### fnml:predicate

<dfn class="lint-ignore">fnml:predicate</dfn> connects the [fnml:ParameterTermMap] with a parameter predicate.
It has domain [=fnml:ParameterTermMap=] and range [rdf:Property].
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, we shouldn't restrict the range to rdf:Property to more easily connect other approaches in the future.

FNML/ontology.md Outdated
Comment on lines 162 to 167
[
a fnml:ParameterTermMap
fnml:predicate grel:stringInput ;
fnml:execution <#Execution2> ; # Link to the nested execution
fnml:output grel:stringOutput . # Specify which output of the nested execution is taken
] .
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm this is tricky. A ParameterTermMap is now not only a TermMap and PredicateObjectMap, but also sometimes an ExecutionTermMap?

Not saying it can't work, but, I wonder if it wouldn't be cleaner to keep these concepts seperate?

e.g.

        [
            a fnml:ParameterMap
            fnml:parameter grel:stringInput ;
            fnml:parameterValue [
                # a rr:TermMap, fnml:ExecutionTermMap
                fnml:execution <#Execution2> ;     # Link to the nested execution
                fnml:output grel:stringOutput .    # Specify which output of the nested execution is taken
            ]
        ] .

In this case I introduce a new predicate fnml:parameterValue which refers to a TermMap, thus making it natural to reuse fnml:ExecutionTermMap at this location.

Co-authored-by: Pano Maria <pano.maria@gmail.com>
@bjdmeest
Copy link
Member Author

Closed in favor of latest draft at https://kg-construct.github.io/fnml-spec/

@bjdmeest bjdmeest closed this Oct 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants