[ES] Spring Boot 에서 ES 사용하기 (인덱스편)

mallin·2022년 5월 4일
1

ElasticSearch

목록 보기
9/9
post-thumbnail

클라이언트 모듈

지금까지 사용하던 HTTP 방식은 단 건의 요청을 처리하기에는 편리하지만 대량의 요청을 처리하기에는 적합하지 않습니다. 그렇기 때문에 엘라스틱서치에서는 다양한 프로그래밍 언어에서 직접적으로 사용할 수 있는 라이브러리를 개발해서 제공합니다.

ES 에서 지원하는 클라이언트 모듈은 https://www.elastic.co/guide/en/elasticsearch/client/index.html 에서 확인할 수 있습니다.

현재 (2022년 5월 4일 기준)

위와 같은 클라이언트 모듈을 지원하고 있습니다.

원래 자바 클라이언트에는

① 내부적으로 HTTP 방식으로 REST API 를 사용해 접근하는 방식
(Java REST Client, Java High Level REST Client)

② 네티(Netty) 모듈을 이용해 네이티브 클라이언트를 통해 접근 하는 방식
(Java Transport Client, Java CLient)

으로 총 두가지 클라이언트 모듈이 있는데 2번째 방식은 버전 8 기준으로 종료되었습니다.

Transport 방식이 종료되고, REST 클라이언트를 사용해야 하는 이유는 다음과 같습니다.

  • Transport 클라이언트와 REST 클라이언트의 가장 큰 차이는 클라이언트의 요청을 객체로 하냐 HTTP 로 하냐의 차이이다.
  • REST 클라이언트의 요청은 JSON이 서버에 그대로 전달되는 것에 반해 Transport 클라이언트의 요청은 JSON 을 파싱하고 이를 자바 객체로 반환한 다음, Transport Network 계층을 통해 바이너리 형식으로 서버에 전달된다.
  • 이론적으로 봤을 때 Transport 클라이언트 방식이 성능 측면에서 우수할 수 밖에 없지만, REST 방식의 기술적인 발전으로 성능이 거의 비슷하게 나온다.
  • REST 클라이언트를 사용할 경우 보안 측변에서 HTTPS 를 사용하는것이 가능해지며, 이를 통해 클러스터의 보안을 강화할 수 있기 때문에 REST 클라이언트를 사용한다.

이번 예제에서도 REST 클라이언트 방식을 사용해서 구현해보도록 하겠습니다.
코드는 ⭐️ https://github.com/soyeon207/velog_example/tree/master/es-test-server ⭐️ 여기에서 확인하실 수 있습니다.

ES 환경 설정하기

  1. build.gradle 에 elasticsearch 관련 추가
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
    implementation 'org.springframework.boot:spring-boot-starter-web'
}
  1. application.yml 에 elasticsearch 관련 설정 추가
server:
  port: 8003

elasticsearch:
  host: localhost
  port: 9200
  indecies:
    studentsIndexName: students
    testIndexName: tests
  1. EsProperties & EsConfig 설정

EsProperties :: ES 연결할 때 필요한 데이터들을 설정해주는 파일

@Component
@Setter
@ConfigurationProperties(prefix = "elasticsearch")
public class EsProperties {

    private String host;        // ES 호스트
    private int port;           // ES 포트
    private Indices indecies;   // ES 인덱스 정보

    public HttpHost httpHost() {
        return new HttpHost(host, port, "http");
    }

    public String getStudentIndexName() {
        return Optional.ofNullable(indecies).map(Indices::getStudentsIndexName).orElse(null);
    }

    public String getTestIndexName() {
        return Optional.ofNullable(indecies).map(Indices::getTestIndexName).orElse(null);
    }

    @Getter
    @Setter
    public static class Indices {
        String studentsIndexName;
        String testIndexName;
    }

}

EsConfig :: ES connect 관련 설정 파일

@Configuration
@RequiredArgsConstructor
public class EsConfig extends AbstractElasticsearchConfiguration {

    private final EsProperties esProperties;

    @Override
    public RestHighLevelClient elasticsearchClient() {
        // https://discuss.elastic.co/t/localhost-nodename-nor-servname-provided-or-not-known/186173/11
        return new RestHighLevelClient(RestClient.builder(esProperties.httpHost()));
    }
}

인덱스 관련 API 연동

인덱스 생성

인덱스 생성은 sync(동기) 와 async(비동기) 로 할 수 있습니다.

동기 인덱스 생성 API

// ①
CreateIndexRequest request = new CreateIndexRequest(esProperties.getTestIndexName()); 
// ②
request.settings(Settings.builder() 
		.put("index.number_of_shards", 1)
		.put("index.number_of_replicas", 0));

try {
	// ③
	CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
	return createIndexResponse.isAcknowledged();
} catch (Exception e) {
	log.error("인덱스 생성에 실패했습니다. 원인 : " + e.getMessage());
	return false;
}

① 인덱스 생성은 CreateIndexRequest 를 통해서 할 수 있습니다. new CreateIndexRequest 로 객체를 생성해주고, 생성자 파라미터로 생성하고자 하는 인덱스 이름을 넣어줍니다. 이전에 설정했던 EsProperties 에 있는 getTestIndexName 메소드를 통해 tests 라는 인덱스를 만들어주도록 하겠습니다.

② 만들어질 인덱스에 샤드와 레플리카의 개수를 설정해줍니다.
해당 예제에서는 샤드의 개수는 1개, 레플리카의 개수를 0 개로 설정해주도록 하겠습니다.

③ client (RestHighLevelClient) 를 통해 tests 라는 인덱스를 만들어줍니다.
위에서 설정한 CreateIndexRequest 와 RequestOptions 를 파라미터로 넘겨주면 되는데 RequestOptions 의 경우에는 headers, parameters ... 등등을 커스텀하게 설정할 수 있습니다. 만일 커스텀하게 설정할 필요가 있는 경우 미리 선언되어 있는 RequestOptions.DEFAULT 를 사용하면 됩니다.

비동기 인덱스 생성 API

CreateIndexRequest request = new CreateIndexRequest(esProperties.getTestIndexName());
        request.settings(Settings.builder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 0));

		// ②
        ActionListener<CreateIndexResponse> listener = new ActionListener<CreateIndexResponse>() {
            @Override
            public void onResponse(CreateIndexResponse createIndexResponse) {
                System.out.println("성공!!");
            }

            @Override
            public void onFailure(Exception e) {
                log.error("인덱스 생성에 실패했습니다. 원인 : " + e.getMessage());
            }
        };
		
        // ①
        client.indices().createAsync(request, RequestOptions.DEFAULT, listener);

① 동기 방식과 거의 동일하지만 비동기 방식은 createAysnc 메소드를 사용합니다.
② 비동기 방식으로 실행될 코드를 설정해줍니다. onResponse 는 성공했을 때 실행할 메소드이고, onFailure 는 실패했을 때 실행할 메소드입니다.

인덱스 삭제

try {
	// ①
    DeleteIndexRequest request = new DeleteIndexRequest(esProperties.getTestIndexName());
    return client.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (Exception e) {
    log.error("인덱스 삭제에 실패했습니다. 원인 : " + e.getMessage());
    return false;
}

① 인덱스 삭제는 DeleteIndexRequest 를 사용합니다.
위와 동일하게 cleint(RestHighLevelClient) 를 사용하되 delete 메소드를 이용해 인덱스를 삭제해줍니다.

인덱스 오픈 & 닫기

인덱스 오픈 / 닫기 ?
이게 무슨 소린가 할 수 있지만, ElasticSearch 에서는 인덱스를 오픈하거나 닫을 수 있습니다.
오픈하는 건 인덱스를 사용할 수 있는 상태, 닫는 건 인덱스를 사용할 수 없는 상태입니다.

인덱스를 닫았을 때에는 인덱스의 상태를 조회 (GET /_cat/indices?pretty) 하면 상태가 close 로 노출되고,

인덱스를 사용하려고 해도 에러가 발생됩니다.

인덱스 오픈

try {
	// ①
    OpenIndexRequest request = new OpenIndexRequest(esProperties.getTestIndexName());
    return client.indices().open(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (Exception e) {
    log.error("인덱스 오픈을 실패했습니다. 원인 : " + e.getMessage());
    return false;
}

① 인덱스 오픈은 OpenIndexRequest 를 사용합니다.

인덱스 닫기

try {
	// ①
    CloseIndexRequest request = new CloseIndexRequest(esProperties.getTestIndexName());
    return client.indices().close(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (Exception e) {
    log.error("인덱스 닫기를 실패했습니다. 원인 : " + e.getMessage());
    return false;
}

① 인덱스 닫기는 CloseIndexRequest 를 사용합니다.

🙇🏼‍♀️ 레퍼런스

SpringBoot + ElasticSearch 연동 및 간단 API 호출해보기
Elasticsearch Java Rest High Level Client 사용하기[elasticsearch + Spring] elasticsearch를 Java Spring에서 사용해보자 - 환경설정과 Index 만들기

0개의 댓글