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를 더 공부해서 더 많은 기능들을 프로젝트에 적용시켜 보도록 해야겠습니다.