-
Notifications
You must be signed in to change notification settings - Fork 17
Performance
We wrote a paper comparing JOPA with other object-triple mapping libraries (such as AliBaba, Empire, KOMMA, RDFBeans). It presents:
- A feature comparison of the libraries
- A benchmark showcasing typical application operations - create, retrieve, retrieve all (instances of a specific type), update, delete
More information about the benchmark, the methodology, raw data and the original results can be found at https://kbss.felk.cvut.cz/web/otm-benchmark.
However, the benchmark is quite old. The following table thus provides a perspective on how the performance of JOPA in the benchmark has evolved since version 0.10.7 (the version used in the original benchmark). The benchmark was run with the following setup:
- Linux Mint 21.3 (kernel 6.8.0-87-generic) - disabled network, no other applications running
- AMD Ryzen 7 PRO 4750U
- 32GB RAM
- GraphDB 10.8.4
| JOPA version | Create | Retrieve | Retrieve all | Update | Delete | |||||
|---|---|---|---|---|---|---|---|---|---|---|
| Mean/ms | σ / ms | Mean / ms | σ / ms | Mean / ms | σ / ms | Mean / ms | σ / ms | Mean / ms | σ / ms | |
| 0.10.7 | 16694.17 | 181.4378 | 11930.94 | 871.2306 | 12077.37 | 921.4616 | 15142.52 | 455.5812 | 25580.1 | 959.1004 |
| 2.6.0 | 12338.22 | 637.955 | 12660.44 | 420.3243 | 12991.11 | 382.5462 | 15234.75 | 536.3642 | 9607.23 | 520.1247 |
| 2.7.0 | 11915.46 | 612.0381 | 12371.51 | 765.871 | 12521.72 | 650.8022 | 15111.65 | 522.3286 | 9819.639 | 518.1418 |
By default, a query that returns entities is processed in two phases:
- The query is executed, returning only identifiers of the resulting entities
- Each resulting entity is loaded using the underlying access API (just as if
EntityManager.findwas called for the result element)
This makes query result loading typically a little slower and requires more requests to the repository (n+1 where n is the number of result rows). However, it gives JOPA better control over inferred/asserted data to be loaded, cache access and repository contexts.
Nevertheless, it is often more favorable to just load the entities directly from the query result (thus requiring only one request to the repository). Two optimizers are (as of 2.7.1) available for optimized entity loading from query results.
-
Unbound predicate and object optimizer adds, as its name suggests, a triple pattern of the form
?x ?xP ?xVinto the query, making the query basically return triples with subject?x. The entity is then loaded from them. However, this may retrieve more data than expected and could make the query run slow. Therefore, this pattern is used only if the target type has a@Propertiesfield -
Attribute enumerating optimizer adds optional groups (e.g.,
OPTIONAL { ?x ?hasStringAttribute ?stringAttribute }) for each of the attributes of the target entity class. This narrows the amount of data actually retrieved by the query and should improve the query performance. This is the default optimizer used when the target entity class does not have a@Propertiesfield. This optimizer is also able to work with repository contexts specified by the descriptor passed to the query API.
Entity loading optimizers are not used when the query uses OFFSET or LIMIT, because they both influence the number of query result rows and could thus skew the actual results.
It is also necessary to emphasize that using the loading optimizers means that all inferred data are included in the loaded entity (or the query has to be executed without inference at all), so the loaded entities may contain more data than if they were loaded using the default mechanism.
Entity loading query result optimization can be enabled for individual queries using the cz.cvut.kbss.jopa.query.enableEntityLoadingOptimizer query hint (use the QueryHints class for convenience).