본문 바로가기

삽질

[Spring Boot] nested exception is ElasticsearchException[Elasticsearch exception [type=no_such_file_exception, reason=/usr/share/elasticsearch/config/settings/stop/english.txt]]

이 글은 이전 글과 연관되어 있습니다.

 

저는 불용어(stopword) 동의어(synonym) 별도의 파일로 관리하고 있습니다.

 

아래의 코드로 nori 분석기를 설치할 수 있었으나,

불용어와 동의어 파일을 불러오는 부분이 없다는 것을 알 수 있습니다.

@TestConfiguration
@EnableElasticsearchRepositories(basePackageClasses = UserSearchRepository.class)
public class ElasticTest extends AbstractElasticsearchConfiguration {

    private static final GenericContainer container;

    static{
        container = new GenericContainer(
                new ImageFromDockerfile().withDockerfileFromBuilder(
                        b -> {
                            b.from("docker.elastic.co/elasticsearch/elasticsearch:7.10.2")
                                    .run("bin/elasticsearch-plugin install analysis-nori")
                                    .build();
                        })
        ).withExposedPorts(9200, 9300).withEnv("discovery.type","single-node");
        container.start();
    }
    ....
}

 

관련 레퍼런스를 찾아본 결과, 해결 방법을 찾았습니다.

GenericContainer가 제공하는 withFileSystemBind를 사용하시면됩니다.

 

withFileSystemBind는 세 가지 인수를 받습니다.

// hostPath : 바인딩할 호스트 파일 경로 (상대경로 가능)
// containerPath : 컨테이너 내부에 저장할 위치 (절대경로'만' 가능)
// bindMode : 바인딩 방법 (READ_ONLY, READ_WRITE)

new GenericContainer(...)
        .withFileSystemBind(hostPath, containerPath, bindMode)

 

주의할 점은 두 번째 인수인 contianerPath는 컨테이너의 절대경로를 적어야합니다.

아니면 아래의 에러를 만날 것입니다.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userSearchRepository' defined in com.example.es_springboot.repository.es.UserSearchRepository defined in @EnableElasticsearchRepositories declared on ElasticTest: Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository]: Constructor threw exception; nested exception is RestStatusException{status=400} org.springframework.data.elasticsearch.RestStatusException: Elasticsearch exception [type=illegal_argument_exception, reason=IOException while reading stopwords_path: /usr/share/elasticsearch/config/settings/stop/english.txt]; nested exception is ElasticsearchException[Elasticsearch exception [type=no_such_file_exception, reason=/usr/share/elasticsearch/config/settings/stop/english.txt]]

 

엘라스틱서치 컨테이너의 절대 경로는 /usr/share/elasticsearch 입니다.

즉, 아래와 같이 하면 정상적으로 테스트 컨테이너를 만들 수 있을 것입니다.

@TestConfiguration
@EnableElasticsearchRepositories(basePackageClasses = UserSearchRepository.class)
public class ElasticTest extends AbstractElasticsearchConfiguration {

    private static final GenericContainer container;

    static{
        container = new GenericContainer(
                new ImageFromDockerfile().withDockerfileFromBuilder(
                        b -> {
                            b.from("docker.elastic.co/elasticsearch/elasticsearch:7.10.2")
                                    .run("bin/elasticsearch-plugin install analysis-nori")
                                    .build();
                        })
        ).withExposedPorts(9200, 9300)
                .withFileSystemBind(
                        "es/settings/stop/english.txt",
                        "/usr/share/elasticsearch/config/settings/stop/english.txt",
                        BindMode.READ_ONLY)
                .withFileSystemBind(
                        "es/settings/synonym/english.txt",
                        "/usr/share/elasticsearch/config/settings/synonym/english.txt",
                        BindMode.READ_ONLY)
                .withEnv("discovery.type","single-node");
        container.start();
    }
    ...
}

 

참고

https://velog.io/@backtony/Spring-Data-Elasticsearch-%EC%97%B0%EB%8F%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0