ElasticSearch + SpringBoot 검색 기능 만들기

henu·2024년 9월 2일

ElasticSearch


ElasticSearch란


ElasticSearch는 분산형 RESTful 검색 및 분석 엔진이다.
검색에 최적화된 엔진인 만큼 로깅 서치 등에 많이 활용되고 있다.

RDB와 어떻게 다를까


RDB는 행 단위로 데이터를 저장한다.

저장과 삭제가 편하지만 특정 조건을 검색할 경우 모든 데이터를 탐색해야 하는 단점이 있다.

ElasticSearch는 역인덱스를 통해 단어 기반으로 데이터를 조회한다.

역인덱스 기반이기 때문에 검색에는 좋은 성능을 보이지만 삭제의 경우 RDB에 비해 비효율적이다.

docker compose로 elastic search 설정하기


services:
  es:
    container_name: es
    image: docker.elastic.co/elasticsearch/elasticsearch:7.15.2
    environment:
      - node.name=single-node
      - cluster.name=backtony
      - discovery.type=single-node
    ports:
      - 9200:9200
      - 9300:9300
    networks:
      - es-bridge

  kibana:
    container_name: kibana
    image: docker.elastic.co/kibana/kibana:7.15.2
    environment:
      SERVER_NAME: kibana
      ELASTICSEARCH_HOSTS: http://es:9200
    ports:
      - 5601:5601
    # Elasticsearch Start Dependency
    depends_on:
      - es
    networks:
      - es-bridge

networks:
  es-bridge:
    driver: bridge

kibana는
엘라스틱서치의 소스 이용이 가능한 데이터 시각화 대시보드 소프트웨어이다.

window 환경에서는 docker desktop까지 실행시켜야한다.

docker compose -f els.yml up -d

http://localhost:5601 로 접속하면

잘 작동하는 것을 확인할 수 있다.

SpringBoot 세팅하기


의존성 추가하기

implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'

Configuration
@Configuration
@EnableElasticsearchRepositories(basePackages = "org.springframework.data.elasticsearch.repository")
public class ElasticSearchConfig extends ElasticsearchConfiguration {

    @Override
    public ClientConfiguration clientConfiguration() {
        return ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .build();
    }
}
Entity
@Entity
@Document(indexName = "article")
@Mapping(mappingPath = "static/elastic-mapping.json")
@Setting(settingPath = "static/elastic-token.json")
@NoArgsConstructor
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Field(name = "id", type = FieldType.Keyword)
    private Long id;

    @Column
    @Field(type = FieldType.Text)
    private String title;

    @Column
    @Field(type = FieldType.Text)
    private String content;

    @Column
    @Field(type = FieldType.Text)
    private String image;

    @Column
    @Field(type = FieldType.Text)
    private String description;

    @Column
    @Field(type = FieldType.Keyword)
    private SectionType section;

    @Column
    @Field(type = FieldType.Text)
    private String name;

    @Column
    @Field(type = FieldType.Date, format = {}, pattern = "uuuu-MM-dd")
    private LocalDate date;

    @Builder
    public Article(String title, String content, String image, String description, SectionType section, String name, LocalDate date) {
        this.title = title;
        this.content = content;
        this.image = image;
        this.description = description;
        this.section = section;
        this.name = name;
        this.date = date;
    }
}
  • @Document를 통해 ElasticSearch의 "article" 인덱스에 매핑한다.
  • @Mapping, @Satting을 통해 클래스에 해당하는 매핑/세팅 정보를 json파일에서 가져온다.
  • 여기서는 @Field를 통해 매핑되었다.
Repository
public interface ArticleSearchRepository extends ElasticsearchRepository<Article, Long> {
    List<Article> findByTitle(String title);
}

제목으로 검색할 수 있게 하였다.

Service
    public void registArticle(Member member, RegistArticleDto.Request request) {
        String name = member.getName();
        Article article = request.toArticle(name);
        Article savedArticle = articleRepository.save(article);
        articleSearchRepository.save(savedArticle);
    }

ElasticSearch에서는 Id값이 자동으로 생성되지 않기 때문에 JPA를 통해 저장한 후 반환되는 값을 사용해 ElasticSearch에 저장해주었다.

  1. Elastic Search를 사용한 조회(15ms)

  2. JPA에서 contains를 사용한 조회(158ms)

profile
주니어 백엔드 개발자입니다

0개의 댓글