💻문제점1: CreatedAt 필드 타입
post-mappings.json
{
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "korean"
},
"content": {
"type": "text",
"analyzer": "korean"
},
"createdAt": {
"type": "date",
"format": "yyyy-MM-dd'T'HH:mm:ss.SSSSSS||epoch_millis"
},
"imageUrl": {
"type": "text"
},
"tags": {
"type": "keyword"
}
}
}
PostDocument
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Document(indexName = "posts")
@Setting(settingPath = "elastic/post-setting.json")
@Mapping(mappingPath = "elastic/post-mapping.json")
public class PostDocument {
@Id
private Long id;
private String title;
private String content;
private LocalDateTime createdAt;
private String imageUrl;
private List<String> tags;
@Builder
public PostDocument(
Long id,
String title,
String content,
LocalDateTime createdAt,
String imageUrl,
List<String> tags) {
this.id = id;
this.title = title;
this.content = content;
this.createdAt = createdAt;
this.imageUrl = imageUrl;
this.tags = tags;
}
}
PostElasticRepository
@Repository
public interface PostElasticRepository extends ElasticsearchRepository<PostDocument, Long> {
List<PostDocument> findByTitleContaining(String title);
}
Elasticsearch를 사용한 데이터 검색이 정상 동작하는지 확인하기 위해 간단히 검색 api를 만들어 테스트했다.
'http://localhost:8080/api/v1/posts/elastic?keyword=오늘'로 요청을 보냈을 때, 다음과 같은 오류가 발생했다.
No converter found capable of converting from type [java.lang.Long] to type [java.time.LocalDateTime]
🔍문제점1-해결
Kibana를 통해 생성된 posts 인덱스를 확인해보니, createdAt 필드 타입이 date 타입이 아닌 long 타입으로 생성되었다.
kibana > dev tools 를 통해 인덱스를 직접 생성해주었다.
PUT /posts
{
"settings": {
"analysis": {
"analyzer": {
"english": {
"type": "whitespace"
},
"korean": {
"type": "nori"
}
}
}
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "korean"
},
"content": {
"type": "text",
"analyzer": "korean"
},
"createdAt": {
"type": "date",
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS||epoch_millis"
},
"imageUrl": {
"type": "text"
},
"tags": {
"type": "keyword"
}
}
}
}
💻문제점2: _class 필드 역직렬화
'http://localhost:8080/api/v1/posts/elastic?keyword=날씨' 로 요청을 보냈을 때, 다음과 같은 오류가 발생했다.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "_class" (class com....post.domain.document.PostDocument), not marked as ignorable (6 known properties: "imageUrl", "title", "content", "id", "tags", "createdAt"])
🔍문제점2-해결
JSON 응답을 PostDocument로 역직렬화하는 과정에서 _class라는 인식되지 않은 필드가 존재하여 발생한 문제이다. Spring Data Elasticsearch는 기본적으로 엔터티 클래스의 _class 필드를 추가하여 인덱싱한다.
PostDocument
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Document(indexName = "posts", createIndex = false, writeTypeHint = WriteTypeHint.FALSE)
@Setting(settingPath = "elastic/post-setting.json")
@Mapping(mappingPath = "elastic/post-mapping.json")
public class PostDocument {
@Id
private Long id;
private String title;
private String content;
private LocalDateTime createdAt;
private String imageUrl;
private List<String> tags;
@Builder
public PostDocument(
Long id,
String title,
String content,
LocalDateTime createdAt,
String imageUrl,
List<String> tags) {
this.id = id;
this.title = title;
this.content = content;
this.createdAt = createdAt;
this.imageUrl = imageUrl;
this.tags = tags;
}
}
@Document 속성
- indexName: ElasticSearch 인덱스 이름 지정
- createIndex: 애플리케이션 시작 시 인덱스를 자동으로 생성할지 여부 지정
- writeTypeHint: 도큐먼트에 타입 힌트를 쓸지 여부 지정
- 도큐먼트에 _class 필드를 추가하지 않도록 한다.
💻문제점3: LocalDateTime 필드 매핑
'http://localhost:8080/api/v1/posts/elastic?keyword=날씨' 로 요청을 보냈을 때, 다음과 같은 오류가 발생했다
Type LocalDateTime of property PostDocument.createdAt is a TemporalAccessor class but has neither a @Field annotation defining the date type nor a registered converter for reading! It cannot be mapped from a complex object in Elasticsearch!
🔍문제점3-해결
LocalDateTime 필드를 Elasticsearch와 올바르게 매핑하기 위해 PostDocument의 createdAt 필드에 @Field 애노테이션을 추가했다.
@Field(type = FieldType.Date, format = {}, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS||epoch_millis")
private LocalDateTime createdAt;
기존 인덱스도 삭제하고 재생성해주었다.
DELETE /posts
post를 저장하고, 다음과 같이 kibana를 통해 확인할 수 있었다.
'http://localhost:8080/api/v1/posts/elastic?keyword=날씨' 로 요청을 보냈을 때 정상적으로 응답이 왔다.
Elasticsearch와 Spring Boot를 연동하여 데이터를 저장하고 검색하는 과정에서 다양한 문제가 발생했다.
요청 하나 보내기 정말 어렵다 😂
'TIL' 카테고리의 다른 글
[TIL-20240813-17] Elasticsearch 자동 완성 (2) (0) | 2024.08.13 |
---|---|
[TIL - 20240810~12] ElasticSearch 자동 완성 (1) (0) | 2024.08.12 |
[TIL - 20240612] Swagger HTTPS 설정 (0) | 2024.06.12 |
[TIL - 20240612] Swagger Failed to load remote configuration 해결 (0) | 2024.06.12 |
[TIL-231219] 사용자 정의 애노테이션을 사용한 List 요소 검증 (0) | 2024.03.20 |