WFS에서 BBOX와 FILTER는 왜 사용할까? 필요한 데이터만 조회하기
이전에 WMS와 WFS의 차이를 정리하면서 WFS는 지도 이미지를 받아오는 것이 아니라 공간 객체(Feature) 자체를 데이터로 가져오는 방식이라고 정리했다.
WFS를 처음 사용할 때는 GetFeature 요청만 보내면 데이터를 가져올 수 있으니 크게 어려울 게 없어 보였다.
예를 들어 이런 식이다.
SERVICE=WFS
VERSION=1.1.0
REQUEST=GetFeature
TYPENAME=sample_layer
그런데 데이터가 많은 레이어에서 아무 조건 없이 GetFeature를 호출하면 문제가 생길 수 있다.
필요한 건 현재 지도에 보이는 일부 데이터인데 전체 Feature를 전부 받아오고 있을 수도 있기 때문이다.
이럴 때 사용할 수 있는 대표적인 방법이 BBOX와 FILTER다.
아무 조건 없이 WFS를 호출하면 어떻게 될까?
예를 들어 하나의 레이어에 전국 데이터가 10만 건 있다고 해보자.
현재 사용자가 보고 있는 지도 화면에는 그중 몇백 건만 필요하더라도 아무 조건 없이 요청하면 서버 입장에서는 전체 데이터를 조회하게 될 수 있다.
각 Feature의 Geometry와 속성값까지 함께 전달할 수 있기 때문에 객체가 많아질수록 응답 데이터도 커진다.
실제로 예전에 WFS를 별다른 조건 없이 조회했을 때 응답 데이터가 약 1GB까지 커졌고 브라우저 메모리도 10GB 이상 사용하는 상황을 겪은 적이 있었다.
처음에는 브라우저 문제인가 싶었는데, 결국 클라이언트가 처리해야 하는 데이터 자체가 너무 많았던 것이다.
그래서 WFS에서는 필요한 데이터만 요청하는 것이 중요하다.
BBOX는 공간적인 범위를 제한한다
BBOX는 Bounding Box의 약자다.
쉽게 생각하면 지도에서 사각형 영역을 하나 정해서
이 범위 안에 있는 Feature만 보내줘.
라고 요청하는 것이다.
예를 들어:
BBOX=126.8,37.4,127.2,37.8
처럼 사용할 수 있다.
전체 Feature를 가져오는 대신 현재 필요한 공간 범위의 Feature만 조회하는 것이다.

웹지도에서는 BBOX를 어떻게 활용할까?
웹지도를 생각하면 이해하기 더 쉽다.
사용자가 현재 서울 주변을 보고 있다고 해보자.
전국 데이터를 전부 가져올 필요 없이 현재 화면 영역의 좌표를 이용해서:
현재 지도 영역
↓
Extent 계산
↓
BBOX 생성
↓
WFS 요청
↓
현재 영역의 Feature만 반환
하는 식으로 사용할 수 있다.
사용자가 지도를 이동하면 새로운 영역을 기준으로 다시 요청할 수도 있다.
OpenLayers 같은 웹지도 라이브러리를 사용한다면 현재 View의 extent를 얻어서 WFS 요청 범위로 활용하는 방식도 생각해볼 수 있다.
즉 BBOX는 “어디에 있는 데이터를 가져올 것인가?”를 제한한다고 생각하면 이해하기 쉽다.
FILTER는 데이터의 조건을 제한한다
BBOX가 위치를 기준으로 데이터를 줄이는 방법이라면 FILTER는 특정 조건에 맞는 Feature만 조회하기 위해 사용할 수 있다.
예를 들어 시설물 데이터가 있다고 해보자.
시설물 전체
등대
항구
부표
등대
부표
항구
등대
...
그런데 내가 필요한 데이터가 등대뿐이라면 전체 시설물을 가져올 필요가 없다.
개념적으로는:
전체 100,000건
↓ FILTER
종류 = '등대'
↓
등대 1,200건
처럼 필요한 Feature만 조회하는 것이다.
OGC Filter Encoding을 사용하는 환경이라면 요청에 XML 형태의 조건이 들어갈 수 있다.
예를 들면 개념적으로:
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>type</ogc:PropertyName>
<ogc:Literal>LIGHTHOUSE</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
서비스 구현이나 WFS 버전에 따라 실제 요청 방식은 달라질 수 있지만 핵심은 같다.
특정 조건을 만족하는 Feature만 요청한다.

BBOX와 FILTER의 차이
처음에는 둘 다 데이터를 줄이는 기능이라 비슷하게 느껴질 수 있다.
하지만 기준이 다르다.
| 기준 | 공간 범위 | 조건 |
| 의미 | 어디에 있는가? | 어떤 데이터인가? |
| 예시 | 현재 지도 화면 | 종류가 등대인 객체 |
| 목적 | 조회 영역 제한 | 조회 대상 제한 |
가장 간단하게 기억하면:
BBOX
→ 어디에 있는 데이터?
FILTER
→ 어떤 데이터?
라고 보면 된다.
BBOX와 FILTER를 같이 사용하면?
둘 중 하나만 사용해야 하는 것은 아니다.
예를 들어 현재 지도 화면 안에 있는 등대만 필요하다고 해보자.
전체 데이터가:
┌──────────────────────────────┐
│ ●등대 ▲부표 ●등대 │
│ │
│ ┌─────────────┐ │
│ │ ▲부표 ●등대 │ │
│ │ ●등대 ■항구 │ │
│ └─────────────┘ │
│ ■항구 ▲부표 │
└──────────────────────────────┘
이라면 먼저 공간 범위를 제한하고:
BBOX
↓
현재 지도 영역
그 안에서 다시 조건을 적용해서:
FILTER
type = '등대'
↓
●등대
●등대
처럼 필요한 Feature만 조회할 수 있다.
결국:
전체 데이터
↓
BBOX
↓
현재 영역 데이터
↓
FILTER
↓
필요한 Feature
가 되는 것이다.

데이터가 많을수록 차이가 커진다
Feature가 100개 정도라면 전체 데이터를 가져와도 별 차이를 느끼지 못할 수도 있다.
하지만 데이터가 수만 건, 수십만 건으로 늘어나면 상황이 달라진다.
예를 들어:
전체 조회
DB
↓
100,000 Feature 조회
↓
WFS 응답 생성
↓
네트워크 전송
↓
브라우저 파싱
↓
지도 렌더링
과
BBOX / FILTER 적용
DB
↓
필요한 Feature 조회
↓
작은 WFS 응답
↓
네트워크 전송
↓
브라우저 파싱
↓
지도 렌더링
은 서버뿐만 아니라 네트워크와 브라우저에서도 처리해야 하는 데이터 양이 달라진다.
그래서 WFS 성능 문제를 볼 때는 단순히
서버 메모리를 늘려야 하나?
만 생각하기보다 먼저 애초에 필요한 Feature만 요청하고 있는지 확인해볼 필요가 있다.
클라이언트에서 받은 뒤 거르면 안 될까?
물론 전체 데이터를 가져온 뒤 JavaScript에서 필요한 데이터만 골라낼 수도 있다.
하지만 이미:
DB 조회
→ WFS 응답 생성
→ 네트워크 전송
→ 브라우저 수신
→ 데이터 파싱
까지 끝난 뒤다.
100,000건을 받아서 브라우저에서 500건만 사용하는 것과 처음부터 서버에 500건만 요청하는 것은 다르다.
그래서 가능하다면 조회 단계에서 데이터 범위를 줄이는 것이 효율적이다.
BBOX를 사용한다고 항상 빨라지는 건 아니다
여기서 하나는 구분해야 한다.
BBOX나 FILTER를 붙였다고 해서 무조건 성능 문제가 해결되는 것은 아니다.
실제 성능에는:
- 데이터 건수
- Geometry 복잡도
- DB 인덱스
- 공간 인덱스
- 조건식
- 지도 서버 설정
- 반환 형식
등 여러 요소가 영향을 준다.
예를 들어 DB에서 공간 조건을 검색하는데 적절한 공간 인덱스가 없다면 범위를 제한했는데도 조회 자체가 느릴 수 있다.
따라서 BBOX와 FILTER는 불필요한 데이터를 줄이는 기본적인 방법으로 보고, 실제 속도 문제는 서버와 DB까지 함께 확인하는 것이 좋다.

정리
WFS는 Feature 자체를 전달하기 때문에 데이터가 많아질수록 응답 크기와 클라이언트 처리 부담도 커질 수 있다.
이럴 때 모든 데이터를 무조건 요청하기보다는 필요한 범위와 조건을 정해서 요청하는 것이 중요하다.
BBOX
→ 공간 범위 제한
FILTER
→ Feature 조건 제한
BBOX + FILTER
→ 특정 영역에서 필요한 Feature만 조회
예전에는 WFS 요청이 성공해서 데이터만 나오면 된다고 생각했는데, 데이터가 많아지니 “정상적으로 조회되는가”보다 “얼마나 필요한 데이터만 조회하는가”도 중요했다.
특히 대용량 WFS를 다룬다면 가장 먼저 현재 요청이 전체 Feature를 가져오고 있지는 않은지 확인해볼 만하다.