지난 5월부터 미국에서 알게된 형과 교수님과 친구와 스타트업을 하게 되었다..
BM은 무엇인가?
내비게이션이다..
정말 살면서 한번도 직접 만들어볼거라고 생각 해본적 없는 BM이었다. 그래서? 오히려 신났다.

내가 이런 BM으로 서비스를 만들어 볼 수 있다고? 성장 했잖아라고 생각했다.
하지만 정말 처음이었기에 배경 지식 또한 없었고, 일단 기존에 있는 라이브러리가 있는지부터 찾아보게 되었다.
결론은, 먼저 OSRM과 OSM을 이해하고, 프로토타입을 만드는 일을 하는 것이다.
우리의 최종 목표는 OSRM이 아닌 우리만의 알고리즘을 직접 만들어서 도입하는 것이다.
물론 그러기 위해서는 데이터도 많이 필요하고, 시간과 돈도 필요했다.
어쨌든, 먼저 일단 OSRM에 대해서 알아보자.
OSM은 그저 지도이미지 Open Street Map의 약자로 전 세계 누구나 자유롭게 편집·활용할 수 있는 오픈 소스 지도 프로젝트라고 한다.
2004년 영국에서 시작되었고, 현재는 전 세계 자원봉사자들이 GPS 기기, 항공사진, 현장 조사 등을 통해 지도 데이터를 지속적으로 업데이트하고 있단다. 이런건 됐고,
핵심은 무료로 접근 가능하고, 상업적·비상업적 용도로 모두 활용 가능하다는 것
기본적으로 XML 기반의 .osm 형식을 사용한다.
세 가지 기본 요소:
- Node: 특정 위치(위경도 점)
- 우리가 흔히 아는 위치 나타내는 점.
- 독립적으로 존재 가능
- 선이나 면을 구성 할 수 있음
- Way: 선/폴리곤 (도로, 강, 건물 외곽 등)
- 노드가 서로 연결된 선(도로, 경로, 강줄기 등 표현)
- Open ways
- 시작점, 끝점 다른 선(도로, 개울, 철도선)
- Closed ways
- 시작점, 끝점 동일한 선(왕복)
- Open ways
- 일반적인 면이나 구역을 표현할 때 사용
- 노드가 서로 연결된 선(도로, 경로, 강줄기 등 표현)
- Area
- Closed ways 중 내부가 채워진 형태
- Relation: 노드와 웨이를 묶어 복잡한 구조 표현 (예: 버스 노선, 다각형 집합 등)
- 더 복잡한 형태, 물리적으로 연결되지 않은 요소들을 하나의 관계로 묶고자 할 때 사용
- ex) 여로 도로를 하나의 버스 노선으로 묶기, 여러 건물 묶어서 캠퍼스로 표현하기 등
- 예시 : 버스노선
- 더 복잡한 형태, 물리적으로 연결되지 않은 요소들을 하나의 관계로 묶고자 할 때 사용
Relation ID: 3001
Type: route
Members:
- way: 516로
- way: 1100로
Tags:
- type=route
- route=bus
- ref=502번
- Tags
- 모든 요소는 태그 부여 가능
- 태그로 요소 구분, 어떤 속성 가지는지 설명
- ex)highway = primary, name=산록로, maxspeed=60
PostgreSQL에 저장하면 아래와 같은 파일들이 있다.
planet_osm_line
- 설명: 선(라인) 형태의 지리정보를 저장하는 테이블
- 용도: 도로, 강, 철도, 경계선, 산책로 등 선으로 표현되는 객체들
- 주요 컬럼:
- osm_id (OSM 원본 아이디)
- highway (도로 종류)
- name (이름)
- tags (hstore 형식으로 태그 정보 저장)
- way (지리공간 geometry 타입)
planet_osm_point
- 설명: 점(point) 형태의 지리정보 저장
- 용도: 가로등, 신호등, 우체통, 버스 정류장, 나무 등 점으로 표현되는 객체
- 주요 컬럼:
- osm_id, name, tags, way (point geometry)
planet_osm_polygon
- 설명: 다각형(polygon) 형태의 지리정보 저장
- 용도: 건물, 공원, 호수, 토지 이용 구역 등 영역이나 면적을 가지는 객체
- 주요 컬럼:
- osm_id, name, tags, way (polygon geometry)
planet_osm_roads
- 설명: planet_osm_line 테이블에서 도로 관련 정보만 따로 추린 테이블
- 용도: 도로 네트워크를 빠르게 쿼리하거나 경로 탐색에 사용
- 주요 컬럼:
- osm_id, name, highway, tags, way (line geometry)
planet_osm_nodes
- 설명: OSM 원본 데이터 중 노드(node) 데이터만 저장한 테이블
- 용도: 라인이나 폴리곤을 구성하는 점, 또는 개별 점 객체
- 주요 컬럼:
- osm_id, tags, way (point geometry)
planet_osm_ways
- 설명: OSM 원본의 ways 정보를 저장하는 테이블
- 용도: 노드들의 연결 정보(라인, 폴리곤 등)를 저장
- 주요 컬럼:
- osm_id, tags
planet_osm_rels
- 설명: OSM relation 정보를 저장하는 테이블
- 용도: 복잡한 관계나 멀티폴리곤, 경로 등 다중 객체 묶음 표현
- 주요 컬럼:
- osm_id, tags
osm2pgsql_properties
- 설명: osm2pgsql 로딩 시 내부적으로 사용하는 설정 및 메타정보 저장
- 용도: 기본 설정이나 버전 정보 등
spatial_ref_sys
- 설명: 공간 참조 시스템(SRS) 정의 테이블
- 용도: 좌표계 정보 저장 (EPSG 코드, Proj4 텍스트 등)
이렇게 OSM에 대해 알아보았다.
그럼 이젠 OSRM이 무엇인가?
오픈소스 경로 탐색 엔진이다. 쉽게 말해, 구글맵이나 네이버 지도 같은 내비게이션 앱이 하는 “출발지 → 목적지 최적 경로 찾기” 기능을 직접 구현할 수 있게 해주는 소프트웨어인 것
먼저, 사용하기 위해서는 OSM 데이터를 다운받아야하고,
그 다음에 extract, partition, customize의 단계로 전처리를 하여서 마지막에 route 서버를 실행하여 사용한다.
이를 한번에 하기 위해서 아래와 같은 docker-compose 파일을 만들었다.
version: '3.8'
services:
postgis:
image: postgis/postgis:15-3.3
platform: linux/amd64
container_name: postgis
ports:
- "5432:5432"
environment:
POSTGRES_DB: {데이터베이스 이름}
POSTGRES_USER: {사용자 이름}
POSTGRES_PASSWORD: {비밀번호}
volumes:
- postgis-data:/var/lib/postgresql/data
osrm-extract:
image: osrm/osrm-backend:latest
container_name: osrm-extract
command: osrm-extract -p /opt/car.lua /data/south-korea-latest.osm.pbf
volumes:
- ./osrm-data:/data
platform: linux/amd64
osrm-partition:
image: osrm/osrm-backend:latest
container_name: osrm-partition
command: osrm-partition /data/south-korea-latest.osrm
volumes:
- ./osrm-data:/data
depends_on:
- osrm-extract
platform: linux/amd64
osrm-customize:
image: osrm/osrm-backend:latest
container_name: osrm-customize
command: osrm-customize /data/south-korea-latest.osrm
volumes:
- ./osrm-data:/data
depends_on:
- osrm-partition
platform: linux/amd64
osrm:
image: osrm/osrm-backend:latest
container_name: osrm
command: osrm-routed --algorithm mld /data/south-korea-latest.osrm
ports:
- "8000:5000"
volumes:
- ./osrm-data:/data
depends_on:
- osrm-customize
platform: linux/amd64
volumes:
postgis-data:
그 다음 우리는 스프링 부트 기반의 서버를 구축할것이기 때문에
아래 처럼 service를 구현한다.
@Slf4j
@Service
public class OsrmService {
@Value("${osrm.url}")
private String baseUrl;
private final WebClient webClient = WebClient.builder().build();
private final ObjectMapper objectMapper = new ObjectMapper();
public RouteResponse getRoute(List<Coordinate> coordinates) throws JsonProcessingException {
String coords = coordinates.stream()
.map(c -> c.lon() + "," + c.lat())
.collect(Collectors.joining(";"));
String url = UriComponentsBuilder.fromUriString(baseUrl + coords)
.queryParam("overview", "full")
.queryParam("geometries", "geojson")
.build()
.toUriString();
log.info(url);
log.info("Coordinates: {}", coordinates);
String responseBody = webClient.get()
.uri(url)
.retrieve()
.bodyToMono(String.class)
.doOnNext(body -> log.info("Response Body: {}", body))
.block();
log.info(responseBody);
return objectMapper.readValue(responseBody, RouteResponse.class);
}
}
이렇게 해서 경로를 얻을 수 있는 프로토 타입 코드를 작성한다.
예시로 뽑으면 아래와 같은식으로 나온다.

프로토 타입은 여기까지 한다. -끄으읏-
'노예 일지 > 스타트업 노예일지' 카테고리의 다른 글
| 토스(Toss) 결제 연동하기 (0) | 2025.12.21 |
|---|---|
| 노예는 시키면 뭐든해요. 프런트 만드는 백엔드 (0) | 2025.11.28 |