Post

⚓ DATT 06 - Place 도메인 및 장소 검색 구조 설계

⚓ DATT 06 - Place 도메인 및 장소 검색 구조 설계

개요

DATT 프로젝트 2주차에서는 장소(Place) 도메인 및 검색 구조를 중심으로 설계를 진행하였다.

1주차에서는 인증/보안 기반 구조를 구축하였다면,
2주차부터는 실제 서비스 핵심 데이터인 장소 데이터를 어떻게 저장하고 검색할 것인지에 대한 구조 설계가 핵심이었다.

특히 이번 작업에서는 다음 내용을 중심으로 정리하였다.

  • 공공데이터 기반 Place 도메인 설계
  • PlaceMaster 구조 도입 이유
  • 장소 검색 API 구현
  • 검색 Query 구조 설계
  • 검색 성능 개선 방향

왜 Place가 아니라 PlaceMaster인가

초기에는 단순히 Place Entity를 바로 만드는 방향을 고려하였다.

하지만 DATT는 일반적인 맛집 서비스와 달리:

1
공공데이터 기반 장소 데이터 수집

구조를 목표로 하고 있었다.

즉 현재 구조는:

1
2
3
4
공공데이터
→ Batch 적재
→ PlaceMaster 저장
→ 서비스 기능에서 활용

흐름이다.

따라서:

1
공공데이터 원본 저장용 도메인

과:

1
실제 서비스 기능용 Place

는 역할이 다르다고 판단하였다.

그래서 현재는:

1
PlaceMaster

라는 이름으로 공공데이터 기반 장소 마스터 테이블을 먼저 구축하였다.


PlaceMaster Entity 설계

현재 PlaceMaster는 공공데이터 원본 컬럼을 최대한 유지하는 방향으로 설계하였다.

핵심 필드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private String bizesId;
private String bizesNm;
private String brchNm;

private String indsLclsCd;
private String indsLclsNm;

private String indsMclsCd;
private String indsMclsNm;

private String indsSclsCd;
private String indsSclsNm;

private String ctprvnNm;
private String signguNm;
private String adongNm;
private String ldongNm;

private String lnoAdr;
private String rdnmAdr;

private Double lon;
private Double lat;

왜 공공데이터 컬럼을 그대로 유지했는가

처음에는 서비스용 카테고리 Enum을 바로 만들까 고민했다.

예:

1
2
3
CAFE
RESTAURANT
BAR

하지만 현재 단계에서는:

1
실제 공공데이터 업종 값 분석이 먼저

라고 판단하였다.

예를 들어 실제 데이터가:

1
커피전문점/카페

일 수도 있고:

1
커피음료

일 수도 있다.

즉 실제 데이터를 충분히 분석하지 않은 상태에서 서비스 카테고리를 먼저 추상화하면:

1
너무 이른 추상화

가 될 가능성이 높다.

따라서 현재는:

1
공공데이터 원본 구조 보존

을 우선하였다.


왜 PlaceCategory Enum을 보류했는가

처음에는 다음 구조를 고려하였다.

1
2
3
4
5
public enum PlaceCategory {
    CAFE,
    RESTAURANT,
    BAR
}

하지만 실제 공공데이터 업종 체계를 충분히 확인하지 않은 상태에서:

1
서비스 카테고리 정규화

를 먼저 진행하는 것은 위험하다고 판단하였다.

현재 기준으로는:

1
2
3
indsLclsNm
indsMclsNm
indsSclsNm

를 그대로 저장한 뒤,

이후 실제 데이터를 분석하면서:

1
서비스 카테고리 정책

을 별도로 설계하는 방향으로 변경하였다.


장소 검색 API 구현

2주차에서는 기본 장소 검색 API도 구현하였다.

현재 구조는:

1
GET /api/place-masters?keyword=스타벅스

형태로 구성하였다.

검색 흐름은 다음과 같다.

1
2
3
4
keyword 요청
→ Repository 검색
→ DTO 변환
→ 응답 반환

Service:

1
2
3
4
5
6
7
8
9
public List<PlaceMasterSearchResponse> searchByKeyword(
        String keyword
) {
    return placeMasterRepository
            .findByBizesNmContaining(keyword)
            .stream()
            .map(PlaceMasterSearchResponse::from)
            .toList();
}

왜 Entity를 직접 반환하지 않았는가

검색 응답은 DTO 기반으로 구성하였다.

즉:

1
Entity 직접 반환 X

구조다.

이유는 다음과 같다.

  • API 응답 스펙 분리
  • Entity 변경 영향 최소화
  • 불필요한 필드 노출 방지
  • 검색 응답 경량화

따라서 검색 응답은:

1
PlaceMasterSearchResponse

를 통해 반환하도록 구성하였다.


검색 Query 구조 설계

현재 검색 구조는 단순한:

1
findByBizesNmContaining()

수준이다.

하지만 이후 확장을 고려하여:

1
검색 조건 객체화

방향을 미리 고려하였다.

예상 검색 조건:

1
2
3
4
5
6
7
keyword
지역
업종
좌표
반경
정렬
페이징

즉 이후에는:

1
동적 Query 기반 검색 구조

로 확장될 예정이다.


왜 처음부터 QueryDSL을 도입하지 않았는가

현재 단계에서는 우선:

1
기본 검색 흐름 검증

이 목적이었다.

따라서:

  • QueryDSL
  • Elasticsearch
  • PostGIS

같은 고급 검색 기술은 아직 도입하지 않았다.

현재 우선순위는:

1
정상 동작 가능한 검색 구조

였기 때문이다.

즉:

1
2
3
단순 구조
→ 동작 검증
→ 이후 최적화

순서로 접근하고 있다.


검색 성능 개선 방향

현재 검색은:

1
LIKE '%keyword%'

기반이다.

즉 데이터가 많아질수록 검색 비용이 증가한다.

따라서 이후 다음 방향들을 고려하고 있다.


1. Index 최적화

예상 인덱스 대상:

1
2
3
4
bizes_nm
ctprvn_nm
signgu_nm
inds_lcls_nm

2. Pageable 기반 검색

현재는 단순 List 반환이지만 이후:

1
Pageable

기반으로 전환 예정이다.


3. Elasticsearch

다음 기능이 필요해지면 Elasticsearch 도입을 고려하고 있다.

  • 자동완성
  • 오타 허용 검색
  • 유사 검색
  • 검색 랭킹
  • 인기 검색

4. Redis Cache

반복 조회가 많은:

  • 인기 장소
  • 지역 기반 조회
  • 인기 검색어

등은 Redis Cache 적용을 고려 중이다.


5. PostGIS

현재 좌표 저장은:

1
2
Double lon;
Double lat;

기반이다.

하지만 이후:

1
거리 계산 최적화

가 필요해지면:

1
PostGIS

도입을 검토하고 있다.


Place 검색 구조에서 중요하게 본 점

이번 Place 도메인 설계에서 가장 중요하게 본 기준은 다음이었다.

1
과도한 추상화를 피할 것

이었다.

즉:

  • 실제 데이터 확인 전 서비스 카테고리 추상화 X
  • 처음부터 Elasticsearch 도입 X
  • 처음부터 PostGIS 도입 X
  • 먼저 단순 구조로 동작 검증

방향을 우선하였다.

현재 단계의 목적은:

1
공공데이터 기반 장소 플랫폼의 기반 구축

이기 때문이다.


테스트 코드 작성

검색 구조는 테스트 코드 기반으로 검증하였다.

검증 대상:

  • PlaceMaster 저장
  • bizesId 중복 확인
  • 상호명 기반 검색
  • Service 검색 흐름

테스트 메서드는 기존과 동일하게 BDD 스타일을 사용하였다.

1
2
3
void givenPlaceMaster_whenSave_thenPersistPlaceMaster()

void givenKeyword_whenSearchByKeyword_thenReturnPlaceMasters()

마무리

2주차를 진행하면서 단순 CRUD 이상의 설계 관점을 많이 고민하게 되었다.

특히:

  • 원본 데이터 보존
  • 서비스 추상화 시점
  • 검색 확장 가능성
  • 검색 성능
  • Batch 기반 적재 구조

등을 실제로 고려하면서 설계를 진행하였다.

현재는 아직:

1
검색 가능한 장소 플랫폼 기반

수준이지만,

이후:

  • Elasticsearch
  • 추천 시스템
  • 지도 기반 검색
  • 인기 장소
  • 리뷰/저장 기능

등으로 확장할 수 있는 기반 구조를 구축한 상태다.

This post is licensed under CC BY 4.0 by the author.