Performance and Optimizations

Serializing Literal Values

Literal Objects must be able to store their state in character format, but may have repository conversion optimizations as MemoryStore does. When using non-String literal property values, overhead of conversion can occur particularly if no String constructor is present and no static valueOf method exists. The default LiteralManager ships with common Java conversions and also supports valueOf method, String constructors, and Java serialization. Java serialization is provided as a catch-all solution and often under-performs compared to object-specific converters. When using non-standard literal objects, ensure that they have a static valueOf method or String constructor (if this is not possible, consider using a custom LiteralManager).

AugurRepository and ReadAheadRepository

When using non-local repositories, overhead costs exist for each repository hit. If concept properties are retrieved in nested loops, the overhead cost can add up quickly. In this case the repository client can be wrapped in an AugurRepository or ReadAheadRepository. The AugurRepository can reduce the number of hits to the delegate connection from o(m^n) to o(n) by tracking requests and anticipating related information. The ReadAheadRepository reduces the number of hits to the repository for the same subject.

Augur is best used when the complete results are expected to fit into memory and not all the properties will be read. ReadAhead is best used when the complete results may not fit into memory and most of the concept properties will be retrieved. Below is an example of using the AugurRepository or ReadAheadRepository in a SesameManagerFactory:

repository = new HttpRepository("http://server.example.com/openrdf-sesame/", "default");
repository = new AugurRepository(repository); // or new ReadAheadRepository(repository);
repository.initialize();
ElmoModule module = new ElmoModule();
Module.addRole(Employee.class);
factory = new SesameManagerFactory(module, repository);
manager = factory.createElmoManager();

// By using Augur all information is gathered in 6 hits.
// By using ReadAhead: 1 + number of employees.
// Otherwise it would hit: 1 + 5 * number of employees.
for (Employee emp : manager.findAll(Employee.class)) {
    String name = emp.getName();
    String address = emp.getAddress();
    String phone = emp.getPhoneNumber();
    String email = emp.getEmailAddress();
    String details = name + address + phone + email;
    System.out.print(details);
}

Above, five properties are retrieved for each employee. By using just the AugurRepository the repository will be hit for:

  1. a list of employees,

  2. the type of each employee,

  3. the name of each employee,

  4. the address of each employee,

  5. the phone number of each employee, and finally

  6. the email address of each employee.

With just the ReadAheadRepository every property will be retrieved at once for each entity. Without anything the repository will be hit for every method called.

There is extra overhead for tracking what properties need to be and have been retrieved. When using a local repository, such as MemoryStore or NativeStore directly, the extra overhead does not outweigh the benefits.

ResourceManager

The subject types of every entity are stored in the repository using the predicate "http://www.w3.org/1999/02/22-rdf-syntax-ns#type". The designate method adds the types to the repository and are read during create and find methods. RDF data by design is semi-structured, making it necessary to read the type of each entity. However, in some domains, reading the type of the entity may not be necessary. By overriding the default resource manager, domainspecific optimizations can be performed.

Class Loading

Elmo creates new entity proxy classes dynamically at run-time to account for the different combinations of roles and to implement the RDF property mapping. These classes are only created once for each combination, and are reused for subsequent entities. When the necessary role combinations are known in advance and compiled classes are included in the Java class-path, no classes will be created at run-time. When the system property "elmobeans.target" is set, every dynamic class created will be saved to the folder value of the property. These class files can be packaged into a jar and deployed with an Elmo application to avoid new classes being created at run-time.

There are three types of classes created: mappers, entities, and behaviours. They are created in the package elmobeans.mappers, elmobeans.proxies, and elmobeans.behaviours respectively. The class names are hash combinations of the names of the roles they implement. The mappers are created by ElmoMapperClassFactory implementing ElmoMapperResolver, the proxies and factories are created by ElmoEntityCompositor implementing ElmoEntityResolver. Both implementations attempt to load existing classes using ClassFactory before creating a new copy. Elmo uses Javassist to generate the Java byte-code. If all role combinations are compiled in advance, these implementations can be substituted.