About
async-elastic-orm is an asynchronous POJO-to-ElasticSearch library for Java. It allows for quick and easy saving, loading and searching of any regular java POJO with support for complex object graphs and polymorphism.
Installing
You can either add the jar to your classpath along with the ElasticSearch Java library ( http://www.elasticsearch.org/download/ ) or you can use maven and add the dependency to your pom:
<dependency>
<groupId>io.github.ryan-za</groupId>
<artifactId>async-elastic-orm</artifactId>
<version>0.2.3-SNAPSHOT</version>
</dependency>
Basic Usage
POJO definition
public class POJO {
@ID String id;
String name;
}
Saving a POJO
POJO pojo = new POJO();
new GDS().save(pojo).result().now();
Loading a POJO
POJO pojo = new GDS().load().fetch(POJO.class, id).now();
Searching or loading multiple
List<POJO> list = new GDS().query(POJO.class).asList();
Asynchronous Usage
async-elastic-orm allows for non-blocking operations which are preferable when creating a high performance server (such as with http://vertx.io ). All operations return a GDSResult or GDSMultiResult with the operations now() or later(). Use later() for non-blocking. The async callbacks are optimized to be used with Java8 lambdas when they become a standard language feature by only having a single method. Error results are returned as a parameter you must check rather than a distinct callback as this seems to make for neater code.
Saving a POJO
POJO pojo = new POJO();
new GDS().save(pojo).result().later(new GDSCallback<Key>() {
@Override
public void onSuccess(Key t, Throwable err) {
// Check err for errors, the key contains the id
}
});
Loading a POJO
new GDS().load().fetch(POJO.class, id).later(new GDSCallback<POJO>() {
@Override
public void onSuccess(POJO pojo, Throwable err) {
// Check err for errors
}
});
Searching or loading multiple (full list callback)
List<POJO> list = new GDS().query(POJO.class).result()
.laterAsList(new GDSResultListReceiver<POJO>() {
@Override
public void success(List<POJO> list, Throwable err) {
// Check err for errors
}
});
Searching or loading multiple (feeder callback)
List<POJO> list = new GDS().query(POJO.class).result()
.later(new GDSResultReceiver<POJO>() {
@Override
public boolean receiveNext(POJO pojo) {
return true; // return false to stop receiving more
}
@Override
public void onError(Throwable err) {
// Specific error callback as receiveNext()+finished()
// block this being used as a lambda
}
@Override
public void finished() {
// Called when all results have been pushed to
// receiveNext()
}
});
Batching async operations
There is a GDSBatcher available for batching together multiple async operations so that you do not need a specific handler for each one. This is useful for only running operations when all saves or loads have completed.
TestParent testParent1 = new TestParent();
GDSResult<Key> result1 = getGDS().save().entity(testParent1).result();
TestParent testParent2 = new TestParent();
GDSResult<Key> result2 = getGDS().save().entity(testParent2).result();
TestParent testParent3 = new TestParent();
GDSResult<Key> result3 = getGDS().save().entity(testParent3).result();
TestParent testParent4 = new TestParent();
GDSResult<Key> result4 = getGDS().save().entity(testParent4).result();
TestParent testParent5 = new TestParent();
GDSResult<Key> result5 = getGDS().save().entity(testParent5).result();
GDSResult<Boolean> allResult =
new GDSBatcher(result1, result2, result3, result4, result5)
.onAllComplete();
boolean success = allResult.now();
Object versioning
Elasticsearch provides for object versioning which can be used in places where consistency is important. async-elastic-orm provides for easy access to this functionality by declaring a version parameter in your pojo. When doing an update of a pojo with a version field, the operation will only succeed if the version matches with the pojo being updated to ensure no data is overwritten.
public class TestVersionedObject {
@ID
String id;
@Version
long ver;
String name;
}
TestVersionedObject testVersionedObject = new TestVersionedObject();
testVersionedObject.name = "one";
// This will succeed
Key key1 = getGDS().save(testVersionedObject).now();
testVersionedObject.name = "two";
// This will also succeed as the pojo's version
// has been updated on save
Key key2 = getGDS().save(testVersionedObject).now();
// simulate an old copy of the object
testVersionedObject.ver = 1;
// This will fail as the version is older
getGDS().save(testVersionedObject).now();
More examples
More examples of usage are available in the tests. Please help by submitting more tests.
Performance
While this library uses reflection, all of the reflection classes are only fetched a single time and then cached for performance. With Java7+, cached reflection calls are not significantly slower than regular method calls. There are performance tests available in the tests. Performance for the Async operation mode appears to be very good and there is not much overhead compared to regular elasicsearch api commands.