In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article focuses on "how to use Quarkus to respond in Elasticsearch". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to use Quarkus to be responsive in Elasticsearch.
Create Quarkus project mvn io.quarkus:quarkus-maven-plugin:1.0.1.Final:create\-DprojectGroupId=org.otaibe.quarkus.elasticsearch.example\-DprojectArtifactId=otaibe-quarkus-elasticsearch-example\-DclassName= "org.otaibe.quarkus.elasticsearch.example.web.controller.FruitResource"\-Dpath= "/ fruits"\-Dextensions= "resteasy-jackson,elasticsearch-rest-client" Maven setting
As you can see, there is an elasticsearch-rest-client in Quarkus; however, this is an Elasticsearch Java low-level REST client. If we want to use Elasticsearch Java High Level REST Client, we just need to add it to the pom.xml file as a dependency:
Org.elasticsearch.client elasticsearch-rest-high-level-client 7.4.0
Make sure that the version of Elasticsearch Java Low Level REST Client matches Elasticsearch Java High Level REST Client.
Because we use Elasticsearch in a responsive manner, I prefer to use Project Reactor. We must add BOM to the dependency management section:
Io.projectreactor reactor-bom Dysprosium-SR2 pom import
We must also add reactor-core as a dependency:
Io.projectreactor reactor-core
I have separated the common code in a library, so we should add this library to our sample project. To do this, we will use Jitpack. This is a great service. You just need to point out the right method for your Github project, and it will build an artifact for it. This is how I use it:
Com.github.tpenakov.otaibe-commons-quarkus otaibe-commons-quarkus-core elasticsearch-example.02 com.github.tpenakov.otaibe-commons-quarkus otaibe-commons-quarkus-elasticsearch elasticsearch-example.02 com.github.tpenakov.otaibe-commons-quarkus otaibe-commons-quarkus-rest elasticsearch-example.02 starts Elasticsearch through Docker
In addition, we should start Elastisearch. The easiest way is to run it through Docker:
Docker run-it-- rm=true-- name elasticsearch_quarkus_test\-p 11027rm=true 9200-p 11028 name elasticsearch_quarkus_test 9300\-e "discovery.type=single-node"\ docker.elastic.co/elasticsearch/elasticsearch:7.4.0 connects to Elasticsearch
Let's start by connecting our service to Elasticsearch-- the implementation in the example project is simple-- so it will listen for Quarkus startup and shutdown events and initialize or terminate the connection:
Package org.otaibe.quarkus.elasticsearch.example.service;import io.quarkus.runtime.ShutdownEvent;import io.quarkus.runtime.StartupEvent;import lombok.Getter;import lombok.Setter;import lombok.extern.slf4j.Slf4j;import org.otaibe.commons.quarkus.elasticsearch.client.service.AbstractElasticsearchService;import javax.enterprise.context.ApplicationScoped;import javax.enterprise.event.Observes;@ApplicationScoped@Getter@Setter@Slf4jpublic class ElasticsearchService extends AbstractElasticsearchService {public void init (@ Observes StartupEvent event) {log.info ("init started") Super.init (); log.info ("init completed");} public void shutdown (@ Observes ShutdownEvent event) {log.info ("shutdown started"); super.shutdown (); log.info ("shutdown completed");}}
The actual work of connecting to Elasticsearch is done in AbstractElasticsearchService:
Public abstract class AbstractElasticsearchService {@ ConfigProperty (name = "service.elastic-search.hosts") String [] hosts; @ ConfigProperty (name = "service.elastic-search.num-threads", defaultValue = "10") Optional numThreads; private RestHighLevelClient restClient; private Sniffer sniffer; @ PostConstruct public void init () {log.info ("init started") List httpHosts = Arrays.stream (hosts) .map (s-> StringUtils.split (s,':')) .map (strings-> new HttpHost (strings [0], Integer.valueOf (strings [1])) .map (Collectors.toList ()); RestClientBuilder builder = RestClient.builder (new HttpHost [httpHosts.size ()]) GetNumThreads () .ifPresent (integer-> builder.setHttpClientConfigCallback (httpClientBuilder-> httpClientBuilder.setDefaultIOReactorConfig (IOReactorConfig. Custom (). SetIoThreadCount (integer). Build (); restClient = new RestHighLevelClient (builder) Sniffer = Sniffer.builder (getRestClient (). GetLowLevelClient ()) .build (); log.info ("init completed");}}
As you can see, the connection here is done as recommended in the Elasticsearch documentation. My implementation depends on two configuration properties:
Properties file:
Service.elastic-search.hosts=localhost:11027
This is the Elasticsearch connection string started from Docker. The second optional attribute is: properties file
Service.elastic-search.num-threads
This is the number of threads required by the client.
Create POJO
Now, let's create a domain object (Fruit):
Package org.otaibe.quarkus.elasticsearch.example.domain;import com.fasterxml.jackson.annotation.JsonProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@NoArgsConstructor@AllArgsConstructor (staticName = "of") public class Fruit {public static final String ID = "id"; public static final String EXT_REF_ID = "ext_ref_id"; public static final String NAME = "name"; public static final String DESCRIPTION = "description"; public static final String VERSION = "version" @ JsonProperty (ID) public String id; @ JsonProperty (EXT_REF_ID) public String extRefId; @ JsonProperty (NAME) public String name; @ JsonProperty (DESCRIPTION) public String description; @ JsonProperty (VERSION) public Long version;} create and implement DAO index creation
Let's create a FruitDaoImpl. It is an advanced class that populates AbstractElasticsearchReactiveDaoImplementation and implements the required business logic. Another important part here is to create an index for the Fruit class:
@ Overrideprotected Mono createIndex () {CreateIndexRequest request = new CreateIndexRequest (getTableName ()); Map mapping = new HashMap (); Map propsMapping = new HashMap (); propsMapping.put (Fruit.ID, getKeywordTextAnalizer ()); propsMapping.put (Fruit.EXT_REF_ID, getKeywordTextAnalizer ()); propsMapping.put (Fruit.NAME, getTextAnalizer (ENGLISH)); propsMapping.put (Fruit.DESCRIPTION, getTextAnalizer (ENGLISH)); propsMapping.put (Fruit.VERSION, getLongFieldType ()) Mapping.put (PROPERTIES, propsMapping); request.mapping (mapping); return createIndex (request);}
The actual indexing call to Elasticsearch is implemented in the parent class (AbstractElasticsearchReactiveDaoImplementation):
Protected Mono createIndex (CreateIndexRequest request) {return Flux.create (fluxSink-> getRestClient (). Indices (). CreateAsync (request, RequestOptions.DEFAULT, new ActionListener () {@ Override public void onResponse (CreateIndexResponse createIndexResponse) {log.info ("CreateIndexResponse: {}", createIndexResponse); fluxSink.next (createIndexResponse.isAcknowledged ()); fluxSink.complete () } @ Override public void onFailure (Exception e) {log.error ("unable to create index", e); fluxSink.error (new RuntimeException (e));}}) .Next ();} play DAO
Most CRUD operations are implemented in AbstractElasticsearchReactiveDaoImplementation.
It has save, update, findById, and deleteById public methods. It also has findByExactMatch and findByMatch protection methods. FindBy* these methods are useful in descendant classes when you need to populate business logic.
The business lookup method is implemented in the FruitDaoImpl class:
Public Flux findByExternalRefId (String value) {return findByMatch (Fruit.EXT_REF_ID, value);} public Flux findByName (String value) {return findByMatch (Fruit.NAME, value);} public Flux findByDescription (String value) {return findByMatch (Fruit.NAME, value);} public Flux findByNameOrDescription (String value) {Map query = new HashMap (); query.put (Fruit.NAME, value); query.put (Fruit.DESCRIPTION, value); return findByMatch (query);} encapsulate DAO in Service class
FruitDaoImpl is encapsulated in FruitService:
@ ApplicationScoped@Getter@Setter@Slf4jpublic class FruitService {@ Inject FruitDaoImpl dao; public Mono save (Fruit entity) {return getDao () .save (entity);} public Mono findById (Fruit entity) {return getDao () .findById (entity);} public Mono findById (String id) {return Mono.just (Fruit.of (id, null, null)) .flatMap (entity-> findById (entity)) } public Flux findByExternalRefId (String value) {return getDao () .findByExternalRefId (value);} public Flux findByName (String value) {return getDao () .findByName (value);} public Flux findByDescription (String value) {return getDao () .findByDescription (value);} public Flux findByNameOrDescription (String value) {return getDao () .findByNameOrDescription (value) } public Mono delete (Fruit entity) {return Mono.just (entity.getId ()) .filter (s-> StringUtils.isNotBlank (s)) .flatMap (s-> getDao () .deleteById (entity)) .defaultIfEmpty (false);}} Test FruitService
The FruitServiceTests is written to test basic functionality. It is also used to ensure that Fruit class fields are indexed correctly and that full-text search works as expected:
@ Testpublic void manageFruitTest () {Fruit apple = getTestUtils (). CreateApple (); Fruit apple1 = getFruitService (). Save (apple). Block (); Assertions.assertNotNull (apple1.getId ()); Assertions.assertTrue (apple1.getVersion () > 0); log.info ("saved result: {}", getJsonUtils (). ToStringLazy (apple1)); List fruitList = getFruitService (). FindByExternalRefId (TestUtils.EXT_REF_ID). CollectList (). Block () Assertions.assertTrue (fruitList.size () > 0); List fruitList1 = getFruitService (). FindByNameOrDescription ("bulgaria"). CollectList (). Block (); Assertions.assertTrue (fruitList1.size () > 0); / / Ensure that the full text search is working-it is' Apples' in description List fruitList2 = getFruitService (). FindByDescription ("apple"). CollectList (). Block (); Assertions.assertTrue (fruitList2.size () > 0) / / Ensure that the full text search is working-it is' Apple' in name List fruitList3 = getFruitService (). FindByName ("apples"). CollectList (). Block (); Assertions.assertTrue (fruitList3.size () > 0); Boolean deleteAppleResult = getFruitService (). GetDao (). DeleteById (apple1). Block (); Assertions.assertTrue (deleteAppleResult);} add REST endpoints
Because this is a sample project, the full CRUD functionality will not be added as an REST endpoint. Only save and findById are added as REST endpoints. They are added to the FruitResource. The method there returns CompletionStage, which ensures that there are no blocked threads in our application.
Test REST Endpoint
Add FruitResourceTest to test RESTendpoints:
Package org.otaibe.quarkus.elasticsearch.example.web.controller;import io.quarkus.test.junit.QuarkusTest;import lombok.AccessLevel;import lombok.Getter;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.eclipse.microprofile.config.inject.ConfigProperty;import org.junit.jupiter.api.Assertions;import org.junit.jupiter.api.Test;import org.otaibe.commons.quarkus.core.utils.JsonUtils;import org.otaibe.quarkus.elasticsearch.example.domain.Fruit Import org.otaibe.quarkus.elasticsearch.example.service.FruitService;import org.otaibe.quarkus.elasticsearch.example.utils.TestUtils;import javax.inject.Inject;import javax.ws.rs.core.HttpHeaders;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response;import javax.ws.rs.core.UriBuilder;import java.net.URI;import java.util.Optional;import static io.restassured.RestAssured.given @ QuarkusTest@Getter (value = AccessLevel.PROTECTED) @ Slf4jpublic class FruitResourceTest {@ ConfigProperty (name = "service.http.host") Optional host; @ Inject TestUtils testUtils; @ Inject JsonUtils jsonUtils; @ Test public void restEndpointsTest () {log.info ("restEndpointsTest start"); Fruit apple = getTestUtils () .createApple () Fruit savedApple = given () .when () .header (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) .body (apple) .post (getUri (FruitResource.ROOT_PATH)) .then () .statusCode (2000.extract () .as (Fruit.class)) String id = savedApple.getId (); Assertions.assertTrue (StringUtils.isNotBlank (id)); URI findByIdPath = UriBuilder.fromPath (FruitResource.ROOT_PATH) .path (id) .build () Fruit foundApple = given () .when () .get (getUri (findByIdPath.getPath ()). GetPath ()). Then () .statusCode (200) .extract () .as (Fruit.class); Assertions.assertEquals (savedApple, foundApple); Boolean deleteResult = getService (). Delete (foundApple). Block () Assertions.assertTrue (deleteResult); given (). When (). Get (findByIdPath.getPath ()). Then () .statusCode (Response.Status.NOT_FOUND.getStatusCode ()); log.info ("restEndpointsTest end");} private URI getUri (String path) {return getUriBuilder (path) .build () } private UriBuilder getUriBuilder (String path) {return getHost () .map (uri-> UriBuilder.fromUri (uri)) .map (uriBuilder-> uriBuilder.path (path)) .orElse (UriBuilder .fromPath (path));} build a local executable
Before building the native executable, we must register our Fruit domain object. The reason for this is that our FruitResource returns CompletionStage, so the actual return type of the application is unknown, so we must explicitly register it for reflection. There are at least two ways to do this in Quarkus:
Annotated by @ RegisterForReflection.
Through reflection-config.json.
I personally prefer the second method, because the class you want to register may be in a third-party library, and it's impossible to put @ RegisterForReflection there.
Now, reflection-config.json looks like this:
[{"name": "org.otaibe.quarkus.elasticsearch.example.domain.Fruit", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true, "allDeclaredFields": true, "allPublicFields": true}]
The next step is to let Quarkus know about the reflection-config.json file. You should add this line to the native configuration file in the pom.xml file:
-project.basedir ReflectionConfigurationFilesystems ${ReflectionConfigurationFilesystems / src/main/resources/reflection-config.json
You can now build your native application:
Mvn clean package-Pnative
And start it:
. / target/otaibe-quarkus-elasticsearch-example-1.0-SNAPSHOT-runner
The service will be available on http://localhost:11025 because this is the port explicitly specified in application.properties.
Quarkus.http.port=11025 testing the establishment of this organization
The FruitResourceTest expects the following optional attributes:
Properties file:
Service.http.host
If present, the test request will hit the specified host. If you start the native executable:
Shell:
. / target/otaibe-quarkus-elasticsearch-example-1.0-SNAPSHOT-runner
And perform the test / build using the following code:
Shell:
Mvn package-D% test.service.http .host = http://localhost:11025
The test will be built and run against this organization.
At this point, I believe you have a deeper understanding of "how to use Quarkus to respond in Elasticsearch". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.