본문 바로가기
게임서버-스파르타코딩NodeJs_7기/CH6 최종 프로젝트

GEOSEARCH와 GEORADIUS

by GREEN나무 2025. 3. 20.
728x90

GEOSEARCH와 GEORADIUS는 둘 다 Valkey의 지리 공간 데이터를 활용하는 명령어지만, 사용 목적과 성능 차이 때문에 선택이 달라집니다. 

1. 명령어 차이

  • GEORADIUS: 특정 좌표를 기준으로 반경 내의 위치를 검색합니다.
  • GEOSEARCH: 보다 유연한 검색을 제공하며, 기준 좌표나 특정 지점을 중심으로 다양한 형태의 검색이 가능합니다.

2. 차이점 비교

항목 GEORADIUS GEOSEARCH
기준점 설정 좌표 기반 좌표 또는 키 기반
검색 영역 원형 반경 검색 원형 또는 사각형 영역 검색
정렬 거리 기준 정렬 거리 기준 정렬 및 필터링 지원
반환 데이터 위치 이름, 거리 등 선택 가능 위치 이름, 거리 등 선택 가능
성능 단순한 반경 검색에 최적화 복잡한 공간 검색에 적합

3. 어떤 상황에서 사용하는가?

  • GEORADIUS는 단순히 반경 내의 위치를 빠르게 찾고 싶을 때 사용합니다.
    → 예: 사용자의 현재 위치에서 5km 이내의 편의점을 찾는 경우
  • GEOSEARCH는 더 복잡한 조건이나 사각형 영역을 활용해 위치를 검색해야 할 때 유용합니다.
    → 예: 사용자의 이동 경로를 기준으로 경로 주변 일정 거리 내의 관광지를 찾는 경우, ☆가장 가까운 하나만 선택한 경우

4. 실제 사용 예시

# GEORADIUS 사용 예시
GEORADIUS location 127.0 37.5 5 km WITHDIST
  • 위치 기준 반경 5km 이내의 모든 장소 검색
  • 거리 정보 포함
# GEOSEARCH 사용 예시
GEOSEARCH location FROMLOC 127.0 37.5 BYBOX 10 10 km ASC
  • 기준 위치에서 가로 10km, 세로 10km의 사각형 영역 내의 장소 검색
  • 거리 기준으로 오름차순 정렬

결론

  • 단순한 반경 검색이 필요하다면 → GEORADIUS
  • 복잡한 영역 검색이나 정렬이 필요하다면 → GEOSEARCH

검색 조건의 복잡성이나 성능 최적화가 필요해서 다른 명령어를 선택.


 

geoservice.ts

  /**
   * 반경 5m 이내 북마크 검색 및 상세 정보 반환
   * @param latitude 사용자 위도
   * @param longitude 사용자 경도
   * @returns 반경 내 북마크 상세 정보 목록
   */
  async getNearbyBookmarksS(
    latitude: number,
    longitude: number,
  ): Promise<any[]> {
    console.log('범위탐색');
    // 1. GEO에서 반경 5m 내의 북마크 ID 목록 가져오기
    const nearbyIds = (await this.client.georadius(
      this.S_GEO_KEY,
      longitude, // 경도먼저
      latitude,
      5,
      'm',
    )) as string[];
    console.log('범위탐색 nearbyIds: ', nearbyIds);
    // 2. ID 목록을 기반으로 Hash에서 상세 정보 가져오기
    const bookmarkDetails = await Promise.all(
      nearbyIds.map(async (id) => {
        const hashKey = `bookmarkS:${id}`;
        const details = await this.client.hgetall(hashKey);
        return { id, ...details }; // ID와 상세 정보를 함께 반환
        // Hash로 저장된 데이터는  ...details 로 객체의 모든 속성을 전개할 수 있다.
      }),
    );

    console.log('범위탐색 bookmarkDetails: ', bookmarkDetails);
    return bookmarkDetails; // 널이 반환됨
  }

  /**
   * 반경 5m 이내 북마크 검색 및 상세 정보 반환
   * @param latitude 사용자 위도
   * @param longitude 사용자 경도
   * @returns 반경 내 북마크 상세 정보 목록
   */
  async getNearbyBookmarkP(
    latitude: number,
    longitude: number,
  ): Promise<any | null> {
    // 1. GEO에서 반경 5m 내의 가장 가까운 북마크 ID 가져오기
    const nearestIds = (await this.client.geosearch(
      this.P_GEO_KEY,
      'FROMLONLAT',
      longitude, // 경도먼저
      latitude,
      'BYRADIUS',
      5,
      'm',
      'ASC', // 가장 가까운 순으로 정렬
      'COUNT',
      1, // 1개만 가져옴
    )) as string[];

    if (!nearestIds || nearestIds.length === 0) return null; // 반경 내 북마크가 없으면 null 반환

    // 2. 해당 ID의 Hash에서 상세 정보 가져오기
    const nearestId = nearestIds[0];
    const hashKey = `bookmarkP:${nearestId}`;
    const details = await this.client.hgetall(hashKey);

    return details && Object.keys(details).length > 0
      ? { id: nearestId, ...details }
      : null;
  }