Reactive Elasticsearch With Quarkus
Reactive Elasticsearch With Quarkus
In this article, we discuss how to connect Quarkus with Elasticsearch with Project Reactor to begin binding Quarkus to Elasticsearch's Java REST Client.
Join the DZone community and get the full member experience.Join For Free
I’ve implemented one service with Quarkus as a main framework and Elasticsearch as a data store. During the implementation, I came up with the idea to write an article on how to bind Quarkus in a reactive manner with Elasticsearch's Java High Level REST Client.
I started to make notes about the article and separated the common Elasticsearch related code in the common library (otaibe-commons-quarkus-elasticsearch module) stored in Github. Then, it took me a few hours to assemble a simple example project (also in Github) in a way as in the Quarkus Guides page. For the moment, an Elasticsearch guide is missing there.
Let's continue with a more detailed explanation of how to connect Quarkus with Elasticsearch.
Creating a Quarkus project
You amy also like: Build a Java REST API With Quarkus.
As you can see an elasticsearch-rest-client is present in Quarkus; however, this is an Elasticsearch Java Low Level REST Client. If we want to use Elasticsearch Java High Level REST Client, we simply have to add it as a dependency in the pom.xml file:
Please, make sure that the version of Elasticsearch Java Low Level REST Client matches the Elasticsearch Java High Level REST Client.
Since we are using the Elasticsearch in a reactive way, I prefer to use a Project Reactor. We have to add the BOM in the dependency management section:
We also have to add reactor-core as a dependency:
I’ve separated the common code in a library, so we should add this library to our example project. For this purpose, we will use Jitpack. It is an awesome service. You just have to point the right way to your Github project, and it will build an artifact for it. Here is the way how I am using it:
Start Elasticsearch Through Docker
Also, we should have Elastisearch started. The easiest way to do this is to run it through Docker:
Connecting to Elasticsearch
Let's start with connecting our service to Elasticsearch — the implementation in the example project is simple — so it will listen to the Quarkus startup and shutdown events and init or terminate the connections:
The actual job of connecting to the Elasticsearch is done in the AbstractElasticsearchService:
As you can see, the connection here is done in the way suggested in the Elasticsearch documentation. My implementation, it depends on two config properties:
This is the Elasticsearch connection string after starting it from Docker.
The second optional property is:
This is the number of threads needed for the Client.
Now, let’s create our domain object (Fruit):
Creating and Implementing DAO
Creating the Index
Let's create FruitDaoImpl. It is a high-level class built to fill in the AbstractElasticsearchReactiveDaoImplementation and implement the required business logic. The other important part here is to create an index for the Fruit class:
The real create index call to the Elasticsearch is implemented in the parent class (AbstractElasticsearchReactiveDaoImplementation):
Playing With the DAO
Most of the CRUD operations are implemented in the AbstractElasticsearchReactiveDaoImplementation.
deleteById public methods. It also has
findByMatch protected methods. The
FindBy* methods are very helpful in the descendant classes when the business logic needs tobe filled in.
The business find methods are implemented in the FruitDaoImpl class:
Encapsulating DAO in the Service Class
Testing the FruitService
The FruitServiceTests is written in order to test basic functionality. It is also used to ensure that the Fruit class fields are properly indexed and the full-text search is working as expected:
Adding REST Endpoints
Because this is an example project, full CRUD functionality is not added as REST endpoints. Only the
findById are added as REST endpoints. They are added in FruitResource. The methods there return
CompletionStage<Response>, which ensures that there will be no blocked threads in our application.
Testing REST endpoints
FruitResourceTest is added in order to test the RESTendpoints:
Building a Native Executable
Before building a native executable, we have to register our Fruit domain object. The reason for this is that our FruitResource returns
CompletionStage<Response>, and because of that, the actual return type is unknown for the application, so we have to register it explicitly for reflection. There are at least two methods to do that in Quarkus:
I personally prefer the second method because the classes that you want to register might be in a third-party library, and it would be impossible to put the @RegisterForReflection there.
Now, the reflection-config.json looks like this:
The next step is to make Quarkus aware of the reflection-config.json file. You should add this line in to the
native profile in your pom.xml file:
You can now build your native application:
And start it:
Testing the Native Build
The FruitResourceTest expects the following optional property:
If it is present, the test requests will hit the specified host. If you start the native executable:
and execute the tests/build with the following code:
the tests will run against the native build.
I was pleasantly surprised that Elasticsearch works out of the box with Quarkus and can be compiled to native code, which combined with reactive implementation via Project Reactor, will make the footprint of the application almost insignificant.
Opinions expressed by DZone contributors are their own.