@@ -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 (
0 commit comments