1+ package com .snowykte0426 .minsole .domain .data .service ;
2+
3+ import com .opencsv .CSVReader ;
4+ import com .snowykte0426 .minsole .domain .data .entity .DataJpaEntity ;
5+ import com .snowykte0426 .minsole .domain .data .repository .DataJpaRepository ;
6+ import jakarta .annotation .PostConstruct ;
7+ import lombok .RequiredArgsConstructor ;
8+ import lombok .extern .slf4j .Slf4j ;
9+ import org .apache .commons .text .similarity .JaroWinklerDistance ;
10+ import org .springframework .stereotype .Service ;
11+
12+ import java .io .BufferedReader ;
13+ import java .io .FileInputStream ;
14+ import java .io .FileReader ;
15+ import java .io .InputStreamReader ;
16+ import java .nio .charset .Charset ;
17+ import java .util .HashMap ;
18+ import java .util .List ;
19+ import java .util .Map ;
20+
21+ @ Service
22+ @ RequiredArgsConstructor
23+ @ Slf4j
24+ public class CsvRatingUpdater {
25+
26+ private final DataJpaRepository dataJpaRepository ;
27+
28+ @ PostConstruct
29+ public void updateRatingsFromCsv () {
30+ String csvPath = "/Users/snowykte0426/Programming/BigData-Server/서울관광재단_식당품질정보_20230111.csv" ; // CSV 파일 경로
31+
32+ Map <String , Double > csvRatings = loadCsvData (csvPath );
33+ List <DataJpaEntity > dbEntities = dataJpaRepository .findAll ();
34+
35+ JaroWinklerDistance jw = new JaroWinklerDistance ();
36+ final double THRESHOLD = 0.90 ; // 유사도 임계값
37+
38+ for (DataJpaEntity entity : dbEntities ) {
39+ String bizName = entity .getBizName ();
40+ if (bizName == null ) continue ;
41+
42+ double bestScore = 0.0 ;
43+ String bestMatch = null ;
44+ for (String csvName : csvRatings .keySet ()) {
45+ double score = jw .apply (bizName , csvName );
46+ if (score > bestScore ) {
47+ bestScore = score ;
48+ bestMatch = csvName ;
49+ }
50+ }
51+
52+ if (bestScore >= THRESHOLD && bestMatch != null ) {
53+ Double rating = csvRatings .get (bestMatch );
54+ entity = DataJpaEntity .builder ().
55+ id (entity .getId ()).
56+ serviceId (entity .getServiceId ()).
57+ orgCode (entity .getOrgCode ()).
58+ manageCode (entity .getManageCode ()).
59+ bizName (bizName ).
60+ permitNo (entity .getPermitNo ()).
61+ roadAddr (entity .getRoadAddr ()).
62+ jibunAddr (entity .getJibunAddr ()).
63+ applyDate (entity .getApplyDate ()).
64+ designateDate (entity .getDesignateDate ()).
65+ foodType (entity .getFoodType ()).
66+ naverRating (rating ).
67+ build ();
68+ log .info ("Updated {} with rating {}" , bizName , rating );
69+ }
70+ }
71+
72+ dataJpaRepository .saveAll (dbEntities ); // 모든 변경 저장
73+ log .info ("네이버 평점 업데이트 완료" );
74+ }
75+
76+ private Map <String , Double > loadCsvData (String csvFilePath ) {
77+ Map <String , Double > dataMap = new HashMap <>();
78+ try (CSVReader reader = new CSVReader (new InputStreamReader (new FileInputStream (csvFilePath ), Charset .forName ("EUC-KR" )))) {
79+ List <String []> allLines = reader .readAll ();
80+ String [] header = allLines .getFirst (); // 헤더 줄
81+
82+ // "식당명"과 "네이버평점" 컬럼의 인덱스 찾기
83+ int nameIndex = -1 ;
84+ int ratingIndex = -1 ;
85+ for (int i = 0 ; i < header .length ; i ++) {
86+ if (header [i ].equals ("식당명" )) nameIndex = i ;
87+ if (header [i ].equals ("네이버평점" )) ratingIndex = i ;
88+ }
89+ if (nameIndex == -1 || ratingIndex == -1 ) {
90+ throw new RuntimeException ("CSV 파일에 '식당명' 또는 '네이버평점' 컬럼이 없습니다." );
91+ }
92+
93+ // 데이터 읽기
94+ for (int i = 1 ; i < allLines .size (); i ++) {
95+ String [] line = allLines .get (i );
96+ if (line .length <= Math .max (nameIndex , ratingIndex )) continue ;
97+
98+ String name = line [nameIndex ];
99+ String rating = line [ratingIndex ];
100+ if (name != null && rating != null ) {
101+ dataMap .put (name .trim (), Double .valueOf (rating .trim ()));
102+ }
103+ }
104+ } catch (Exception e ) {
105+ log .error ("CSV 읽기 실패" , e );
106+ }
107+ return dataMap ;
108+ }
109+ }
0 commit comments