Skip to content

Commit

Permalink
[폐업 추정] 로깅 & 폐업 일자 필드 추가 (#412)
Browse files Browse the repository at this point in the history
* feat: add more fields and logger

* fix: compile

* refactor: extension method

* feat: add address as well

* fix: build
  • Loading branch information
jyoo0515 authored Nov 2, 2024
1 parent 09514b8 commit 7786225
Show file tree
Hide file tree
Showing 15 changed files with 57 additions and 12 deletions.
2 changes: 1 addition & 1 deletion api-admin/api-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ components:
type: string
address:
type: string
createdAt:
closedAt:
$ref: '#/components/schemas/EpochMillisTimestamp'
acceptedAt:
$ref: '#/components/schemas/EpochMillisTimestamp'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class AcceptClosedPlaceCandidateUseCase(
placeId = place.id,
name = place.name,
address = place.address.toString(),
createdAt = candidate.createdAt,
closedAt = candidate.closedAt,
acceptedAt = candidate.acceptedAt,
ignoredAt = candidate.ignoredAt,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import club.staircrusher.place.application.port.out.persistence.ClosedPlaceCandi
import club.staircrusher.place.application.port.out.web.OpenDataService
import club.staircrusher.place.domain.model.ClosedPlaceCandidate
import club.staircrusher.stdlib.persistence.TransactionManager
import club.staircrusher.stdlib.time.toStartOfDay
import mu.KotlinLogging
import org.springframework.stereotype.Service
import java.util.UUID

Expand All @@ -14,31 +16,42 @@ class CreateClosedPlaceCandidatesUseCase(
private val placeApplicationService: PlaceApplicationService,
private val openDataService: OpenDataService,
) {
private val logger = KotlinLogging.logger {}

fun handle() {
val closedPlacesFromOpenData = openDataService.getClosedPlaces()

val closedPlaceCandidates = closedPlacesFromOpenData.mapNotNull { closedPlace ->
val nearbyPlaces = placeApplicationService.searchPlacesInCircle(closedPlace.location, SEARCH_RADIUS)
if (nearbyPlaces.isEmpty()) return@mapNotNull null

val similarPlace = nearbyPlaces
.minByOrNull { StringSimilarityComparator.getSimilarity(it.name, closedPlace.name) }
val placeToSimilarity = nearbyPlaces
.associateWith { StringSimilarityComparator.getSimilarity(it.name, closedPlace.name) }
val similarPlace = placeToSimilarity.minByOrNull { it.value }
?.also {
logger.info("[CreateClosedPlaceCandidates] most similar place for ${closedPlace.name} is ${it.key.name} with similarity of ${it.value}")
}
?.key
?: return@mapNotNull null

ClosedPlaceCandidate(
id = UUID.randomUUID().toString(),
placeId = similarPlace.id,
externalId = closedPlace.externalId,
originalName = closedPlace.name,
originalAddress = closedPlace.address,
closedAt = closedPlace.closedDate.toStartOfDay(),
)
}

transactionManager.doInTransaction {
val (placeIds ,externalIds) = closedPlaceCandidates.map { it.placeId to it.externalId }.unzip()

val alreadyExistingPlaceIds = closedPlaceCandidateRepository.findByPlaceIdIn(placeIds).map { it.placeId }
// 혹시 다른 externalId 지만 similarity 알고리즘의 부정확성 때문에 같은 장소로 판단되는지 확인하지 못해서 일단 보류합니다
// val alreadyExistingPlaceIds = closedPlaceCandidateRepository.findByPlaceIdIn(placeIds).map { it.placeId }
val alreadyExistingExternalIds = closedPlaceCandidateRepository.findByExternalIdIn(externalIds).map { it.externalId }
val filteredCandidates = closedPlaceCandidates
.filter { it.externalId !in alreadyExistingExternalIds && it.placeId !in alreadyExistingPlaceIds }
.filter { it.externalId !in alreadyExistingExternalIds }

closedPlaceCandidateRepository.saveAll(filteredCandidates)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class GetClosedPlaceCandidateUseCase(
placeId = place.id,
name = place.name,
address = place.address.toString(),
createdAt = candidate.createdAt,
closedAt = candidate.closedAt,
acceptedAt = candidate.acceptedAt,
ignoredAt = candidate.ignoredAt,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class IgnoreClosedPlaceCandidateUseCase(
placeId = place.id,
name = place.name,
address = place.address.toString(),
createdAt = candidate.createdAt,
closedAt = candidate.closedAt,
acceptedAt = candidate.acceptedAt,
ignoredAt = candidate.ignoredAt,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class ListClosedPlaceCandidatesUseCase(
placeId = place.id,
name = place.name,
address = place.address.toString(),
createdAt = candidate.createdAt,
closedAt = candidate.closedAt,
acceptedAt = candidate.acceptedAt,
ignoredAt = candidate.ignoredAt,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import java.time.LocalDate
data class ClosedPlaceResult(
val externalId: String,
val name: String,
val address: String,
val postalCode: String,
val location: Location,
val phoneNumber: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ data class NamedClosedPlaceCandidate(
val placeId: String,
val name: String,
val address: String,
val createdAt: Instant,
val closedAt: Instant,
val acceptedAt: Instant?,
val ignoredAt: Instant?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ class ClosedPlaceCandidate(
@Column(nullable = false)
val externalId: String,

@Column(nullable = false)
val originalName: String,

@Column(nullable = false)
val originalAddress: String,

@Column(nullable = false)
val closedAt: Instant,

@Column(nullable = true)
var acceptedAt: Instant? = null,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import club.staircrusher.place.application.port.out.persistence.ClosedPlaceCandi
import club.staircrusher.place.domain.model.ClosedPlaceCandidate
import club.staircrusher.place.domain.model.Place
import club.staircrusher.place.infra.adapter.`in`.controller.base.PlaceITBase
import club.staircrusher.stdlib.clock.SccClock
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -112,6 +113,9 @@ class AdminPlaceControllerTest : PlaceITBase() {
id = UUID.randomUUID().toString(),
placeId = place.id,
externalId = UUID.randomUUID().toString(),
originalName = place.name,
originalAddress = place.address.toString(),
closedAt = SccClock.instant(),
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class CreateClosedPlaceCandidateTest : PlaceITBase() {
ClosedPlaceResult(
externalId = externalId,
name = name,
address = "가짜",
postalCode = "21213",
location = location,
phoneNumber = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fun NamedClosedPlaceCandidate.toAdminDTO() = club.staircrusher.admin_api.spec.dt
placeId = placeId,
name = name,
address = address,
createdAt = createdAt.toDTO(),
closedAt = closedAt.toDTO(),
acceptedAt = acceptedAt?.toDTO(),
ignoredAt = ignoredAt?.toDTO(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class GovernmentOpenDataService(
opnSvcId = CAFE_CODE,
)

logger.info("Closed restaurant response: $restaurantResponse")
logger.info("Closed cafe response: $cafeResponse")

val closedRestaurants = restaurantResponse.result.body?.rows?.get(0)?.row?.mapNotNull {
it.toDTO()
} ?: emptyList()
Expand Down Expand Up @@ -170,7 +173,12 @@ class GovernmentOpenDataService(
get() = "${mgtNo};${opnSvcId}"

val location: Location?
get() = x?.let { locationConverter.toLocation(it.toDouble(), y!!.toDouble()) }
get() = x
?.takeIf { it.isNotBlank() }
?.let { locationConverter.toLocation(it.toDouble(), y!!.toDouble()) }

val address: String?
get() = rdnWhlAddr?.takeIf { it.isNotBlank() } ?: siteWhlAddr?.takeIf { it.isNotBlank() }
}
}
}
Expand All @@ -182,6 +190,7 @@ class GovernmentOpenDataService(
return ClosedPlaceResult(
externalId = externalId,
name = bplcNm ?: return null,
address = address ?: return null,
postalCode = rdnPostNo ?: return null,
location = location ?: return null,
phoneNumber = siteTel,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE closed_place_candidate
ADD COLUMN original_name TEXT NOT NULL,
ADD COLUMN original_address TEXT NOT NULL,
ADD COLUMN closed_at TIMESTAMP(6) WITH TIME ZONE NOT NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package club.staircrusher.stdlib.time

import java.time.DayOfWeek
import java.time.Instant
import java.time.LocalDate
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZoneOffset
Expand Down Expand Up @@ -46,3 +47,6 @@ fun Instant.getDayOfWeek(zoneId: ZoneId = ZoneId.of("Asia/Seoul")): DayOfWeek =
atZone(zoneId).dayOfWeek

fun Long.epochMilliToInstant() = Instant.ofEpochMilli(this)

fun LocalDate.toStartOfDay(zoneId: ZoneId = ZoneId.of("Asia/Seoul")): Instant =
this.atStartOfDay(zoneId).toInstant()

0 comments on commit 7786225

Please sign in to comment.