Skip to content

Commit b674f5a

Browse files
authored
Merge pull request #201 from 2025AlphaProject/hotfix/#198-addPlaceError
[HOTFIX]: 커스텀 장소 추가 오류 해결
2 parents 8465383 + a679085 commit b674f5a

1 file changed

Lines changed: 51 additions & 9 deletions

File tree

tour/services.py

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from services.exception_handler import *
1313
from django.utils import timezone
1414
from services.tour_api_service import TourAPIService, area_codes
15+
import difflib
16+
from services.utils import haversine
1517

1618
logger = logging.getLogger(APP_LOGGER)
1719

@@ -202,42 +204,73 @@ def _handle_custom_places(self, travel_id: int, custom_places: List[Dict]) -> No
202204
def _get_or_create_place(self, place_data: Dict) -> Place:
203205
"""근처 장소 검색 또는 새로운 장소 생성"""
204206
mapX, mapY = float(place_data['mapX']), float(place_data['mapY'])
207+
name = place_data.get('name')
208+
if name is None: NoRequiredParameterException()
209+
210+
# 이름이 일치하고, 그 일치하는 장소들 중에서 1km 내에 있는 장소 정보를 가져옵니다.
211+
place = self.__get_place_by_name_equal(name, mapX, mapY)
212+
if place is not None: return place
205213

214+
# 이름 불일치 시
206215
# 10m 내 기존 장소 검색
207-
existing_place = self._find_nearest_place(mapX, mapY)
216+
existing_place = self._find_nearest_place(name, mapX, mapY)
208217
if existing_place:
209218
return existing_place
210219

211220
# 새 장소 생성
212221
return self._create_new_place(place_data, mapX, mapY)
213222

214-
def _find_nearest_place(self, x: float, y: float) -> Optional[Place]:
215-
"""10m 내에 있는 가장 가까운 장소 찾기"""
223+
def _find_nearest_place(self, original_place_name:str, x: float, y: float) -> Optional[Place]:
224+
"""50m 내에 있는 가장 가까운 장소 찾기"""
216225
from django.db.models import FloatField
217226
from django.db.models.functions import Cast
218-
from services.utils import haversine
219227

220228
near_places = Place.objects.annotate(
221229
mapX_float=Cast('mapX', FloatField()),
222230
mapY_float=Cast('mapY', FloatField())
223231
).filter(
224-
mapX_float__gte=(x - self.LON_DIF_PER_10M),
225-
mapX_float__lte=(x + self.LON_DIF_PER_10M),
226-
mapY_float__gte=(y - self.LAT_DIF_PER_10M),
227-
mapY_float__lte=(y + self.LAT_DIF_PER_10M)
232+
mapX_float__gte=(x - (self.LON_DIF_PER_10M * 10)),
233+
mapX_float__lte=(x + (self.LON_DIF_PER_10M * 10)),
234+
mapY_float__gte=(y - (self.LAT_DIF_PER_10M * 10)),
235+
mapY_float__lte=(y + (self.LAT_DIF_PER_10M * 10))
228236
)
229237

238+
near_places_after_similarity = []
239+
for place in near_places:
240+
# 이름 유사도 검사
241+
if self._check_name_similarity(original_place_name, place.name):
242+
near_places_after_similarity.append(place)
243+
244+
if len(near_places_after_similarity) == 1: return near_places_after_similarity.pop() # 하나면 그냥 반환
245+
230246
closest_place = None
231247
min_distance = None
232248

233-
for place in near_places:
249+
for place in near_places_after_similarity:
234250
distance = haversine(x, y, float(place.mapX), float(place.mapY))
235251
if min_distance is None or distance < min_distance:
236252
closest_place = place
237253
min_distance = distance
238254

255+
239256
return closest_place
240257

258+
def _check_name_similarity(self, name1, name2):
259+
# 장소 이름 유사도 검사를 실시합니다.
260+
CUTLINE = 0.8 # 유사도 80% 이상 시 통과
261+
answer_bytes = bytes(name1, 'utf-8')
262+
input_bytes = bytes(name2, 'utf-8')
263+
answer_bytes_list = list(answer_bytes)
264+
input_bytes_list = list(input_bytes)
265+
266+
sm = difflib.SequenceMatcher(None, answer_bytes_list, input_bytes_list)
267+
similar = sm.ratio()
268+
if similar >= CUTLINE:
269+
return True
270+
else:
271+
return False
272+
273+
241274
def _create_new_place(self, place_data: Dict, mapX: float, mapY: float) -> Place:
242275
"""새로운 장소 생성"""
243276
name = place_data.get('name')
@@ -279,6 +312,15 @@ def _update_place_address(self, place: Place) -> None:
279312
serializer.is_valid(raise_exception=True)
280313
serializer.save()
281314

315+
@staticmethod
316+
def __get_place_by_name_equal(name, mapX, mapY):
317+
db_places = Place.objects.filter(name=name)
318+
for db_place in db_places:
319+
if haversine(db_place.mapX, db_place.mapY, mapX, mapY) > 1: # 1km보다 크다면
320+
continue
321+
return db_place
322+
return None
323+
282324

283325
class TravelUpdateService:
284326
"""여행 업데이트와 관련된 로직을 담당하는 서비스"""

0 commit comments

Comments
 (0)