fix: 추천 검색어 동적 임계값 필터링 복원
- SQL GREATEST()로 동적 임계값 적용 - MAX(count) * 1% 또는 최소 10회 중 더 큰 값 사용 - Prefix, 초성, 인기 검색어 모두 필터링 적용 - 데이터가 적을 때도 오타 필터링 가능 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
108265b1fd
commit
72db9dcdc1
1 changed files with 19 additions and 13 deletions
|
|
@ -15,8 +15,8 @@ const inko = new Inko();
|
|||
const CONFIG = {
|
||||
// 추천 검색어 최소 검색 횟수 비율 (최대 대비)
|
||||
MIN_COUNT_RATIO: 0.01,
|
||||
// 최소 임계값 (데이터 적을 때)
|
||||
MIN_COUNT_FLOOR: 5,
|
||||
// 최소 임계값 (데이터 적을 때 오타 방지)
|
||||
MIN_COUNT_FLOOR: 10,
|
||||
// Redis 키 prefix
|
||||
REDIS_PREFIX: 'suggest:',
|
||||
// 캐시 TTL (초)
|
||||
|
|
@ -24,7 +24,6 @@ const CONFIG = {
|
|||
PREFIX: 3600, // prefix 검색: 1시간
|
||||
BIGRAM: 86400, // bi-gram: 24시간
|
||||
POPULAR: 600, // 인기 검색어: 10분
|
||||
MAX_COUNT: 3600, // 최대 횟수: 1시간
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -208,6 +207,7 @@ export class SuggestionService {
|
|||
|
||||
/**
|
||||
* Prefix 매칭
|
||||
* - GREATEST()로 동적 임계값 적용: MAX(count) * 1% 또는 최소 10 중 더 큰 값
|
||||
*/
|
||||
async getPrefixSuggestions(prefix, koreanPrefix, limit) {
|
||||
try {
|
||||
|
|
@ -216,19 +216,21 @@ export class SuggestionService {
|
|||
if (koreanPrefix) {
|
||||
// 영어 + 한글 변환 둘 다 검색
|
||||
[rows] = await this.db.query(
|
||||
`SELECT query, count FROM suggestion_queries
|
||||
WHERE query LIKE ? OR query LIKE ?
|
||||
`SELECT query FROM suggestion_queries
|
||||
WHERE (query LIKE ? OR query LIKE ?)
|
||||
AND count >= GREATEST((SELECT MAX(count) * ? FROM suggestion_queries), ?)
|
||||
ORDER BY count DESC, last_searched_at DESC
|
||||
LIMIT ?`,
|
||||
[`${prefix}%`, `${koreanPrefix}%`, limit]
|
||||
[`${prefix}%`, `${koreanPrefix}%`, CONFIG.MIN_COUNT_RATIO, CONFIG.MIN_COUNT_FLOOR, limit]
|
||||
);
|
||||
} else {
|
||||
[rows] = await this.db.query(
|
||||
`SELECT query, count FROM suggestion_queries
|
||||
`SELECT query FROM suggestion_queries
|
||||
WHERE query LIKE ?
|
||||
AND count >= GREATEST((SELECT MAX(count) * ? FROM suggestion_queries), ?)
|
||||
ORDER BY count DESC, last_searched_at DESC
|
||||
LIMIT ?`,
|
||||
[`${prefix}%`, limit]
|
||||
[`${prefix}%`, CONFIG.MIN_COUNT_RATIO, CONFIG.MIN_COUNT_FLOOR, limit]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -241,15 +243,17 @@ export class SuggestionService {
|
|||
|
||||
/**
|
||||
* 초성 검색
|
||||
* - GREATEST()로 동적 임계값 적용
|
||||
*/
|
||||
async getChosungSuggestions(chosung, limit) {
|
||||
try {
|
||||
const [rows] = await this.db.query(
|
||||
`SELECT word, count FROM suggestion_chosung
|
||||
`SELECT word FROM suggestion_chosung
|
||||
WHERE chosung LIKE ?
|
||||
AND count >= GREATEST((SELECT MAX(count) * ? FROM suggestion_chosung), ?)
|
||||
ORDER BY count DESC
|
||||
LIMIT ?`,
|
||||
[`${chosung}%`, limit]
|
||||
[`${chosung}%`, CONFIG.MIN_COUNT_RATIO, CONFIG.MIN_COUNT_FLOOR, limit]
|
||||
);
|
||||
|
||||
return rows.map(r => r.word);
|
||||
|
|
@ -261,6 +265,7 @@ export class SuggestionService {
|
|||
|
||||
/**
|
||||
* 인기 검색어 조회
|
||||
* - GREATEST()로 동적 임계값 적용
|
||||
*/
|
||||
async getPopularQueries(limit = 10) {
|
||||
try {
|
||||
|
|
@ -272,12 +277,13 @@ export class SuggestionService {
|
|||
return JSON.parse(cached);
|
||||
}
|
||||
|
||||
// DB 조회
|
||||
// DB 조회 (동적 임계값 이상만)
|
||||
const [rows] = await this.db.query(
|
||||
`SELECT query, count FROM suggestion_queries
|
||||
`SELECT query FROM suggestion_queries
|
||||
WHERE count >= GREATEST((SELECT MAX(count) * ? FROM suggestion_queries), ?)
|
||||
ORDER BY count DESC
|
||||
LIMIT ?`,
|
||||
[limit]
|
||||
[CONFIG.MIN_COUNT_RATIO, CONFIG.MIN_COUNT_FLOOR, limit]
|
||||
);
|
||||
|
||||
const result = rows.map(r => r.query);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue