상품 추천에서 유사한 제목 필터링을 위한 텍스트 전처리 및 자카드 유사도 적용기

송현진·2025년 5월 29일
0

프로젝트 회고

목록 보기
4/17

선물 추천 서비스를 운영하면서 사용자에게 제공되는 상품 리스트를 유심히 살펴보던 중 너무 유사한 상품들이 연속적으로 추천되는 현상을 발견했다. 겉보기에 상품 제목은 조금씩 다르지만 실제로는 같은 브랜드의 동일 라인업이거나 용량/옵션만 다른 거의 동일한 상품들이었고 이로 인해 추천 결과가 단조롭고 반복적이라는 인상을 주고 있었다. 이 문제는 사용자 경험에 큰 영향을 미치는 요소였다. 사용자 입장에서는 “추천이 다양하지 않다”, “뭘 봐도 비슷한 것만 나온다”는 불만족으로 이어질 수 있기 때문에 중복되거나 유사한 상품을 자동으로 걸러내는 로직이 꼭 필요하다고 판단했다. 단순히 브랜드나 카테고리 기준으로 중복을 제거하는 방법도 고려했지만 이 방식은 너무 단편적이었다. 같은 브랜드라도 전혀 다른 상품일 수 있고 다른 브랜드더라도 본질적으로 동일한 상품일 수도 있기 때문이다. 결국 핵심은 “제목 자체를 어떻게 비교할 것인가”였고 여기서 두 가지 기능을 도입하게 되었다

  1. 상품 제목을 정규화(정제)하는 extractBaseTitle
  2. 두 제목 간 단어 기반 자카드 유사도를 계산하는 jaccardSimilarityByWords

1. 상품 제목 정제 함수

상품 제목은 판매처마다 다르게 포맷팅되며 다양한 노이즈 요소를 포함한다. 예를 들어 [정품], (화이트), 200ml, -, 등은 상품의 본질과 상관없는 정보지만 제목을 분리하거나 비교하는 데 방해가 된다. 따라서 다음과 같은 과정을 거쳐 제목을 최대한 본질적인 키워드만 남기는 방식으로 전처리했다.

public static String extractBaseTitle(String title) {
    return title
            .replaceAll("\\[[^\\]]*\\]", "") // [정품], [BTS 에디션] 등 대괄호 제거
            .replaceAll("\\([^)]*\\)", "") // (화이트), (옵션 선택) 등 소괄호 제거
            .replaceAll("[-_•·|]", " ") // 특수 구분자 -> 공백
            .replaceAll("\\d+(호|mm|ml|g|kg|cm|개|세트|pack|팩)?", "") // 단위 포함 숫자 제거
            .replaceAll("[^가-힣a-zA-Z0-9 ]", "") // 나머지 특수문자 제거
            .replaceAll("\\s{2,}", " ") // 다중 공백 정리
            .trim()
            .toLowerCase(); // 소문자 통일
}

예시 전후 비교

  • 입력: [정품] 록시땅 핸드크림 (화이트) 30ml - 프랑스 정품 • 감성

  • 출력: 록시땅 핸드크림 프랑스 정품 감성

2. 자카드 유사도 기반 제목 비교

정규화된 제목들끼리 유사도를 판단하기 위해 자카드 유사도(Jaccard Similarity)를 활용했다. 이는 두 문자열을 단어 단위로 나눈 후 교집합과 합집합의 비율을 통해 유사도를 계산하는 방식이다.

public static double jaccardSimilarityByWords(String title1, String title2) {
    Set<String> words1 = new HashSet<>(List.of(title1.split("\\s+")));
    Set<String> words2 = new HashSet<>(List.of(title2.split("\\s+")));

    Set<String> intersection = new HashSet<>(words1);
    intersection.retainAll(words2);

    Set<String> union = new HashSet<>(words1);
    union.addAll(words2);

    return union.isEmpty() ? 0.0 : (double) intersection.size() / union.size();
}

예시 비교

  • 제목1: 록시땅 핸드크림 프랑스 정품 감성
  • 제목2: 프랑스 정품 감성 록시땅 크림
  • 유사도: 4/5 = 0.8

자카드 유사도가 0.8 이상이면 사실상 거의 동일한 상품이므로 하나만 추천 리스트에 포함하도록 했다.

📝 배운점

이번 개선 작업을 통해 추천 리스트에 포함되는 상품들의 다양성을 높이고 사용자 경험을 해치는 유사 상품 중복 노출 문제를 줄일 수 있었다. 특히 상품 제목을 정규화하여 본질적인 키워드만 남기고 자카드 유사도를 기준으로 중복 여부를 판단함으로써 같은 브랜드의 유사 상품이 연속 추천되는 문제를 상당 부분 개선할 수 있었다. 유사도가 0.8 이상인 상품은 하나만 추천되도록 필터링하면서 결과적으로 추천 품질이 더 좋아졌다는 피드백도 확인할 수 있었다.

다만 모든 키워드 조합을 수동으로 테스트하기 어려운 만큼 일부 상황에서는 여전히 유사 상품이 걸러지지 않을 가능성도 존재한다. 이 부분은 향후 더 정교한 필터링 조건 등을 고민해보며 계속 개선해나가야 될 거 같다.

profile
개발자가 되고 싶은 취준생

0개의 댓글