지리 공간

지리 공간 (Geospatial)

Pinot의 지리 공간 지원에 대해 설명해요.

출처: 문서

본문

Pinot는 SQL/MM 지리 공간 데이터를 지원하며 Open Geospatial Consortium (OGC) OpenGIS Specifications을 준수해요. 여기에는 다음이 포함돼요.

  • point, line, polygon 같은 지리 공간 데이터 유형
  • 공간 속성과 관계를 조회하기 위한 지리 공간 함수
  • 공간 연산의 효율적 처리를 위한 지리 공간 인덱싱

언제 사용하나 (When to use)

쿼리가 WHERE 절에서 ST_Distance로 공간 거리 계산을 포함할 때 지리 공간 인덱싱을 사용하세요. H3 기반 지리 공간 인덱스는 기준점에서 특정 거리 내의 레코드를 찾는 쿼리를 크게 가속화할 수 있어요.

지원 컬럼 유형

H3 지리 공간 인덱스는 구형 지리 데이터를 포함하는 BYTES(단일 값) 컬럼을 필요로 해요. 컬럼은 transformFunction을 사용해 좌표를 SphericalGeography 형식으로 변환해야 해요.

지리 공간 데이터 유형

지리 공간 데이터 유형은 경계와 차원 같은 공간 구조를 추상화하고 캡슐화해요. 여러 면에서 공간 데이터 유형은 단순히 도형으로 이해될 수 있어요. Pinot는 WKT(Well-Known Text)와 WKB(Well-Known Binary) 형태의 지리 공간 객체를 지원해요. 예:

  • POINT (0, 0)
  • LINESTRING (0 0, 1 1, 2 1, 2 2)
  • POLYGON (0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1)
  • MULTIPOINT (0 0, 1 2)
  • MULTILINESTRING ((0 0, 1 1, 1 2), (2 3, 3 2, 5 4))
  • MULTIPOLYGON (((0 0, 4 0, 4 4, 0 4, 0 0), (1 1, 2 1, 2 2, 1 2, 1 1)), ((-1 -1, -1 -2, -2 -2, -2 -1, -1 -1)))
  • GEOMETRYCOLLECTION(POINT(2 0),POLYGON((0 0, 1 0, 1 1, 0 1, 0 0)))

Geometry vs Geography

좌표가 지리적(geographics)이거나 위도/경도인 데이터를 갖는 것이 흔해요. Mercator나 UTM의 좌표와 달리 지리 좌표는 데카르트 좌표가 아니에요.

  • 지리 좌표는 평면에 그려진 원점으로부터의 선형 거리를 나타내지 않아요. 대신 이 구형 좌표는 지구본 위의 각도 좌표를 설명해요.
  • 구형 좌표는 기준 자오선으로부터의 회전 각도(경도)와 적도로부터의 각도(위도)로 점을 지정해요.

지리 좌표를 근사 데카르트 좌표로 취급하고 계속 공간 계산을 수행할 수 있어요. 그러나 거리, 길이, 면적 측정은 무의미해져요. 구형 좌표는 각도 거리를 측정하므로 단위는 **도(degrees)**이에요.

Pinot는 geometry와 geography 유형을 모두 지원하며, 이들은 섹션에 표시된 대로 해당 함수로 구성될 수 있어요. geography 유형의 경우 ST_Distance, ST_Area 같은 측정 함수가 각각 지구의 구형 거리와 구형 면적을 계산해요.

지리 공간 함수

지리 공간 데이터를 조작하기 위해 Pinot는 기하학 구성요소 분석, 공간 관계 결정, 기하학 조작을 위한 함수 집합을 제공해요. 특히 ST_ 접두사로 시작하는 지리 공간 함수는 SQL/MM 사양을 지원해요.

Pinot에서 기본 제공되는 지리 공간 함수는 다음과 같아요.

집계 (Aggregations)

ST_Union(geometry[] g1_array) → Geometry 기하학 집합에서 MULTI geometry나 NON-MULTI geometry를 반환하는 집계 함수. NULL 기하학은 무시해요.

생성자 (Constructors)

측정 (Measurements)

  • ST_Area(Geometry/Geography g) → double geometry 유형의 경우 기하학의 2D 유클리드 면적을 반환해요. geography의 경우 지구에 대한 구형 모델을 사용해 폴리곤이나 멀티-폴리곤의 면적을 제곱미터로 반환해요.
  • ST_Distance(Geometry/Geography g1, Geometry/Geography g2) → double geometry 유형의 경우 투영된 단위에서 두 기하학 사이의 2차원 데카르트 최소 거리(공간 참조 기반)를 반환해요. geography의 경우 두 SphericalGeography 점 사이의 대권(great-circle) 거리를 미터로 반환해요. g1, g2는 같은 유형이어야 해요.
  • ST_GeometryType(Geometry g) → String 기하학의 유형을 문자열로 반환해요. 예: ST_Linestring, ST_Polygon, ST_MultiPolygon 등.

출력 (Outputs)

변환 (Conversion)

관계 (Relationship)

  • ST_Contains(Geometry/Geography, Geometry/Geography) → boolean 두 번째 geometry/geography의 어떤 점도 첫 번째 geometry/geography의 외부에 있지 않고, 첫 번째 geometry의 내부의 적어도 한 점이 두 번째 geometry의 내부에 있으면 true를 반환해요. 경고: Geography에서 ST_Contains는 대략적인 근사만 제공해요.
  • ST_Equals(Geometry, Geometry) → boolean 주어진 기하학들이 같은 geometry/geography를 나타내면 true를 반환해요.
  • ST_Within(Geometry, Geometry) → boolean 첫 번째 geometry가 두 번째 geometry 내부에 완전히 있으면 true를 반환해요.

지리 공간 인덱스

지리 공간 함수는 일반적으로 평가 비용이 비싸며, geoindex를 사용하면 쿼리 평가를 크게 가속화할 수 있어요. Pinot의 Geoindex는 육각형 기반 계층 그리딩인 Uber의 H3를 기반으로 해요.

주어진 지리 공간 위치(경도, 위도)는 하나의 육각형( H3Index로 표현됨)으로 매핑될 수 있어요. 그리고 H3에서 그 이웃들은 육각형의 고리로 근사될 수 있어요. 임의의 두 지리 공간 위치 사이의 거리를 빠르게 식별하기 위해 두 위치를 H3Index로 변환한 다음 H3 사이의 거리를 확인할 수 있어요. H3 거리는 육각형의 수로 측정돼요.

예를 들어 아래 다이어그램에서 빨간 육각형들은 중앙 육각형의 거리 1 안에 있어요. 육각형의 크기는 인덱싱의 해상도에 의해 결정돼요. resolutions 수준과 해당 정밀도(km 단위) 표를 확인하세요.

geoindex 사용 방법

geoindex를 사용하려면 먼저 스키마에서 지리 위치 필드를 bytes로 선언하세요. (QuickStart example 예시 참조)

{
  "dataType": "BYTES",
  "name": "location_st_point",
  "transformFunction": "toSphericalGeography(stPoint(lon,lat))"
}

ST_Distance 함수가 필요한 SphericalGeography 형식으로 생성된 point를 변환하는 transformFunction 사용에 주목하세요.

다음으로 table configuration에서 지리 공간 인덱스를 선언해야 해요.

indexes 섹션을 사용하는 후자를 권장해요.

{
  "fieldConfigList": [
    {
      "name": "location_st_point",
      "encodingType":"RAW", // this actually disables the dictionary
      "indexes": {
        "h3": {
          "resolution": [13, 5, 6]
        }
      }
    }
  ],
  ...
}

대안으로 H3 인덱스를 구성하는 이전 방식도 여전히 지원돼요.

{
  "fieldConfigList": [{
    "name": "location_st_point",
    "encodingType":"RAW", // this actually disables the dictionary
    "indexTypes":["H3"],
    "properties": {
      "resolutions": "13, 5, 6" // Here resolutions must be a string with ints separated by commas 
    }
  }],
  ...
}

아래 쿼리는 geoindex를 사용해 베이 지역의 주어진 점에서 5km 내의 스타벅스 매장을 필터링해요.

SELECT address, ST_DISTANCE(location_st_point, ST_Point(-122, 37, 1))
FROM starbucksStores
WHERE ST_DISTANCE(location_st_point, ST_Point(-122, 37, 1)) < 5000
limit 1000

이전 세그먼트 리로드

변환된 geometry 컬럼과 H3 인덱스를 이미 세그먼트가 있는 테이블에 추가하면 이전 세그먼트에 geometry를 파생하는 데 필요한 원본 컬럼이 없을 수 있어요. 그 행들은 리로드 중 기본 빈 BYTES 값을 받아요.

이 상황에서 리로드 전에 ingestionConfig.continueOnError를 true로 설정하세요. Pinot는 그러면 새 세그먼트와 리로드된 세그먼트 모두에 대해 H3 인덱스를 구축하는 동안 빈, 유효하지 않은, 비-point geometry 값을 건너뛰어요. 영향을 받는 행은 H3 인덱스 밖에 남아요. continueOnError가 false이면 유효하지 않은 geometry는 H3 인덱스가 구축되지 못하게 해요.

세그먼트가 null을 저장하고 쿼리가 advanced null handling을 활성화하면 Pinot는 H3 인덱스 결과에서 null geometry 행을 제외해요. 이는 무한대 및 하한만 있는 ST_Distance 범위 조건자에도 적용되므로, 누락된 geometry가 H3 포스팅이 없다는 이유만으로 매치가 되지는 않아요.

geoindex 동작 방식

Pinot geoindex는 정확성을 유지하면서 쿼리 평가를 가속화해요. 현재 geoindex는 WHERE 절의 ST_Distance 함수를 지원해요.

높은 수준에서 geoindex는 주어진 위치의 인근 육각형 내 레코드를 검색한 다음 ST_Distance를 사용해 일치한 결과를 정확하게 필터링하는 데 사용돼요.

위의 예시 다이어그램에서처럼 샌프란시스코 주변 주어진 거리 내(빨간 원 안 영역)의 모든 관련 점을 찾으려면 geoindex가 있는 알고리즘은:

  • 먼저 범위를 포함하는 H3 거리 x를 찾음(예: 빨간 원 안).
  • 그런 다음 H3 거리 내의 점( kRing(x) 안에 완전히 포함된 육각형들이 커버하는 점들)에 대해 필터링 없이 직접 수용함.
  • 마지막으로 빨간 원 H3 거리의 바깥 가장자리에 있는 kRing(x)의 육각형 안에 포함된 점들의 경우, ST_Distance(loc1, loc2) < x 조건을 평가해 원 안에 있는 것들만 찾도록 필터링함.

제한 사항

  • H3 지리 공간 인덱스는 WHERE 절에서 ST_Distance만 지원해요. ST_Contains나 ST_Within 같은 다른 공간 조건자는 인덱스를 사용하지 않아요.
  • 컬럼은 raw 인코딩의 BYTES 유형이어야 해요 — 사전 인코딩은 H3 인덱스와 호환되지 않아요.
  • 인덱스는 H3 육각형 그리드를 기반으로 하므로 정확도는 구성된 해상도에 의존해요. 정밀도와 성능의 균형을 맞추기 위해 여러 해상도를 지정할 수 있어요.
  • 단일 값 컬럼만 지원돼요.

더 알아보기 (Learn more)