Commit 4a6bb884 authored by Lars Gleim's avatar Lars Gleim 🇪🇺
Browse files

Merge branch 'performance-improvements' into 'master'

Performance improvements - UGQL 1.1.0

See merge request !1
parents 6163ec7d cbeed17b
# Changelog
### Version 1.1.0
Changes:
- New result transformation
- Improved performance
- Simplified code
- Changed internal query translation form JSON to java objects
- Increased type strictness
- Added user definable prefixes
- Updated and improved documentation
- Added support for bundled root queries
- Query resolving of multiple root queries is now possible
- Updated evaluation results for this version
- Removed data fetchers
- New result transformation does not require data fetchers
Bug fixes:
- Fixed [type resolver issue](./docs/evaluation/type_resolver_problem.md)
- Fixed unnecessary generation of extracted schemas during JUnit-Tests
- Fixed query handling of mutations
- Fixed internal schema translation for equivalent property definitions
## Version 1.0.0
Initial release of UltraGraphQL
UltraGraphQL is based on **HyperGraphQL version 1.0.3** and was heavily modified.
- Automatic bootstrapping phase (through schema summarization)
- Configurable summarization querying
- Configurable mapping vocabulary
- Mutation support
- Insert and delete mutation fields are generated for all objects in the schema
- Mutation action is limited to one service (MUST be LocalModelSPARQLService or SPARQLEndpointService)
- Support for [multiple services](./docs/multiple_service_feature.md) per schema entity
- Support of equivalence relations in the schema and during querying
- [Interafaces](./docs/interface.md) and [Unions](./docs/union.md) supported in the schema
- Filter options now also avaliable for fields (prior only avaliable for the root query fields)
- Simplified query naming schema
- Additional web server framework to host the UltraGraphQL instance to allow multiple instances running on the same system
\ No newline at end of file
# <img src="./docs/figures/hypergraphql-logo.svg" width="30"> UltraGraphQL
# [<img src="./docs/figures/HyperGraphQL.png" width="30">](hypergraphql-logo.svg) UltraGraphQL
UltraGraphQL is a [GraphQL](https://graphql.org/) interface for querying and modifying RDF data on the Web.
It extends [HyperGraphQL](https://www.hypergraphql.org/) by providing a automatic bootstrapping phase of the service and a more feature rich schema support with additional support for GraphQL mutations.
Because it is based on HyperGraphQL features like the support of federated querying and exposing data from multiple linked data services using GraphQL query language and schemas were maintained and extended.
The core of the response is a JSON-LD object, which extends the standard JSON with the JSON-LD context enabling semantic disambiguation of the contained data.
![](./docs/figures/ugql_linked_data_access.png)
## Features
### Bootstrapping (OPTIONAL)
> Only needs to be done if the schema is not known
> Only needs to be done if the schema is not known or was updated
> Requirements: All service of the type SPARQLEndpointService **MUST** allow *SPARQL 1.1* queries and the runtime limitation **SHOULD** be deactivated because the schema summarization can have a long execution time on large datasets.
......@@ -17,7 +19,7 @@ The default [extraction query](./docs/schema_extraction_query.md) and [schema vo
This [example](./examples/extended_mapping/README.md) shows how to configure the schema vocabulary and the effect those changes.
If multiple service are defined in the configuration the schema is summarized on all services and then mapped to one unified schema
<img src="./docs/figures/bootstrapping_example.svg">
![Abstract example of the schema summarization and mapping](./docs/figures/bootstrapping_example.png "Abstract overview of the bootstrapping phase")
### Queries
For each object type of the provided or extracted schema a query field is generated.
......@@ -27,7 +29,7 @@ To test the different features of UGQL the provided [examples](examples/README.m
> Note: The service MUST not be defined in the query. Based on the UGQL schema (UGQLS) the different services will be queried accordingly.
<img src="./docs/figures/ugql_query_schematic.svg">
[![](./docs/figures/ugql_query_schematic.png)](./docs/figures/ugql_query_schematic.svg)
### Mutations
Insert and delete mutations are [generated](./docs/translation_phase.md#mutation-translation) for each object type of the UGQLS which corresponds to the output type of the mutation allowing to directly query the modified data.
......@@ -81,6 +83,8 @@ java -jar build/libs/<exe-jar> --config <path to config>
For example UGQL service setups look into the [examples](examples/README.md) and their configurations.
-----------------------------------------
## Differences to HyperGraphQL
- Automatic bootstrapping phase (through schema summarization)
- Configurable summarization querying
......@@ -94,6 +98,7 @@ For example UGQL service setups look into the [examples](examples/README.md) and
- Filter options now also avaliable for fields (prior only avaliable for the root query fields)
- Simplified query naming schema
- Additional web server framework to host the UltraGraphQL instance to allow multiple instances running on the same system
- Simplified and more efficient result transformation (v1.1.0 or higher)
### License note:
This software is a further development of HyperGraphQL which has been developed and is maintained by [Semantic Integration Ltd.](http://semanticintegration.co.uk). It is released under Apache License 2.0. See [LICENSE.TXT](https://github.com/semantic-integration/hypergraphql/blob/master/LICENSE.TXT) for more infromation.
......@@ -15,7 +15,7 @@ apply plugin: 'maven'
apply plugin: 'com.github.johnrengelman.shadow'
group = 'org.hypergraphql'
version = '1.0.0'
version = '1.1.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
......
......@@ -27,8 +27,8 @@ For the placeholder object and field the name space hgqls was chosen to avoid in
>The name and name space of the placeholder object can be configured in the HGQL_Vocabulary class, but it has to be considered that changing the default value can lead to incompatibility issues and incase the object name ic changed it would also require to adjust the extraction query.
>It should be mentioned that the placeholder object for literals is only generated if besides a String as output type also at least one other output type is defined.
##Example
###Dataset
## Example
### Dataset
```
ex:Bob a ex:Person;
ex:name "Bob";
......@@ -40,7 +40,7 @@ ex:addr742ET a ex:Address;
ex:street_name "Evergreen Terrace";
ex:house_number "742".
```
###HGQL Schema
### HGQL Schema
```GraphQl
interface ex_Address_Interface {
......@@ -72,7 +72,7 @@ type ex_Address implements ex_address_OutputType & ex_Address_Interface @service
```
###GraphQL query
### GraphQL query
```
{ex_Person
ex_name
......@@ -87,8 +87,10 @@ type ex_Address implements ex_address_OutputType & ex_Address_Interface @service
}
```
###JSON Representation of the Query
### UGQL Representation of the Query
> As from **UGQL 1.1.0 or higher** the JSON representation of the query is replaced by java objects with the same structure.
> The JSON object below is therefore still valid to express the structure and naming of the UGQL representation of the GQL query since the SPARQL variable naming scheme did not change.
```json
{
......@@ -154,7 +156,7 @@ type ex_Address implements ex_address_OutputType & ex_Address_Interface @service
```
###SPARQL Translation of the Query
### SPARQL Translation of the Query
```sparql
SELECT *
WHERE
......@@ -188,29 +190,8 @@ WHERE
###Result enhancement
### Result enhancement
The result of the query is a mapping from result resources (IRIs and Literals) to corresponding query variables. During the result processing the results get enhanced with information of the schema.
The single IRIs get transformed to complete triples so that the query resolver defined in the GraphQl schema are able to retrieve the information corretlly.
Example:
Let the result to the Query above be the following
- ?x_1 = <http://example.org/Bob>
- ?x_1_2 = "Bob"
- ?x_1_1_y_1 = <http://example.org/addr742ET>
- ?x_1_1_y_1_1 = "742"
- ?x_1_1_y_2 = "742 Evergreen Terrace"
The getModelFromResults method then transforms the results to the following triples.
```rdf
http://example.org/Bob @http://example.org/address http://example.org/addr742ET;
http://example.org/Bob @http://example.org/name "Bob";
http://example.org/Bob @http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://example.org/Person;
http://hypergraphql.org/query @http://hypergraphql.org/query/ex_Person http://example.org/Bob;
http://example.org/addr742ET @http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://example.org/Address;
http://example.org/addr742ET @http://example.org/house_number "742".
ex:Bob ex:address hgqls:x_1_1_y_2.
hgqls:x_1_1_y_2 rdf:type hgqls:Literal.
hgqls:x_1_1_y_2 hgqls:string "742 Evergreen Terrace".
```
The result of the query is a mapping from result resources (IRIs and Literals) to corresponding query variables.
During the result transformation the results for the literal placeholder need to be converted to the literal placeholder structure to keep the result schema compliant.
The results are therefore inserted with the structural overhead of the placeholder structure to the final result format.
# Documentation
## Service Setup
|Link|Description|
|:------|:-------|
|[Configuration File](./config.md)|Detailed explaination of the configuration file|
|[Mapping Vocabulary](./schema_mapping.md)|Default mapping vocabulary ways to adjust it|
|[Extraction Query](./schema_extraction_query.md)|Default schema extraction query and explainations how to change the extraction query|
## Method of Operation
|Link|Description|
|:------|:-------|
|[Bootstrapping Phase](./bootstrapping.md)|Detailed explanation of the bootstrapping phase|
|[Translation Phase](./translation_phase.md)|Detailed explanation of the translation phase|
|[Mutations](./mutations.md)|Detailed explanation of the mutation support|
|[Query Modifiers](./query_modifiers.md)|Listing and explaination of all supported query modifiers|
![Abstract component overview of UGQL](./figures/ugql_abstract_component_diagram.png)
## Technical Details
|Link|Description|
|:------|:-------|
|[Multiple Services](./multiple_service_feature.md)|Supporting multiple services per schema entity|
|[Literal Placeholder](./Literal_placehoilder.md)|Introducing the concept of the literla placeholder to support literal values on properties with multiple ranges|
|[Interface](./interface.md)|Support of interface types in the UGQLS|
|[Union](union.md)|Support of union types in the UGQLS|
## Evaluation / JUnit-Tests
|Link|Description|
|:------|:-------|
|[Performance Evaluation](../evaluation/evaluation.ipynb)|Performance Evaluation of UltraGraphQL|
|[JUnit-Tests](./evaluation/README.md)|Tests for different features of UGQL partly with detailed analyses|
# Automatic Bootstrapping Through Schema Extraction
- [HGQL Configuration](./config.md): Expanded the configuration with bootstapping feature
- [Schema Exraction Query](./schema_extraction_query.md): Explaination how to write or alter a HGQL compatible schema extraction query
- [Schema Mapping](./schema_mapping.md): Explaination how the schema is mapped and how to configure the mapping
#ToDo
The bootstrapping phase is a **optional** phase during the start up of the UGQL endpoint and is only performed if enabled in the [endpoint configuration](./config.md).
When the bootstrapping is enabled the RDF schema is extracted from thee services defined in the enpoint configuration.
The schema extraction is based on the schema [extraction query](./schema_extraction_query.md) and the [schema mapping](./schema_mapping.md).
Both can be configured through the endpoint configuration or if not defined the defualt query and mapping will be used.
The configured mapping is then used to generate the final extraction query which is then executed against the SPARQL services.
The resulting SPARQL results which contain the RDF schema of the datasets are then translated to the corresponding **UltraGraphQL schema (UGQLS)**.
An UGQLS is a valid GraphQL schema but does not define query and mutation fields.
Furthermore, it requires the definition of the *__Context* object type in which stores the name resolution of the used GQL names to the corresponding IRIs.
For the translation of the schema the configured mapping vocabulary defines how the extracted RDF schema is mapped to the corresponding UGQLS features.
If multiples services are defined the extraction query is executed separetly and translated to a unified UGQLS by maintaining the service origin of the different schema entities and by maintaining schema relations across service boundaries.
The bootstrapping phase ends with the completion of the UGQLS for the configured services.
> RDF allows a wide variety of different schemas.
> The default mapping vocabulary and extraction query tries to cover the most common cases.
> If the default configuration is not well suited for a configured data set the mapping or the extraction query have to be adjusted to the actual dataset in order to function correctly.
![Abstract overview about the bootstrapping phase of UGQL. UGQL is started with the Endpoint configuration in which the services are defined and also the mapping and extraction query are configured or if not the default will be used. With this configuration the extraction queries are build and executed against the defined services. The resulting SPARQL results contain the extracted RDF schema which is then maped to corresponding UGQL schema. This UGQLS is then used to start the UGQL endpoint.](./figures/bootstrapping_phase_schematic.png)
## Related Documentation
|Link|Description|
|---------------|-------------------------|
| [HGQL Configuration](./config.md)| Expanded the configuration with bootstapping feature|
|[Schema Exraction Query](./schema_extraction_query.md)| Explaination how to write or alter a UGQL compatible schema extraction query|
| [Schema Mapping](./schema_mapping.md)| Explaination how the schema is mapped and how to configure the mapping|
......@@ -13,7 +13,7 @@ True if mutations fields SHOULD be generated with corresponding actions, otherwi
> Datatype: Boolean
##mutationService
Service id of the service on which the mutation actions are executed. The service id MUST corespond to an service that is define din services.
Service id of the service on which the mutation actions are executed. The service id MUST correspond to a service that is defined in the services.
> Datatype: String
## extraction
......@@ -63,7 +63,7 @@ Contains a list of individual services.
### Service
A Service object consists of the id, type and URL of the service.
Additionally the graph in which the data is stored is given and authentication information to access this service are given.
Additionally, the graph in which the data is stored and authentication information to access this service are given.
>Datatype: JSON-object
#### id
The id of a service MUST be unique for this service and will be used to link schema entities to a corresponding service using the **@service** directive.
......@@ -94,6 +94,23 @@ Username to access the service
#### password
Password to access the service
>Datatype: String
------------------------
##prefixes
Allows defining prefixes for namespaces that will be used for the name generation of the bootstrapping phase.
Normally the prefixes are queried form the web or are generated if non is found. To control the used prefixes they can be
defined here. Prefixes that are defined in this configuration overwrite any internal prefix look-up or generation.
>Note: namespace and prefix MUST be unique
The prefixes must be defined as follows:
```json
"prefixes":{
"ex": "http//example.org/",
"schema": "http://schema.org/"
}
```
> The use of the IRI "http://hypergraphql.org/schema/" and the prefix "hgqls" are permitted as they are used for internal
> schema relations and auxiliary structures. If they are defined anyway, they are filtered out.
## Example configuration
### Configuration with extraction and SPARQLEndpointService
......@@ -118,11 +135,15 @@ Password to access the service
"user": "admin",
"password": "admin"
}
]
],
"prefixes":{
"ex": "http//example.org/",
"schema": "http://schema.org/"
}
}
```
### Configuration with predefined schema and an local RDF Dataset
### Configuration with predefined schema and a local RDF Dataset
```json
{
"name": "hgql-example-with-sparql",
......
# Evaluation / JUnit-Tests
>ToDo
|Link|Description|
|:------|:-------|
|[Interface Test](./interface_test.md)||
|[SameAs Test](./sameAs_test.md)||
|[Combined Services Test](./test_combined_servicecs.md)||
|[Combined Services Test with Extraction](./test_combined_servicecs_with_extraction.md)||
|[Multiple Services Test](./test_multiple_servicecs.md)||
|[Extended Multiple Services Test](./test_multiple_servicecs_extended.md)||
|[Multiple Services Test](./test_multiple_servicecs.md)||
#Type Resolver Problem
> As from **UGQL v1.1.0 or higher** this problem does not exist anymore. No if a resource has multiple types the fields of the different types are merged.
>Furthermore, if a schema violation does occur because of the merging a safe fail was integrated.
>Meaning that if a field output type is defined as NOT list (single output) but the merging results in more than one result, than the output type for the file is changed to list for this result and marked in the error segment of the result.
>
Fields with the output types interface and union can output differrent object types.
GraphQL therefore need to evaluate the type of result values inorder to call the corresponding data fetcher in order to query type related data.
For this purpose a type resolver is assigned to each field with an interface or union as output type.
......
# HyperGraphQL Interface Support
HGQL supports the basic GraphQL interface functionalities.
In the schema a interface is defined as follows:
# UltraGraphQL Interface Support
UGQL supports the basic GraphQL interface functionalities.
In the schema interfaces are defined as follows:
```GraphQL
interface Pet{
name: String
......@@ -16,9 +16,9 @@ type Cat implements Pet{
age: Int
}
```
The interfaces defined in HGQLS have the same meaning as in GraphQL.
This means that a interface defines a set of fields a type MUST have if it implements the interface.
If a field has a interface as OutputType then the fields of the interface can be queried in the SelectionSet of the field and furthermore type specific fields can be queried within InlineFragments.
The interfaces defined in UGQLS have the same meaning as in GraphQL.
This means that an interface defines a set of fields a type MUST have if it implements the interface.
If a field has an interface as OutputType, then the fields of the interface are queryable in the SelectionSet of the field, and type-specific fields are queryable within InlineFragments.
By querying a field with an interface as output all types that implement this interface are queried.
Example:
```GraphQL
......@@ -43,40 +43,40 @@ type Person{
```
In this example the name and age of all pets of all persons is queried and for the dogs also the color is queried.
GraphQL allows to define blank interfacs which will be enriched by HGQL with the *_id* and *_type* field.
As usual in HGQL only objectType and fields need a defiend service, services that are defined for interfaces or unions will be ignored.
GraphQL allows to define blank interfacs which will be enriched by UGQL with the *_id* and *_type* field.
As usual in UGQL (and *HyperGraphQL*) only objectType and fields need a defiend service, services that are defined for interfaces or unions will be ignored.
>Currently NOT supported:
>- union extend features
>- interface implementing interfaces (NOT supported by graphql-java)
>- interface implementing interfaces (~~NOT supported by graphql-java~~ **Now supported by graphql-java v15 and higher**
> could know be added but requires to change the mapping from UGQLS->GQLS and also allows to optimize the mapping form RDF->UGQLS. In-depth analysis of the new possibilities required)
## Implementation
HGQL has interpreted unions and interfaces as objectTypes, which had allowed to define these types in the schema but it was not possible to use these types in the intended way.
To add interfaceTypes to the HGQLSchema and then to the GraphQL schema, the queries are validated against, the information about these types have to be inserted into the rdfSchema.
>Note: UGQL is based on HGQL meaning that some classes and attributes in UGQL still contain the HGQL name and abbreviations.
HGQL has interpreted unions and interfaces as objectTypes, which had allowed to define these types in the schema, but it was not possible to use these types in the intended way.
To add interfaceTypes to the HGQLSchema and then to the GraphQL schema, the queries are validated against, the information about these types have to be inserted into the rdfSchema (UGQL internal triplestore containing the schema that was provided to the service).
The rdfSchema is an RDF dataset containing information about the HGQLSchema.
With this dataset HGQLSchema objects are created like *FieldConfig*, *FieldOfTypeConfig*, *QueryFieldConfig* and the *TypeConfig*.
These objects contain information about the whole HGQL Schema and are used during the query resolving.
These objects contain information about the whole UGQL Schema and are used during the query resolving.
The TypeConfig class is for all types of the schema and therefore functionalities for unions and interfaces were missing.
Now a TypeConfig object can be specified to be a UNION , INTERFACE or OBJECT to support the needed functions.
Now a TypeConfig object can be specified as a UNION , INTERFACE or OBJECT to support the needed functions.
The created HGQLSchema is then used to generate a GraphQLSchema object.
Therefore the fields and objects are used to generate corresponding GraphQL objects like *GraphQLFieldDefinition* and *GraphQLObjectType*.
To support unionTypes and interfaceTypes the TypeConfig has to checked to generate either a *GraphQLObjectType*, *GraphQLUnionType* or a *GraphQLInterfaceType*.
GraphQLInterfaceType is initialised with the name and a TypeResolver.
This TypeResolver is needed during the data fetching to decide of which type an object is.
>InterfaceType TypeResolver logic:
>
>![Diagram about the InterfacenType TypeResolver logic](./figures/InterfaceType_TypeResolver.svg)
As from UGQL v1.1.0 or higher the query execution and result transformation is completely covered by UGQL using the graphql-java framework only for query validation.
This change in the query resolving makes the generation of typeResolvers redundant and therefore typeResolvers were removed from the GQLS generation.
A detailed description on how interfaces are handled during the query resolving is given below and [here](./translation_phase.md).
For querying the SPARQLEndpoints the GraphQL query is transformed into a [Json representation](#hgql-json-query-representation) of the query containing SPARQL specific information like the SPARQL query variable name of a type and field.
Because all results of the SPARQL query are stoared in a ResultPool, the structure and order of the SPARQL queries is irrelevant for the GraphQL response.
In GraphQL queries with a interface as OutputType can have fields of the types outside the InlineFragments this means that the InlineFragments only contain type specific fields or are used to query specific types. If fields of the interface are queried outside a InlineFragment all types that implement this interface MUST be queried.
Therefore "virtual" fields are created for each type that implements the interface. The SelectionSet of the virtual field is composed of the queried fields of the interface and the for this type defined typespecific fields. As shown in the diagram below the Json representation is then generated for each virtual field.
For querying the SPARQLEndpoints the GraphQL query is transformed into java objects representing the original query but additional contain SPARQL specific information like the SPARQL query variable name of a type and field.
This representation is than translated into SPARQL and executed against the assigned services.
In GraphQL queries with a interface as OutputType can have fields of the types outside the InlineFragments this means that the InlineFragments only contain type specific fields or are used to query specific types.
If fields of the interface are queried outside a InlineFragment all types that implement this interface MUST be queried.
Therefore, "virtual" fields are created for each type that implements the interface.
The SelectionSet of the virtual field is composed of the queried fields of the interface and the for this type defined type-specific fields.
The diagram below shows this process of generating the virual fields for received GQL queries.
>![Conversion of unions to Json representation of the query](./figures/TypeResolver_JsonQuery.svg)
>![Conversion of interfaceType to virtual query fields](./figures/TypeResolver_JsonQuery.svg)
>As from **UGQL v1.1.0 or higher** the JSON representation is replaced by a java object structure with the same structure and naming.
## Current Limitation of Interfaces
The current implementation of the interfaces has the same limitations as the Union implementation.
The current implementation of the interfaces has the same limitations as the [Union](./union.md) implementation.
# Support of multiple services per schema entity
Now instead of only one service per schema entity a array of service can be provided.
If a field or type with multiple services is queried the query is send to all defined services and the responses are merged together.
Instead of only one service per schema entity, like in HyperGraphQL, UGQL supports an array of services per schema entity.
If a field or type with multiple services is queried, the query is send to all defined services and the responses are merged.
## Supported service directives
>```hypergraphql
......@@ -24,8 +24,8 @@ A ManifoldService object is created in the HGQLSchema class during the process o
Here the *@service* directive is checked to find the id of the service that is responsible for the schema entity.
With the support for multiple services the directive argument id can now also be an array containing multiple service ids.
As shown in the diagram below the argument is checked if more than one id is given.
If only one service id is given it is proceeded as usual.
Otherwise a ManifoldService is created containing all service objects that correspond to the ids in the array.
If only one service ID is given it is proceeded as usual.
Otherwise, a ManifoldService is created containing all service objects that correspond to the ids in the array.
>![Diagram: creation of a ManifoldService](./figures/mainfoldService_creation.svg)
......@@ -35,19 +35,19 @@ Otherwise a ManifoldService is created containing all service objects that corre
### Usage
Thanks to the same interface as other services a ManifoldService fits without many modifications in the current processflow of the query resolving.
During the query resolving the ExecutionTreeNode is responsible for querying a given subquery.
This subquery can be the root Field of a query or a field of a subquery.
If the parent field of the query has a type as output type the the ExecutionTreeNode object selects all fields of the selection set (subfields) that have the same service and creates ExecutionTreeNodes for all subfields.
During the query resolving the ExecutionTreeNode is responsible for querying a given sub-query.
This sub-query can be the root Field of a query or a field of a sub-query.
If the parent field of the query has a type as output type the ExecutionTreeNode object selects all fields of the selection set (sub-fields) that have the same service and creates ExecutionTreeNodes for all subfields.
The created ExecutionTreeNodes are stored in the "forest" of the ExecutionTreeNode.
Therfore a ExecutionTreeNode is directly only responsible for one Service object.
Therefore, a ExecutionTreeNode is directly only responsible for one Service object.
As shown in the diagram below the ExecutionTreeNode initiates the query execution by calling the FetchingExecution.
The FetchingExecution is a wrapper class to make services a Callable class to function with Futures.
This means the ExecutionTreeNode objct starts the query execution and initiates the query execution of the forest that contains the queries for the subfields that have a different service.
The subqueries are provided by the ExecutionTreeNode parent object with the needed values for the subqueries.
This means the ExecutionTreeNode object starts the query execution and initiates the query execution of the forest that contains the queries for the subfields that have a different service.
The sub-queries are provided by the ExecutionTreeNode parent object with the needed values for the sub-queries.
To support multiple services per schema entity the ManifoldService is inserted between the FetchingExecution and the regular services to coordinate the queries and to perform a result merging.
Incoming executeQuery() calls arrive now at the ManifoldService object that forward the call to the services the object stores.
Have all services answered the call the results are merged and returned.
Instead of one Service now multiple services are queried with the same query.
Instead of one Service, now multiple services are queried with the same query.
>![Sequence Diagram: ManifoldService at work](./figures/mainfoldService_functionality.svg)
......@@ -56,4 +56,4 @@ Instead of one Service now multiple services are queried with the same query.
#### Detailed view of the query resolving
>![Sequence Diagram: ManifoldService at work](./figures/multiple_service_feature_modifications.svg)
>Path through the HGQL instance a query takes during execution
>Path through the UGQL instance a query takes during execution
......@@ -8,7 +8,7 @@
| order | fields with an array as output type |
## _id
Allows to define a set of IRIS to query fo specific objects.
Allows to define a set of IRIs to query fo specific objects.
If only one ID is defined a String instead of an array acn be used.
Example:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment