์๊ตฌ์ฌํญ
ํฅ์ ๋ฆฌ๋ทฐ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉฐ, ํฅ์ ๋ฆฌ๋ทฐ ๋ฐ์ดํฐ ๊ธฐ๋ฐ์ผ๋ก ํต๊ณ๋ฅผ percentage๋ก ๋ด์ด ๋ฐํํ๋ ์๊ตฌ์ฌํญ์ด ์์๋ค. ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ํน์ ํฅ์์ ๋ํด ์ฌ๋๋ค์ด ๋ฆฌ๋ทฐํ ๋ฌด๊ฒ๊ฐ ์ ๋, ์ง์๋ ฅ, ๊ณ์ , ํ์ฐ๋ ฅ ์ ๋, ์ฌ์ฉ์์ ์ฑ๋ณ์ ๊ธฐ๋ฐ์ผ๋ก ์ค๊ฐํ์ ๋ํ๋ด์ด์ผ ํ๋ค. ์ด๋ฅผ ์ํด ํน์ ํฅ์์ ๋ํ ๋ฆฌ๋ทฐ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด ๊ฐ๊ฐ์ ๋ฆฌ๋ทฐ ์์๋ง๋ค ๋น์จ์ ๊ณ์ฐํด ์กฐํํ๊ณ ์ ํ๋ค. ๋น์ฐํ ๋ง์ด์ง๋ง ๊ฐ๊ฐ์ Percentage๋ฅผ ๋ชจ๋ ํฉํ๋ฉด 100์ด ๋์ด์ผ ํ๋ค.
ํ๋ก์ ํธ์ ๋ฆฌ๋ทฐ ํ ์ด๋ธ๊ณผ ์ ์ ํ ์ด๋ธ ๊ตฌ์กฐ๋ฅผ ๊ฐ๋จํ๊ฒ ์ดํด๋ณด๋ฉด ์๋์ ๊ฐ๋ค. (์ผ๋ถ ํ์์๋ ๋ฐ์ดํฐ๋ ์๋ตํ๋ค.)
ํด๋ผ์ด์ธํธ์๊ฒ๋ ๋ฆฌ๋ทฐ ๋ฐ์ดํฐ์ ๋ฆฌ๋ทฐ๋ฅผ ์์ฑํ ์ฌ์ฉ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด ์๋์ ๊ฐ์ด ๋ฆฌ๋ทฐ ์์๋ง๋ค percentage๋ฅผ ๊ณ์ฐํ์ฌ ๋ฐํํด ์ค ๊ฒ์ด๋ค.
{
"strength": {
"LIGHT": 24,
"HEAVY": 36,
"MODERATE":40
},
"duration": {
"MEDIUM": 0,
"LONG": 0,
"TOO_SHORT": 98,
"SHORT": 2
},
"season": {
"FALL": 0,
"WINTER": 1,
"SPRING": 99,
"SUMMER": 0
},
"dayType": {
"TRAVEL": 30,
"SPECIAL": 13,
"REST": 22,
"DAILY": 35
},
"sex": {
"FEMALE": 5,
"OTHER": 70,
"MALE": 25
}
}
ํด๊ฒฐํ๊ธฐ
๋จผ์ ๋ฆฌ๋ทฐ ์์ ๊ธฐ์ค์ผ๋ก ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ DB์์ ์กฐํํ ํ ํ๋ก๊ทธ๋จ ๋จ์์ ๋น์จ๋ก ๋ณํํด์ค ๊ฒ์ด๋ค. ๋ณธ ํ๋ก์ ํธ์์๋ ์กฐํ ์์๋ QueryDSL์ ์ ๊ทน ํ์ฉํ๊ณ ์์ผ๋ฏ๋ก ์ฌ๊ธฐ์๋ ๋ง์ฐฌ๊ฐ์ง๋ก QueryDSL์ ์ฌ์ฉํด DB ์ง์๋ฅผ ๋ณด๋ผ ๊ฒ์ด๋ค. ๐พ
๋ฆฌ๋ทฐ ์์ ๊ธฐ์ค์ผ๋ก ๋ฆฌ๋ทฐ ๊ฐ์ ๊ตฌํ๊ธฐ
QueryDSL์ where ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋จผ์ ์ฌ๋ฌ ๋ฆฌ๋ทฐ ์ค ํน์ perfumeId์ ํด๋นํ๋ ๋ฆฌ๋ทฐ์ด๋ฉด์ ์ญ์ ๋์ง ์์ ๋ฆฌ๋ทฐ๋ง ์ ๋ณํ๋ค.
์ฐธ๊ณ ๋ก ๋ณธ ํ๋ก์ ํธ์์๋ soft delete ๋ฐฉ์์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์๊ฐ ๋ฆฌ๋ทฐ๋ฅผ ์ญ์ ํ๋๋ผ๋ ๋ฐ์ดํฐ ์์ฒด๋ฅผ ์ง์ฐ๋ ๊ฒ์ด ์๋ deleted_at์true๋ก ๋งํนํ๋๋ก ํ๊ธฐ ๋๋ฌธ์ deletedAt์ด null์ธ, ์ฆ ์ญ์ ๋์ง ์์ ๋ฆฌ๋ทฐ๋ง ์กฐํํ๋๋ก ํ๋ค.
๊ทธ๋ฆฌ๊ณ ํฅ์ ๋ฌด๊ฒ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ ์กฐํํ๊ธฐ ์ํด groupBy ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๊ทธ๋ฃนํ ํ์๋ค.
์ดํ QueryDSL์์ ์ ๊ณตํ๋ transform ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ํฅ์ ๋ฌด๊ฒ๊ฐ์ key๋ก ํ๊ณ ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ value๋ก ํ๋ Map ์๋ฃ๊ตฌ์กฐ์ ๋ด๋๋ก ํ๋ค.
Map<Strength, Long> strengthMap =
jpaQueryFactory
.from(reviewEntity)
.where(reviewEntity.perfumeId.eq(perfumeId), reviewEntity.deletedAt.isNull())
.groupBy(reviewEntity.strength)
.transform(groupBy(reviewEntity.strength).as(reviewEntity.id.count()));
์์ ๋์ผํ๊ฒ ํฅ์ ์ง์๋ ฅ, ์ด์ธ๋ฆฌ๋ ๊ณ์ , ๋ฆฌ๋ทฐ์ด ์ฑ๋ณ ๋ฑ ๋ค๋ฅธ ๋ฆฌ๋ทฐ ์์๋ฅผ ๊ธฐ์ค์ผ๋ก๋ ๊ฐ๊ฐ ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ ์กฐํํ๋ค.
Map<Duration, Long> durationMap =
jpaQueryFactory
.from(reviewEntity)
.where(reviewEntity.perfumeId.eq(perfumeId), reviewEntity.deletedAt.isNull())
.groupBy(reviewEntity.duration)
.transform(groupBy(reviewEntity.duration).as(reviewEntity.id.count()));
Map<Season, Long> seasonMap =
jpaQueryFactory
.from(reviewEntity)
.where(reviewEntity.perfumeId.eq(perfumeId), reviewEntity.deletedAt.isNull())
.groupBy(reviewEntity.season)
.transform(groupBy(reviewEntity.season).as(reviewEntity.id.count()));
Map<DayType, Long> dayTypeMap =
jpaQueryFactory
.from(reviewEntity)
.where(reviewEntity.perfumeId.eq(perfumeId), reviewEntity.deletedAt.isNull())
.groupBy(reviewEntity.dayType)
.transform(groupBy(reviewEntity.dayType).as(reviewEntity.id.count()));
Map<Sex, Long> sexMap =
jpaQueryFactory
.from(reviewEntity)
.leftJoin(userEntity)
.on(reviewEntity.userId.eq(userEntity.id), userEntity.deletedAt.isNull())
.where(reviewEntity.perfumeId.eq(perfumeId), reviewEntity.deletedAt.isNull())
.groupBy(userEntity.sex)
.transform(groupBy(userEntity.sex).as(reviewEntity.id.count()));
์ด๋ ๊ฒ ์กฐํ๋ ๋ฐ์ดํฐ๋ค์ ๋ชจ์ ReviewFeatureCount๋ผ๋ ํด๋์ค์ ๋ด์ ์ ์๋๋ก ํ์๋ค.
๊ทธ๋ฆฌ๊ณ totalReviews ๊ฐ์๋ฅผ ์ ์ฅํด๋ ์ด์ ๋ Percentage๋ฅผ ๊ตฌํ๊ธฐ ์ํด ํน์ ํฅ์์ ํด๋นํ๋ ๋ชจ๋ ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
public record ReviewFeatureCount(
Map<Strength, Long> strengthMap,
Map<Duration, Long> durationMap,
Map<Season, Long> seasonMap,
Map<DayType, Long> dayTypeMap,
Map<Sex, Long> sexMap,
Long totalReviews) {};
Percentage ํํ๋ก ๋ณํํ๊ธฐ
์ด์ ๋ฆฌ๋ทฐ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ๋ Map์ calculatePercentage ๋ฉ์๋๋ฅผ ํตํด ๋น์จ ๊ธฐ๋ฐ์ผ๋ก ๋ Map์ผ๋ก ๋ณํํ๋๋ก ํ๋ค.
calculatePercentage์ ์ธ์๋ฅผ ์ดํด๋ณด๋ฉด, Enum ํ์ ์ ์ ๋ ฅ๋ฐ์ ์ฌ์ฌ์ฉ๋ ์ ์๋๋ก ํ์์ผ๋ฉฐ, ๋ฆฌ๋ทฐ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ๋ Map๊ณผ ํน์ ํฅ์์ ์ด ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ ์ ๋ ฅ๋ฐ๋๋ก ๋์ด ์๋ค.
Map<Strength, Long> strengthMap = calculatePercentage(
Strength.class, reviewFeatureCount.strengthMap(), totalReviewCount);
์์ธํ ๋ฉ์๋ ๊ตฌํ์ ์๋์ ๊ฐ๋ค.
๋จผ์ ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ ์ ์ฅ๋ Map์ ์๋ก์ด mutableMap์ด๋ผ๋ ๋ณ์์ ์ ์ฅํ๋ค. ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ 0์ธ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๊ฐ๊ฐ์ Enum value๋ฅผ ๋๋ฉด์ Map์ ๋น ๊ฐ์ ์ ์ฅํ๋ค.
์๋ฅผ ๋ค์ด ์ ๋ ฅ๋ฐ์ map์ด {LIGHT: 49, MODERATE: 51} ๊ณผ ๊ฐ์ ํํ ์๋ค๋ฉด, ํด๋ผ์ด์ธํธ์๊ฒ ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ 0์ธ Enum value๋ ํจ๊ป ๋ฐํํ๊ธฐ ์ํด {LIGHT: 49, MODERATE: 51, HEAVY: 0} ๊ณผ ๊ฐ์ ํํ๋ก ๋ง๋ค์ด ์ฃผ๋ ๊ฒ์ด๋ค.
์ด๋ ๊ฒ ์์ฑํ Map์ stream()์ผ๋ก ์ํํ๋ฉด์ (๋ฆฌ๋ทฐ ๊ฐ์) / (์ด ๋ฆฌ๋ทฐ ๊ฐ์) * 100 ์์์ ์ ์ฉํด percentage๋ก ๋ณํํ๋ฉด ๋๋ค.
private <V extends Enum<V>> Map<V, Long> calculatePercentage(
final Class<V> enumClazz, final Map<V, Long> map, final long totalReviews) {
Map<V, Long> mutableMap = new HashMap<>(map);
EnumSet.allOf(enumClazz).forEach(enumValue -> mutableMap.putIfAbsent(enumValue, 0L));
return mutableMap.entrySet().stream()
.collect(
Collectors.toMap(
Map.Entry::getKey, e -> Math.round((double) e.getValue() / totalReviews * 100)));
}
๋ง๋ฌด๋ฆฌ
ํ์ DB ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ผ์ด ์๋ ๋์๊ฒ๋ ๋ณต์กํ DB ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด๋ณผ ์ ์๋ ์ข์ ๊ธฐํ์๋ค. ํ์ง๋ง ์ด๋ ๊ฒ ์์ฒญ ๋ณด๋ผ ๋๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ์กฐํํด ๋น์จ์ ๊ณ์ฐํ๋ ๊ฒ์ ์ฌ์ค์ ์ค๋ฌด์์ ์ฌ์ฉ๋๊ธฐ ์ด๋ ค์ธ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ์ค๋ฌด์์๋ ๋ฐ์ดํฐ๋ฅผ ์บ์ฑํด๋๊ณ ํ๋ฃจ์ ํ ๋ฒ์ฉ ๋ง๋ฃ์์ผ ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ์์ผ์ฃผ๋ ๋ฑ์ ์บ์ฑ ์ ๋ต์ด ์ฌ์ฉ๋ ๊ฒ ๊ฐ๋ค.
'SQL > ๊ฐ๋ฐ ๊ธฐ๋ก' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
CentOS7์์ MySQL 8 ๋ฒ์ ์ค์นํ๊ธฐ (0) | 2023.04.20 |
---|---|
ERROR 2002 (HY000): Can't connect to local server through socket '/tmp/mysql.sock' (2) m1 ๋งฅ์์ ํด๊ฒฐํ๊ธฐ (0) | 2022.08.21 |
๋๊ธ