Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,17 @@ public class KakaoNewsService {
private final ElasticsearchClient client;

/**
* ์‚ฌ์šฉ์ž์˜ ํ‚ค์›Œ๋“œ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฌถ์–ด ๋‰ด์Šค ๊ฒ€์ƒ‰ ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
* Hot Fixed
*
*
* @param includeKeywords ํฌํ•จ ํ‚ค์›Œ๋“œ
* @param blockKeywords ์ œ์™ธ ํ‚ค์›Œ๋“œ
* @return
* @return ๋‰ด์Šค ๋ฆฌ์ŠคํŠธ
*/
public List<NewsEsDocument> searchNews(List<String> includeKeywords, List<String> blockKeywords) {
try {

//์ „๋‚  ๊ธฐ์ค€์œผ๋กœ ์‹œ๊ฐ„์„ ์ธก์ •
LocalDate yesterday = LocalDate.now().minusDays(1);

// ํฌํ•จ ํ‚ค์›Œ๋“œ ์ฟผ๋ฆฌ
Query includeKeywordQuery = Query.of(q -> q
.bool(b -> b
.should(includeKeywords.stream()
Expand All @@ -54,23 +53,6 @@ public List<NewsEsDocument> searchNews(List<String> includeKeywords, List<String
)
);

// ์ œ์™ธ ํ‚ค์›Œ๋“œ ์ฟผ๋ฆฌ
Query excludeKeywordQuery = Query.of(q -> q
.bool(b -> b
.should(blockKeywords.stream()
.map(kw -> Query.of(q2 -> q2
.multiMatch(m -> m
.query(kw)
.fields("title", "summary", "content_url", "publisher")
.type(TextQueryType.BoolPrefix)
)
))
.collect(Collectors.toList())
)
)
);

// ๋‚ ์งœ ํ•„ํ„ฐ ์ฟผ๋ฆฌ
Query dateFilter = Query.of(q -> q
.range(r -> r
.field("published_at")
Expand All @@ -80,16 +62,43 @@ public List<NewsEsDocument> searchNews(List<String> includeKeywords, List<String
)
);

// ์ „์ฒด ์ฟผ๋ฆฌ ์กฐํ•ฉ
Query finalQuery = Query.of(q -> q
.bool(b -> b
.must(includeKeywordQuery)
.must(dateFilter)
.mustNot(excludeKeywordQuery)
)
);
// ์ฟผ๋ฆฌ ๋ฆฌ์ŠคํŠธ ์กฐํ•ฉ
List<Query> mustQueries = new ArrayList<>();
mustQueries.add(includeKeywordQuery);
mustQueries.add(dateFilter);

// ์ œ์™ธ ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ must_not ์ถ”๊ฐ€
Query finalQuery;
if (blockKeywords != null && !blockKeywords.isEmpty()) {
Query excludeKeywordQuery = Query.of(q -> q
.bool(b -> b
.should(blockKeywords.stream()
.map(kw -> Query.of(q2 -> q2
.multiMatch(m -> m
.query(kw)
.fields("title", "summary", "content_url", "publisher")
.type(TextQueryType.BoolPrefix)
)
))
.collect(Collectors.toList())
)
)
);

finalQuery = Query.of(q -> q
.bool(b -> b
.must(mustQueries)
.mustNot(excludeKeywordQuery)
)
);
} else {
finalQuery = Query.of(q -> q
.bool(b -> b
.must(mustQueries)
)
);
}

// ๊ฒ€์ƒ‰ ์š”์ฒญ
SearchRequest request = SearchRequest.of(s -> s
.index("news-index-nori")
.query(finalQuery)
Expand All @@ -99,15 +108,12 @@ public List<NewsEsDocument> searchNews(List<String> includeKeywords, List<String
)
);

// ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰
SearchResponse<NewsEsDocument> response = client.search(request, NewsEsDocument.class);

// ๋กœ๊ทธ: ์Šค์ฝ”์–ด ํ™•์ธ
response.hits().hits().forEach(hit ->
log.info("{} | score: {}", hit.source().getTitle(), hit.score())
);

// ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
return response.hits().hits().stream()
.map(hit -> hit.source())
.collect(Collectors.toList());
Expand All @@ -117,4 +123,100 @@ public List<NewsEsDocument> searchNews(List<String> includeKeywords, List<String
return List.of();
}
}

// ======================= Deprecated =========================

// /**
// * ์‚ฌ์šฉ์ž์˜ ํ‚ค์›Œ๋“œ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฌถ์–ด ๋‰ด์Šค ๊ฒ€์ƒ‰ ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ
// *
// * @param includeKeywords ํฌํ•จ ํ‚ค์›Œ๋“œ
// * @param blockKeywords ์ œ์™ธ ํ‚ค์›Œ๋“œ
// * @return
// */
// public List<NewsEsDocument> searchNews(List<String> includeKeywords, List<String> blockKeywords) {
// try {
//
// /* ์ „๋‚  ๊ธฐ์ค€์œผ๋กœ ์‹œ๊ฐ„์„ ์ธก์ • */
// LocalDate yesterday = LocalDate.now().minusDays(1);
//
// /* ํฌํ•จ ํ‚ค์›Œ๋“œ ์ฟผ๋ฆฌ */
// Query includeKeywordQuery = Query.of(q -> q
// .bool(b -> b
// .should(includeKeywords.stream()
// .map(kw -> Query.of(q2 -> q2
// .multiMatch(m -> m
// .query(kw)
// .fields("title", "summary", "content_url", "publisher")
// .type(TextQueryType.BoolPrefix)
// )
// ))
// .collect(Collectors.toList())
// )
// .minimumShouldMatch("1")
// )
// );
//
// /* ์ œ์™ธ ํ‚ค์›Œ๋“œ ์ฟผ๋ฆฌ */
// Query excludeKeywordQuery = Query.of(q -> q
// .bool(b -> b
// .should(blockKeywords.stream()
// .map(kw -> Query.of(q2 -> q2
// .multiMatch(m -> m
// .query(kw)
// .fields("title", "summary", "content_url", "publisher")
// .type(TextQueryType.BoolPrefix)
// )
// ))
// .collect(Collectors.toList())
// )
// )
// );
//
// /* ๋‚ ์งœ ํ•„ํ„ฐ ์ฟผ๋ฆฌ */
// Query dateFilter = Query.of(q -> q
// .range(r -> r
// .field("published_at")
// .gte(JsonData.of(yesterday.toString()))
// .lte(JsonData.of(yesterday.toString()))
// .format("yyyy-MM-dd")
// )
// );
//
// /* ์ „์ฒด ์ฟผ๋ฆฌ ์กฐํ•ฉ */
// Query finalQuery = Query.of(q -> q
// .bool(b -> b
// .must(includeKeywordQuery)
// .must(dateFilter)
// .mustNot(excludeKeywordQuery)
// )
// );
//
// /* ๊ฒ€์ƒ‰ ์š”์ฒญ */
// SearchRequest request = SearchRequest.of(s -> s
// .index("news-index-nori")
// .query(finalQuery)
// .size(5)
// .sort(sort -> sort
// .score(sc -> sc.order(co.elastic.clients.elasticsearch._types.SortOrder.Desc))
// )
// );
//
// /* ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ */
// SearchResponse<NewsEsDocument> response = client.search(request, NewsEsDocument.class);
//
// /* ๋กœ๊ทธ: ์Šค์ฝ”์–ด ํ™•์ธ */
// response.hits().hits().forEach(hit ->
// log.info("{} | score: {}", hit.source().getTitle(), hit.score())
// );
//
// /* ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ */
// return response.hits().hits().stream()
// .map(hit -> hit.source())
// .collect(Collectors.toList());
//
// } catch (IOException e) {
// log.error("ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ๋‰ด์Šค ๊ฒ€์ƒ‰ ์‹คํŒจ: {}", e.getMessage(), e);
// return List.of();
// }
// }
}