기록

Spring data elasticsearch 4.4 환경 설정

돌멩이1 2024. 4. 17. 19:22

시작하며

이번에 회사에서 엘라스틱 서치를 활용한 기능을 개발하면서 회사 서버 프로젝트에 Spring data elasticsearch를 적용하게 되었습니다.
그러면서 발생했던 이슈들과 해결 방안을 기록하고자 합니다. 보다 나은 해결 방법, 보다 나은 접근 방식이 있다면 알려주시면 감사하겠습니다. 😄

버전

회사의 Elasticsearch 버전은 8.x 버전이어서 Spring data elasticsearch 5.0 버전을 사용하면 좋았을테지만 회사 Spring boot 버전과 호환되지 않아 Spring data elasticsearch 4.4를 사용하였습니다.

  • Spring boot 2.7
  • Spring data elasticsearch 4.4
  • Elasticsearch 8.6

공식문서에 Spring data elasticsearch 4.4에서 5버전의 Elasticsearch client 미리 사용하는 방법이 적혀있어서 따라해보았습니다.
결론만 말씀드리면 Native query를 사용하고 script sort를 사용한다면 RestHighLevelClient를 사용해야합니다. NativeQuery의 withSort 메서드가 Sort 타입만 지원하고 있으며 5.0 이후 버전에서야 여러 타입을 오버로딩해서 지원하기 때문입니다.

Dependency & Configuration

implementation("org.springframework.boot:spring-boot-starter-data-elasticsearch")

build.gradle에 Spring data elasticsearch 의존성을 추가해줍니다.

@Configuration
public class ElasticsearchConfiguration extends AbstractElasticsearchConfiguration {

    private final String host;
    private final int port;

    public ElasticSearchConfiguration(
            @Value("${elasticsearch.host}") String host, @Value("${elasticsearch.port}") int port) {
        this.host = host;
        this.port = port;
    }

    public ClientConfiguration clientConfiguration() {
        String hostAndPort = String.format("%s:%d", host, port);
        return ClientConfiguration.builder()
                .connectedTo(hostAndPort)
                .build();
    }

    @Bean
    @Override
    public RestHighLevelClient elasticsearchClient() {
        return RestClients.create(clientConfiguration).rest();                         
    }
}

구동 환경에 따라 host, port를 다르게 주입받을 수 있도록 @Value 를 사용하여 host, port를 주입받도록 하였습니다.
connectTimeout, socketTimeout은 별도 설정하지 않은 경우 각각 10초, 5초를 기본 값으로 갖고있습니다.

Spriung data elsticsearch 4버전, Elasticsearch 8 버전 이상을 사용하는 경우 호환성을 위한 헤더를 추가해야한다고 합니다. 링크 살펴보았을 때 8+ 이상 버전에서는 지원하지 않는 형식의 쿼리를 시도했을 때 오류를 발생하지 않게 해준다는 것 같았습니다. Elasticsearch 7.x 버전을 사용하다가 8.x 버전으로 올린 것은 아닌 상황이라 해당 부분은 고려하지 않았습니다.

Request & Response

@Respository
class ElasticsearchRepository {

    private final ElasticsearchOperations restTemplate;

    @ReadOnlyProperty // @Tansactional(readOnly=true)와 같은 역할로 읽기 전용을 명시합니다.
    public void search() {

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
            .filter(QueryBuilders.existsQuery("birthday"))
            .filter(QueryBuilders.rangeQuery("age".gte(18))
            .should(QueryBuilders.multiMatchQuery(
                    "김철수",
                    "name",
                    "nickname")
                .type(MultiMatchQueryBuilder.Type.BOOL_PREFIX)
                .minimumShouldMatch("1")
            .minimumShouldMatch(1)

        NativeSearchQuery query = new NativeSearchQueryBuilder()
            .withSourceFilter(new FetchSourceFilter(new String[]{"userId"}, null))
            .withQuery(queryBuilder)
            .build();  

        SearchHits<UserDocuemtn> result = restTemplate.search(query, UserDocument.class, "user");
    }
}
  • NativeSearchQueryBuilder에서 .withPageable() 를 명시하지 않는다면 기본 값은 "from" : 0, "size": 10 으로 지정됩니다.
  • 요청에 대한 응답은 search()의 clazz 타입의 필드만 가져오는 것이 아니라 해당되는 document의 모든 필드들을 가져오고 있습니다. 때문에 특정 필드들만 가져오고 싶은 경우 withSourceFilter를 사용해 쿼리에 source 를 정의해주는 것이 좋습니다.
  • 쿼리에서 "_source":false로 source disabling 하는 방법이 있는데 Spring data elasticsearch 4.4 ElasticsearchRestTemplate에서는 방법을 찾을 수 없었습니다. 방법으로는 SearchRequest를 직접 생성해서 쿼리를 요청하는 방법이 있습니다.

Spring data elasticsearch 4.4에서 제공하는 기능만을 사용할 때에는 큰 어려움이 없었습니다.
이후 Spring data elasticsearch 4.4에서 New client를 사용하려고 했을 때 발생했던 문제들을 포스팅해보도록 하겠습니다.

'기록' 카테고리의 다른 글

[Docker] MySQL/mariadb 한글 인코딩 오류  (0) 2022.05.26