TNO / knowledge-engine

Improves interoperability between systems (i.e. devices, platforms, apps, databases) by exchanging data based on their semantics
https://knowledge-engine.eu
Apache License 2.0
33 stars 4 forks source link

AskResult bindingSet different from exchangeInfo bindingSet #506

Closed johankumps closed 5 months ago

johankumps commented 5 months ago

Hello,

It seeams the the bindingSet retrieved via askResult.getBindingSet is different from askResult.getExchangeInfo..get(0).getBindingSet(). More specifically the datatype of a literal is not present in askResult.getBindingSet. Is there a reason for this?

Please consider folowing print screen of my debugging session

image

bnouwt commented 5 months ago

Hey @johankumps, good catch! That is definitely not intended. I think it is a bug in this code.

Thanks for reporting!

bnouwt commented 5 months ago

@johankumps I am trying to reproduce the behavior described above so that I can start solving the issue, but have not succeeded yet. Both via the Java API and the REST API the datatype of a literal shows up in both the merged binding set as well as the knowledge base specific binding set. Do you have additional information for me?

The screenshot of the debugging session confuses me a little bit because both bindingSet variables have the ArrayList type, while in reality they are of type HashSet. Are you using the latest version (1.2.4) of the Knowledge Engine? Maybe you can double check what happens if you actually print the values of the isWithin binding to the console, to make sure the datatype is indeed not there?

johankumps commented 5 months ago

Hello Barry, I'm not using the latest version 1.2.4. I'm using 1.2.1.

I upgraded my KE to 1.2.4. After some issues with the REST client generation I'm able to call the KE from within my code. I execute the scAskPost with no recipientSelector. Only a bindingSet in the ScAskPostRequest instance used as parameter for the ProactiveAPI.scAskPost method. I keep getting this error : The RecipientSelector should be a valid JSON object with a singleKnowledgeBase key that leads to a string value of a KnowledgeBaseId. The POST REST request body to /sc/ask is :

{"recipientSelector":null,"bindingSet":[{"geometry":"<http://example.org/ontology#someGeometry>"},{"foi":"<http://example.org/ontology#myFoi>"}]}

Even when setting a default RecipientSelector in the ScAskPostRequest, the error is thrown. In this case the POST REST request body to /sc/ask looks like :

{"recipientSelector":{},"bindingSet":[{"geometry":"<http://example.org/ontology#someGeometry>"},{"foi":"<http://example.org/ontology#myFoi>"}]}

This is my code :

ScAskPostRequest scAskPostRequest = new ScAskPostRequest();
scAskPostRequest.setBindingSet(bindingSet);
scAskPostRequest.setRecipientSelector(new RecipientSelector());
return this.proactiveApi.scAskPost(knowledgeBaseId, knowledgeInteractionId, scAskPostRequest);
bnouwt commented 5 months ago

Thanks for the info. The POST /sc/ask operation support two different requestBody JSON objects; only a binding set or a recipient selector with a binding set. If you choose the latter, it seems like you cannot leave the recipient selector empty (by null or {}) like you do above. Does the generated ScAskPostRequest object allows you to provide an empty list of knowledge bases which results in the following JSON:

{
    "recipientSelector": {
        "knowledgeBases": []
    },
    "bindingSet": [
        {
            "geometry": "http://example.org/ontology#someGeometry"
        },
        {
            "foi": "http://example.org/ontology#myFoi"
        }
    ]
}

I have tested the above and it works. Alternatively, you can use the binding set only option and make sure the JSON looks like this:

[
    {
        "geometry": "http://example.org/ontology#someGeometry"
    },
    {
        "foi": "http://example.org/ontology#myFoi"
    }
]

Hope this helps! 👍

Regards, Barry

johankumps commented 5 months ago

I just found this setting in the generator config :

@com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL) Will test that first and then your suggestions.
johankumps commented 5 months ago

After adding an empty knowledgebases list to the recipientselector it seems to work but unfortunately the bindingset is still different on the level of the datatype:

result.getBindingSet().get(0).get("isWithin") :: true
result.getExchangeInfo().get(0).getBindingSet().get(0).get("isWithin") :: "true"^^<http://www.w3.org/2001/XMLSchema#boolean>

I'm currently using the 1.2.4 version.

In the generated code the bindingSet variable is defined as : private List<Map<String, String>> bindingSet Where should I see the HashSet? Could it be an difference in the generated code due to the use of another plugin?

This is my generator plugin configuration:

`<plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>7.2.0</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <packageName>eu.knowledge.engine.rest</packageName>
                            <apiPackage>eu.knowledge.engine.rest.api</apiPackage>
                            <modelPackage>eu.knowledge.engine.rest.model</modelPackage>
                            <inputSpec>
                                ${project.basedir}/src/main/resources/openapi-sc.yaml</inputSpec>
                            <generatorName>java</generatorName>
                            <generateSupportingFiles>true</generateSupportingFiles>
                            <generateApis>true</generateApis>
                            <configOptions>
                                <strictSpec>true</strictSpec>
                                <library>resttemplate</library>
                                <useTags>true</useTags>
                                <additionalModelTypeAnnotations>
                                    @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
                                </additionalModelTypeAnnotations>
                            </configOptions>
                        </configuration>
                    </execution>
                </executions>
            </plugin>`
bnouwt commented 5 months ago

unfortunately the bindingset is still different on the level of the datatype

That's a pity. Would it be possible to provide a code example to which I have access that shows the problem in action so I can at least reproduce it?

Where should I see the HashSet?

My mistake, I was mixing up your generated Java client/API with the Knowledge Engine's Java API that. Do you maybe have access to the JSON response from the Knowledge Engine in your generated Java client? This way we can rule out that the problem occurs within the generated Java client.

johankumps commented 5 months ago

I've intercepted the request and response messages:

Request:

{"recipientSelector":{"knowledgeBases":[]},"bindingSet":[{"geometry":"<http://example.org/ontology#someGeometry>"},{"foi":"<http://example.org/ontology#myFoi>"}]}

Response :

{
   "bindingSet":[
      {
         "foi":"http://example.org/ontology#myFoi",
         "geometry":"http://example.org/ontology#someGeometry",
         "isWithin":"true"
      }
   ],
   "exchangeInfo":[
      {
         "initiator":"knowledgeBase",
         "knowledgeBaseId":"https://world.inetum/khc-gw/service/sparql-endpoint-adapter",
         "knowledgeInteractionId":"https://world.inetum/khc-gw/service/sparql-endpoint-adapter/interaction/1a54e939-74ed-4ed5-8117-3b390bf00f75",
         "exchangeStart":"2024-05-30T17:17:00.582+00:00",
         "exchangeEnd":"2024-05-30T17:17:00.865+00:00",
         "status":"SUCCEEDED",
         "bindingSet":[
            {
               "foi":"http://example.org/ontology#myFoi",
               "geometry":"http://example.org/ontology#someGeometry",
               "isWithin":""true"^^http://www.w3.org/2001/XMLSchema#boolean"
            }
         ]
      }
   ]
}
bnouwt commented 5 months ago

Thanks! I notice that in your response the typed literal in the exchange info is incorrect; instead of ""true"^^http://www.w3.org/2001/XMLSchema#boolean" it should look like "\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>. Notice the slashes (\) before the double quotes and the angled brackets (< and >) around the type. Can you, by any chance, show the JSON binding set of the KB that provides the typed literal? I might be able to reproduce this behavior if I see the binding set where the isWithin boolean value is provided.

johankumps commented 5 months ago

The bindingset (as JSON) being returned :

[
   {
      "foi":"<http://example.org/ontology#myFoi>",
      "geometry":"<http://example.org/ontology#someGeometry>",
      "isWithin":"\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>"
   }
]
bnouwt commented 5 months ago

Aha, thanks, so that does not seem to be the problem. Some additional questions:

And just to be clear about the scenario:

[
    {
        "foi": "<http://example.org/ontology#myFoi>",
        "geometry": "<http://example.org/ontology#someGeometry>",
        "isWithin": "\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>"
    }
]
{
    "recipientSelector": {
        "knowledgeBases": []
    },
    "bindingSet": [
        {
            "geometry": "<http://example.org/ontology#someGeometry>"
        },
        {
            "foi": "<http://example.org/ontology#myFoi>"
        }
    ]
}
{
   "bindingSet":[
      {
         "foi":"http://example.org/ontology#myFoi",
         "geometry":"http://example.org/ontology#someGeometry",
         "isWithin":"true"
      }
   ],
   "exchangeInfo":[
      {
         "initiator":"knowledgeBase",
         "knowledgeBaseId":"https://world.inetum/khc-gw/service/sparql-endpoint-adapter",
         "knowledgeInteractionId":"https://world.inetum/khc-gw/service/sparql-endpoint-adapter/interaction/1a54e939-74ed-4ed5-8117-3b390bf00f75",
         "exchangeStart":"2024-05-30T17:17:00.582+00:00",
         "exchangeEnd":"2024-05-30T17:17:00.865+00:00",
         "status":"SUCCEEDED",
         "bindingSet":[
            {
               "foi":"http://example.org/ontology#myFoi",
               "geometry":"http://example.org/ontology#someGeometry",
               "isWithin":""true"^^http://www.w3.org/2001/XMLSchema#boolean"
            }
         ]
      }
   ]
}
johankumps commented 5 months ago
curl --location 'http://localhost:8280/rest/sc/ask' \
--header 'Knowledge-Base-Id: https://world.inetum/khc-gw/service/knowledge-item-fetcher-reasoner' \
--header 'Knowledge-Interaction-Id: https://world.inetum/khc-gw/service/knowledge-item-fetcher-reasoner/interaction/f51ba4d8-495a-4c46-8d37-f0964c1d1749' \
--header 'Content-Type: application/json; charset=UTF-8' \
--header 'Accept: application/json; charset=UTF-8' \
--data '{
    "recipientSelector": {
        "knowledgeBases": []
    },
    "bindingSet": [
        {
            "geometry": "<http://example.org/ontology#someGeometry>"
        },
        {
            "foi": "<http://example.org/ontology#myFoi>"
        },
        {
            "isWithin": "\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>"
        }
    ]
}'
curl --location 'http://localhost:8280/rest/sc/ask' \
--header 'Knowledge-Base-Id: https://world.inetum/khc-gw/service/knowledge-item-fetcher-reasoner' \
--header 'Knowledge-Interaction-Id: https://world.inetum/khc-gw/service/knowledge-item-fetcher-reasoner/interaction/f51ba4d8-495a-4c46-8d37-f0964c1d1749' \
--header 'Content-Type: application/json; charset=UTF-8' \
--header 'Accept: application/json; charset=UTF-8' \
--data '{
    "recipientSelector": {
        "knowledgeBases": []
    },
    "bindingSet": [
        {
            "geometry": "<http://example.org/ontology#someGeometry>"
        },
        {
            "foi": "<http://example.org/ontology#myFoi>"
        }
    ]
}
{
    "bindingSet": [
        {
            "foi": "<http://example.org/ontology#myFoi>",
            "geometry": "<http://example.org/ontology#someGeometry>",
            "isWithin": "true"
        }
    ],
    "exchangeInfo": [
        {
            "initiator": "knowledgeBase",
            "knowledgeBaseId": "https://world.inetum/khc-gw/service/sparql-endpoint-adapter",
            "knowledgeInteractionId": "https://world.inetum/khc-gw/service/sparql-endpoint-adapter/interaction/db773404-70f1-4cea-9f2d-daebc36cd9ac",
            "exchangeStart": "2024-05-31T10:21:19.588+00:00",
            "exchangeEnd": "2024-05-31T10:21:19.849+00:00",
            "status": "SUCCEEDED",
            "bindingSet": [
                {
                    "foi": "<http://example.org/ontology#myFoi>",
                    "geometry": "<http://example.org/ontology#someGeometry>",
                    "isWithin": "\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>"
                }
            ]
        }
    ]
}
bnouwt commented 5 months ago

Can you also post the graph pattern you are using?

johankumps commented 5 months ago

The is the KI spec:

[
    {
        "knowledgeInteractionType": "AskKnowledgeInteraction",
        "communicativeAct": {
            "requiredPurposes": [
                "https://w3id.org/knowledge-engine/InformPurpose"
            ],
            "satisfiedPurposes": [
                "https://w3id.org/knowledge-engine/InformPurpose"
            ]
        },
        "prefixes": {},
        "graphPattern": "?foi <http://example.org/ontology#withinGeometry> ?geometry . ?foi <http://example.org/ontology#isWithin> ?isWithin . ",
        "knowledgeInteractionId": "https://world.inetum/khc-gw/service/knowledge-item-fetcher-reasoner/interaction/f51ba4d8-495a-4c46-8d37-f0964c1d1749"
    }
]
bnouwt commented 5 months ago

I suddenly realize that I assumed you were not using the reasoner, but when I enable the reasoner I can immediately reproduce the behavior 👍 . Now we can take a look at what is going wrong. Thanks for your patience!

johankumps commented 5 months ago

ASK side has reasoner enabled; ANSWER side no reasoner

bnouwt commented 5 months ago

I found the cause, but unfortunately, there is no work around. All typed literals were converted into simple or plain literals when they are converted into a string. I have fixed this behavior to never use plain literals for values in a binding set when converting them and this indeed solves the issue. I also added a unit test for this use case, so if we do a future rewrite this incorrect behavior will hopefully not sneak back in.

You have two options: either use the current SNAPSHOT version with the fix or wait for the next release (nothing planned yet). Is that workable for you?

johankumps commented 5 months ago

I can indeed confirm that the issue is fixed on the current master branch. It's ok for me to use this for now. Looking forward to the new release. Will the lightning fast reasoner :) be in that release too?

bnouwt commented 5 months ago

It might be. We are currently improving the so called Graph Pattern matcher algorithm that is used in the reasoner to build the reasoning graph. This is currently the biggest bottleneck when using the reasoner with bigger graph patterns. We have some clear pointers on how to improve it, but it is still quite challenging 😄.