Dev

ElasticSearch로 검색 성능 높이기

khjoon 2024. 12. 4. 21:10

intro

검색 기능 구현이 필요한데 elasticsearch를 이용하면 빠르게 검색이 가능하기 때문에 elasticsearch를 도입하기 위해 테스트를 진행해보았습니다.

Springboot 의존성 추가

  • spring boot 버전과 맞는 elasticserach 의존성을 추가해 주기
  • spring boot 2.7.7
    implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch:4.4.2'

elasticsearch docker로 설치하기

  • docker 먼저 설치 
  • docker pull elasticsearch:7.17.3 docker run -d -p 9200:9200 -e "discovery.type=single-node" elasticsearch:7.17.3
  • localhost:9200으로 접속해서 잘 접속되는 것을 확인할 수 있습니다.

kibana도 설치하기

docker pull docker.elastic.co/kibana/kibana:7.17.3
docker run -d --link 9b303be09914:elasticsearch -p 5601:5601 docker.elastic.co/kibana/kibana:7.17.3
  • localhost:5601로 접속하면 성공한것을 확인할 수 있습니다.

elasticsearch 보안 설정

1. /usr/share/elasticsearch/config/elasticsearch.yml에 아래 코드 추가 후 재시작
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

2. /usr/share/elasticsearch/bin 폴더에서 아래 코드 실행후 비밀번호 설정
elasticsearch-setup-passwords interactive

  • 암호가 생성된것을 확인할 수 있습니다.

kibana도 암호를 설정

1. 키바나 접속
docker exec -it {kibana 컨테이너명} /bin/bash
cd config/kibana.yml파일에 아래 내용을 추가했습니다.
elasticsearch.username: "elastic"
elasticsearch.password: "password"

  • 이렇게 암호가 생긴것을 확인할 수 있습니다.

코드 작성

config 파일 작성하기

@Configuration
@EnableElasticsearchRepositories(basePackages = "org.test.elasticSearch.elasticRepository")
public class ElasticConfig {

    @Value("${spring.elastic.url}")
    private String elasticUrl;

    @Bean(destroyMethod = "close")
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(elasticUrl)
                .build();

        return RestClients.create(clientConfiguration).rest();
    }
}

elasticsearch용 repository와 spring용 repository만들기

//elastic
@Repository("elasticSearchRepository")
public interface ItemElasticSearchRepository extends ElasticsearchRepository<ItemDocument, Long> {
}

//spring
@Repository("jpaRepository")
public interface ItemRepository extends JpaRepository<Item, Long> {
}

entity도 elasticsearch용 jpa용 따로 만들기

//elastic
@Document(indexName = "item")
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Data
public class ItemDocument {

    @Id
    private Long id;

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

    @Field(type = FieldType.Keyword)
    private ItemStatus status;

    @Field(type = FieldType.Integer)
    private Integer stock;

    @Field(type = FieldType.Long)
    private Long price;

    @Field(type = FieldType.Integer)
    private Integer deliveryFee;

    @Field(type = FieldType.Keyword)
    private DeliveryType deliveryType;

    @Field(type = FieldType.Integer)
    private Integer deliveryDate;

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

    @Field(type = FieldType.Boolean)
    private Boolean isLimitless;

    @Field(type = FieldType.Date)
    private LocalDate startDate;

    @Field(type = FieldType.Date)
    private LocalDate endDate;

    @Field(type = FieldType.Long)
    private Long viewCount;

    @Field(type = FieldType.Long)
    private Long dibsCount;

    @Field(type = FieldType.Long)
    private Long salesCount;

    @Field(type = FieldType.Integer)
    private Integer tagsCount;

    @Field(type = FieldType.Date)
    private LocalDate createdAt;

    @Field(type = FieldType.Date)
    private LocalDate updatedAt;

    public static ItemDocument from(Item item){
        return ItemDocument.builder()
                .id(item.getId())
                .deliveryDate(item.getDeliveryDate())
                .deliveryFee(item.getDeliveryFee())
                .deliveryType(item.getDeliveryType())
                .createdAt(item.getCreatedAt())
                .endDate(item.getEndDate())
                .description(item.getDescription())
                .dibsCount(item.getDibsCount())
                .isLimitless(item.getIsLimitless())
                .name(item.getName())
                .price(item.getPrice())
                .salesCount(item.getSalesCount())
                .startDate(item.getStartDate())
                .viewCount(item.getViewCount())
                .status(item.getStatus())
                .tagsCount(item.getTagsCount())
                .stock(item.getStock())
                .updatedAt(item.getUpdatedAt())
                .build();

    }


}




//jpa
@Entity
@Table(name = "item")
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Data
public class Item extends BaseDateTimeEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id")
    private Long id;


    @Column(nullable = false, length = 300)
    private String name;

    @Enumerated(EnumType.STRING)
    @Column(columnDefinition = "VARCHAR(20)", nullable = false)
    @ColumnDefault("'ONSALE'")
    private ItemStatus status;

    @Column(length = 6)
    private Integer stock;

    private Long price;

    @Column(nullable = false, length = 6)
    private Integer deliveryFee;

    @Enumerated(EnumType.STRING)
    @Column(columnDefinition = "VARCHAR(20)", nullable = false)
    private DeliveryType deliveryType;

    @Column(nullable = false, length = 2)
    private Integer deliveryDate;

    @Column(columnDefinition = "TEXT", nullable = false)
    private String description;

    @Column(columnDefinition = "BOOLEAN", nullable = false)
    private Boolean isLimitless;

    private LocalDate startDate;

    private LocalDate endDate;

    @Column(nullable = false)
    private Long viewCount;

    @Column(nullable = false)
    private Long dibsCount;

    @Column(nullable = false)
    private Long salesCount;

    @Column
    private Integer tagsCount;

}

이제 elasticsearch에 저장하는 로직 작성

@Service
@Transactional
@AllArgsConstructor
public class ItemService {

    private final ElasticsearchRestTemplate elasticsearchTemplate;
    private final ItemElasticSearchRepository itemElasticSearchRepository;
    private final ItemRepository itemRepository;

    public void save(){
        Item item = itemRepository.findById(1L).orElseThrow();
        itemElasticSearchRepository.save(ItemDocument.from(item));
    }


}

kibana로 확인해보면 잘 저장되는 것을 확인할 수 있습니다.

next

이제 elasticsearch를 더 공부해서 더 많은 기능들을 프로젝트에 적용시켜 보도록 해야겠습니다.