java 배우기/TIL

엘라스틱 서치 적용 하기

checkuu 2024. 11. 15. 14:33


docker-compose.yml 에 적용

지금 개발 하는 프로젝트에 엘라스틱 서치 적용을 위해 docker-compose 파일에 설정부터 만들어 줬다.

elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
    container_name: elasticsearch
    environment:
      - node.name=es01
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
      - ELASTIC_PASSWORD=${ES_PASSWORD}
      - xpack.security.enabled=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
      - 9300:9300
    command: >
      /bin/sh -c "if [ ! -d plugins/analysis-nori ]; then 
      bin/elasticsearch-plugin install analysis-nori; 
      fi; 
      /usr/local/bin/docker-entrypoint.sh"

  kibana:
    image: docker.elastic.co/kibana/kibana:7.17.0
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=${ES_USERNAME}
      - ELASTICSEARCH_PASSWORD=${ES_PASSWORD}
    ports:
      - 5601:5601
    depends_on:
      - elasticsearch
    volumes:
      - kibana-data:/usr/share/kibana/data

volumes:
  esdata:
    driver: local
  kibana-data:
    driver: local


기존의 다른 멤버가 docker-compose에 Kafka와 zookeeper 를 사용하고 있어 밑에 해당 설정을 넣어서 같은 컨테이너로 묶었다.

처음에는 엘라스틱서치랑 키바나를 각각의 컨테이너로 만들어서 설정 하고 진행했는데, 키바나가 엘라스틱서치를 인식하지 못해서 로그인이 되지 않는 현상이 발생했다.

 

kibana, elasticsearch 연결 오류
https://checkuu.tistory.com/182

 

키바나에서 엘라스틱서치를 인식 못함.

docker를 이용해서 지금하고 있는 프로젝트에 엘라스틱 서치와 키바나를 연결하여 실행시키는 것까지는 성공 했다.그런데 프로젝트 실행 후 키바나를 켜서 로그인 하면 아래 이미지와 같은 에러

checkuu.tistory.com

 

해결 해준 후 프로젝트 build.gradle에 의존성 주입한다.

 

그리고 elasticsearch에 넣을 데이터를 Document 객체로 새로 만들어서 정의해준다.

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
@Document(indexName = "boards")
public class BoardDocument {

    @Id
    @Field(name = "boards_id", type = FieldType.Long)
    private Long id;

    @Field(name = "title",type = FieldType.Text)
    private String title;

    @Field(name = "content" , type = FieldType.Text)
    private String content;

    @Field(name = "imageUrls" , type = FieldType.Text)
    private String imageUrls;
}

 

기존 Entity에서 왜 Document를 따로 빼서 만들어야 하냐?

 - 엘라스틱서치와 관계형 데이터베이스(RDBMS) 사이의 설계 방식 차이 때문이라 한다.

 

데이터 모델링의 차이:

RDBMSElasticsearch의 데이터 모델은 근본적으로 다릅니다. RDBMS에서는 데이터가 정규화(normalization) 되어 테이블에 저장됩니다. 테이블 간에 관계를 정의하고, 외래키를 사용해 데이터의 관계를 정의합니다.

하지만 Elasticsearch에서는 비정형 데이터를 다루기 때문에, 각 문서가 독립적인 엔티티로 존재합니다. RDBMS에서의 관계형 데이터(예: 게시물과 댓글, 사용자 관계 등)가 Elasticsearch에서 같은 방식으로 저장되지 않으며, 데이터의 중복을 피하거나, 조회 성능을 높이기 위해 문서를 별도로 생성하여 저장합니다.

검색 최적화 :

엘라스틱서치는 검색 성능을 최대화하기 위해 인덱싱을 사용합니다. 이때, Document를 따로 생성하여 저장하는 이유는 인덱스를 효과적으로 만들기 위함입니다.

  • 엘라스틱서치는 각 필드를 인덱싱하여 검색 성능을 최적화합니다. 따라서 검색할 필드만 인덱싱하고, 나머지 필드는 인덱싱하지 않거나 다르게 처리할 수 있습니다.
  • Document를 따로 생성하면, 이 문서 안에서 어떤 필드를 검색 필드로 사용할지, 어떤 필드는 정렬 또는 집계를 위해 사용할지 등을 명시적으로 정의할 수 있습니다.
  • 이를 통해, 검색 속도와 효율성을 높일 수 있습니다.

이러한 이유가 있다고 한다.

 

Document를 생성해 주고난 후 게시판 생성,수정,삭제시 elasticsearch에도 해당 사항이 적용되도록 서비스 로직 변경

//elastic에 저장할 document 생성
BoardDocument boardDocument = new BoardDocument(
        savedBoard.getId(),
        savedBoard.getTitle(),
        savedBoard.getContent(),
        String.join(",", imageUrls));
//elastic에 저장
boardSearchRepository.save(boardDocument);

 

이렇게 변경사항이 저장되도록 수정

데이터가 저장된 후 키바나를 통해 

GET /boards/_search
{
"query": {
"match_all": {}
}
}

 

해당 쿼리로 전부 불러오면 저장된 게시판이 조회되는것 까지 확인 하였다.