Skip to content

Commit e73c59d

Browse files
committed
fix: 뉴스 검색 로직 변경
1 parent 3596e24 commit e73c59d

4 files changed

Lines changed: 61 additions & 81 deletions

File tree

src/main/java/com/example/ImFact/news/service/NewsSearchService.java

Lines changed: 54 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -53,93 +53,64 @@ public class NewsSearchService {
5353
public NewsListDto searchNews(Long userId, int page, int size, String category,
5454
Double reliabilityScore, String query, String press) {
5555
try {
56-
Map<String, Object> searchBody = new HashMap<>();
56+
log.info("뉴스 검색 시작: page={}, size={}, category={}, query={}", page, size, category, query);
5757

58-
// 조건 체크
59-
boolean hasQuery = StringUtils.hasText(query);
60-
boolean hasFilters = StringUtils.hasText(category) ||
61-
StringUtils.hasText(press) ||
62-
reliabilityScore != null;
63-
64-
// Query 부분
65-
Map<String, Object> querySection = new HashMap<>();
66-
67-
if (hasQuery || hasFilters) {
68-
// bool 쿼리 사용
69-
Map<String, Object> boolQuery = new HashMap<>();
70-
71-
// 검색어가 있으면 must에 추가
72-
if (hasQuery) {
73-
List<Map<String, Object>> mustList = new ArrayList<>();
74-
Map<String, Object> multiMatch = new HashMap<>();
75-
multiMatch.put("query", query);
76-
multiMatch.put("fields", List.of("title^2.0", "body^1.0"));
77-
mustList.add(Map.of("multi_match", multiMatch));
78-
boolQuery.put("must", mustList);
79-
}
80-
81-
// 필터가 있으면 filter에 추가
82-
if (hasFilters) {
83-
List<Map<String, Object>> filterList = new ArrayList<>();
84-
85-
if (StringUtils.hasText(category)) {
86-
filterList.add(Map.of("term", Map.of("category.keyword", category)));
87-
}
88-
if (StringUtils.hasText(press)) {
89-
filterList.add(Map.of("term", Map.of("press.keyword", press)));
90-
}
91-
if (reliabilityScore != null) {
92-
filterList.add(Map.of("range",
93-
Map.of("reliability_score", Map.of("gte", reliabilityScore))));
94-
}
95-
96-
boolQuery.put("filter", filterList);
97-
}
98-
99-
querySection.put("bool", boolQuery);
100-
} else {
101-
// 조건 없으면 match_all
102-
querySection.put("match_all", new HashMap<>());
58+
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
59+
60+
// 검색어가 있으면 must 추가
61+
if (StringUtils.hasText(query)) {
62+
boolQuery.must(QueryBuilders.multiMatchQuery(query)
63+
.field("title", 2.0f)
64+
.field("body", 1.0f));
10365
}
10466

105-
searchBody.put("query", querySection);
106-
searchBody.put("from", page * size);
107-
searchBody.put("size", size);
67+
// 필터 추가
68+
if (StringUtils.hasText(category)) {
69+
boolQuery.filter(QueryBuilders.termQuery("category.keyword", category));
70+
}
71+
if (StringUtils.hasText(press)) {
72+
boolQuery.filter(QueryBuilders.termQuery("press.keyword", press));
73+
}
74+
if (reliabilityScore != null) {
75+
boolQuery.filter(QueryBuilders.rangeQuery("reliability_score")
76+
.gte(reliabilityScore));
77+
}
10878

109-
// JSON 변환
110-
ObjectMapper objectMapper = new ObjectMapper();
111-
String requestBody = objectMapper.writeValueAsString(searchBody);
79+
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
11280

113-
log.info("========== OpenSearch Request ==========");
114-
log.info("Body: {}", requestBody);
115-
log.info("======================================");
81+
// 쿼리 설정
82+
if (StringUtils.hasText(query) || StringUtils.hasText(category)
83+
|| StringUtils.hasText(press) || reliabilityScore != null) {
84+
sourceBuilder.query(boolQuery);
85+
} else {
86+
sourceBuilder.query(QueryBuilders.matchAllQuery());
87+
}
11688

117-
// RestClient로 직접 요청
118-
Request request = new Request("POST", "/news/_search");
119-
request.setJsonEntity(requestBody);
89+
sourceBuilder.from(page * size);
90+
sourceBuilder.size(size);
12091

121-
Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
92+
// ✅ 정렬: reg_datetime + _id
93+
sourceBuilder.sort("reg_datetime", SortOrder.DESC);
94+
sourceBuilder.sort("_id", SortOrder.DESC);
12295

123-
// 응답 파싱
124-
String responseBody = EntityUtils.toString(response.getEntity());
125-
JsonNode jsonResponse = objectMapper.readTree(responseBody);
96+
SearchRequest searchRequest = new SearchRequest("news");
97+
searchRequest.source(sourceBuilder);
12698

127-
// hits 추출
128-
JsonNode hits = jsonResponse.get("hits").get("hits");
99+
log.info("========== OpenSearch Query ==========");
100+
log.info("Query: {}", sourceBuilder.toString());
101+
log.info("======================================");
102+
103+
SearchResponse response = restHighLevelClient.search(
104+
searchRequest, RequestOptions.DEFAULT);
129105

130106
List<NewsDocument> documents = new ArrayList<>();
131-
for (JsonNode hit : hits) {
132-
Map<String, Object> sourceMap = objectMapper.convertValue(
133-
hit.get("_source"),
134-
new TypeReference<Map<String, Object>>() {}
135-
);
136-
documents.add(convertMapToNewsDocument(sourceMap));
107+
for (SearchHit hit : response.getHits().getHits()) {
108+
documents.add(convertMapToNewsDocument(hit.getSourceAsMap()));
137109
}
138110

139111
List<NewsArticleDto> articles = convertToDto(documents, userId);
140112

141-
// 전체 개수
142-
long totalHits = jsonResponse.get("hits").get("total").get("value").asLong();
113+
long totalHits = response.getHits().getTotalHits().value;
143114

144115
PageInfoDto pageInfo = PageInfoDto.builder()
145116
.pageNumber(page)
@@ -148,7 +119,15 @@ public NewsListDto searchNews(Long userId, int page, int size, String category,
148119
.totalElements(totalHits)
149120
.build();
150121

151-
log.info("검색 완료: 결과 수={}", articles.size());
122+
if (!articles.isEmpty()) {
123+
log.info("검색 완료: 결과 수={}, 첫 번째={}, 마지막={}",
124+
articles.size(),
125+
articles.get(0).getPublishedAt(),
126+
articles.get(articles.size() - 1).getPublishedAt()
127+
);
128+
} else {
129+
log.info("검색 완료: 결과 수=0");
130+
}
152131

153132
return new NewsListDto(articles, pageInfo);
154133

@@ -190,7 +169,8 @@ public NewsListDto getSubscribedNews(Long userId, int page, int size) {
190169
sourceBuilder.query(boolQuery);
191170
sourceBuilder.from(page * size);
192171
sourceBuilder.size(size);
193-
sourceBuilder.sort("reg_datetime", SortOrder.DESC); // ⭐ 정렬 추가
172+
sourceBuilder.sort("reg_datetime", SortOrder.DESC);
173+
sourceBuilder.sort("_id", SortOrder.DESC);// ⭐ 정렬 추가
194174
searchRequest.source(sourceBuilder);
195175

196176
SearchResponse response = restHighLevelClient.search(

src/main/java/com/example/ImFact/user/entity/UserEntity.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ public class UserEntity {
4141
@Column(name = "status", nullable = false)
4242
private UserStatus status = UserStatus.TEMP;
4343

44-
@Column(name = "refresh_token", length = 512)
45-
private String refreshToken;
46-
4744
@Column(name = "fcm_token", length = 500)
4845
private String fcmToken;
4946

@@ -92,10 +89,6 @@ public void updateUserImageUrl(String userImageUrl) {
9289
this.userImageUrl = userImageUrl;
9390
}
9491

95-
public void updateRefreshToken(String refreshToken) {
96-
this.refreshToken = refreshToken;
97-
}
98-
9992
public void updateFcmToken(String fcmToken) {
10093
this.fcmToken = fcmToken;
10194
}

src/main/resources/application.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ spring.datasource.password=factim~123
77
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
88
spring.jpa.hibernate.ddl-auto=update
99
spring.jpa.show-sql=true
10+
spring.jpa.properties.hibernate.default_batch_fetch_size=100
1011

1112
# AWS 스택 자동 설정 비활성화
1213
spring.cloud.aws.stack.auto=false

src/main/web/WEB-INF/web.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
5+
version="4.0">
6+
</web-app>

0 commit comments

Comments
 (0)