Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

GeoJSON

入力 出力 エイリアス

説明

GeoJSON データは、単一の FeatureCollection ドキュメントとしてやり取りされ、ClickHouse ではこれを 3 つのカラム — idgeometryproperties — に対応付けます。各 Feature につき 1 組です。ドキュメントを読み込むと、Feature ごとに 1 行が生成されます。書き込むと、1 行ごとに 1 つの Feature が生成されます。

データの読み取り

FeatureCollection を読み込むと、地物 ごとに 1 行が生成され、次の固定スキーマになります。

カラム 説明
id Nullable(String) 地物 の id メンバー (JSON の文字列または数値) 。テキストとして格納されます。id が存在しない場合または null の場合は NULL になり、明示的に空文字列が指定された id は '' のまま保持されます。
geometry Geometry 地物 のジオメトリ。Geometry の Variant 型として格納されます。
properties Nullable(JSON) 地物 の properties object。半構造化 JSON カラムとして格納されます。明示的な "properties": nullNULL として保持されます。

各ジオメトリは ClickHouse の Geometry 型 (Variant) に格納されます。サポートされている GeoJSON ジオメトリ型 は PointMultiPointLineStringMultiLineStringPolygonMultiPolygon です。残りの GeoJSON ジオメトリ型 GeometryCollectionGeometry 型では表現できません。これを geometry カラムに読み込むと、デフォルトでは例外が発生しますが、代わりに NULL を挿入するように変更することもできます。詳しくは下の サポートされない ジオメトリ型 の処理 を参照してください。デフォルトでは、geometry カラムが NULL になるのは 地物 の geometry が明示的な JSON null の場合だけです。input_format_geojson_unsupported_geometry_handling = 'null' を指定すると、サポートされない ジオメトリ型 の場合も NULL になります。

ドキュメントの構造は検証されます。最上位の typeFeatureCollection でなければならず、features の各要素は typeFeature でなければなりません。デフォルトでは、coordinates は GeoJSON の shape の不変条件を満たす必要があります。つまり、LineString (および MultiLineString の各 line) は少なくとも 2 つの Point を持つ必要があり、Polygon の リング (および MultiPolygon の各 リング) は閉じていて、少なくとも 4 つの Point を持つ必要があります (Geometry validation を参照) 。不正なドキュメントは黙って読み込まれることはなく、拒否されます。

キーの順序は柔軟です。最上位の typefeatures 配列の前でも後でもよく、geometry object 内では coordinatestype の前でも後でもかまいません。

スキーマ推論では上記の固定スキーマが返されるため、DESCRIBESELECT ... FROM format(...) はテーブル定義なしで動作します。

複数のジオメトリ型が含まれる、次の GeoJSON ファイル london.geojson を例にします。

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "id": "1",
            "geometry": {"type": "Point", "coordinates": [-0.0761, 51.5081]},
            "properties": {"name": "Tower of London", "feature_type": "landmark", "year_built": 1078}
        },
        {
            "type": "Feature",
            "id": "2",
            "geometry": {
                "type": "LineString",
                "coordinates": [[-0.2500, 51.4700], [-0.1800, 51.4900], [-0.1200, 51.5060], [-0.0700, 51.5050], [0.0000, 51.5100]]
            },
            "properties": {"name": "River Thames", "feature_type": "river", "length_km": 346}
        },
        {
            "type": "Feature",
            "id": "3",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[-0.1880, 51.5074], [-0.1533, 51.5074], [-0.1533, 51.5153], [-0.1880, 51.5153], [-0.1880, 51.5074]]]
            },
            "properties": {"name": "Hyde Park", "feature_type": "park", "area_km2": 1.42}
        }
    ]
}

ファイルに対してクエリを実行し、ジオメトリ型を確認できます。

Querysql
SELECT id, properties.name AS name, variantType(geometry) AS geo_type
FROM file('london.geojson', GeoJSON);
Responseresponse
┌─id─┬─name────────────┬─geo_type───┐
│ 1  │ Tower of London │ Point      │
│ 2  │ River Thames    │ LineString │
│ 3  │ Hyde Park       │ Polygon    │
└────┴─────────────────┴────────────┘

ファイル拡張子 .geojson は自動的に検出されるため、フォーマットの引数は省略できます。

Querysql
SELECT id, properties.name AS name, variantType(geometry) AS geo_type
FROM file('london.geojson');

Geometry オブジェクトの基底型は、variantType を使って確認できます:

Querysql
SELECT properties.name AS name, geometry, variantType(geometry)
FROM file('london.geojson', GeoJSON);
Responseresponse
Row 1:
──────
name:                  Tower of London
geometry:              (-0.0761,51.5081)
variantType(geometry): Point

Row 2:
──────
name:                  River Thames
geometry:              [(-0.25,51.47),(-0.18,51.49),(-0.12,51.506),(-0.07,51.505),(0,51.51)]
variantType(geometry): LineString

Row 3:
──────
name:                  Hyde Park
geometry:              [[(-0.188,51.5074),(-0.1533,51.5074),(-0.1533,51.5153),(-0.188,51.5153),(-0.188,51.5074)]]
variantType(geometry): Polygon

また、基になるデータは次のように抽出できます:

Querysql
SELECT properties.name AS name, variantType(geometry), geometry.Point, geometry.LineString, geometry.Polygon
FROM file('london.geojson', GeoJSON);
Responseresponse
Row 1:
──────
name:                  Tower of London
variantType(geometry): Point
geometry.Point:        (-0.0761,51.5081)
geometry.LineString:   []
geometry.Polygon:      []

Row 2:
──────
name:                  River Thames
variantType(geometry): LineString
geometry.Point:        (0,0)
geometry.LineString:   [(-0.25,51.47),(-0.18,51.49),(-0.12,51.506),(-0.07,51.505),(0,51.51)]
geometry.Polygon:      []

Row 3:
──────
name:                  Hyde Park
variantType(geometry): Polygon
geometry.Point:        (0,0)
geometry.LineString:   []
geometry.Polygon:      [[(-0.188,51.5074),(-0.1533,51.5074),(-0.1533,51.5153),(-0.188,51.5153),(-0.188,51.5074)]]

Geometry のサブカラムにアクセスすると、その行にその型の値が入っている場合はその値が返され、そうでない場合はその型のデフォルト値 — Point では (0,0)、配列ベースの型では [] — が返されます。どの型が設定されているかを判別するには、variantType(geometry) を使用します。

GeoJSON データをテーブルに取り込むこともできます。

Querysql
CREATE TABLE london
(
    id           String,
    geometry     Geometry,
    properties   Nullable(JSON),
    name         String MATERIALIZED properties.name,
    feature_type String MATERIALIZED properties.feature_type
)
ENGINE = MergeTree
ORDER BY id;

INSERT INTO london
SELECT id, geometry, properties
FROM file('london.geojson', GeoJSON);

次に、地物タイプでクエリを実行します:

Querysql
SELECT name, feature_type, variantType(geometry) AS geo_type
FROM london
ORDER BY id;
Responseresponse
┌─name────────────┬─feature_type─┬─geo_type───┐
│ Tower of London │ landmark     │ Point      │
│ River Thames    │ river        │ LineString │
│ Hyde Park       │ park         │ Polygon    │
└─────────────────┴──────────────┴────────────┘

テーブル定義がなくても、GeoJSONデータのスキーマを推論できます。

Querysql
DESCRIBE format(GeoJSON, '{"type":"FeatureCollection","features":[]}');
Responseresponse
┌─name───────┬─type─────────────┐
│ id         │ Nullable(String) │
│ geometry   │ Geometry         │
│ properties │ Nullable(JSON)   │
└────────────┴──────────────────┘

サポートされていないジオメトリ型の処理

GeometryCollection など、一部の有効な GeoJSON ジオメトリ型は、ClickHouse の Geometry 型では表現できません。そのようなジオメトリを geometry カラムに格納する必要がある場合の動作は、input_format_geojson_unsupported_geometry_handling 設定で制御できます。設定可能な値は次のとおりです。

  • 'throw' — 例外をスローする (デフォルト)
  • 'null'geometry カラムに NULL 値を挿入し、パースを続行する

この処理が適用されるのは、geometry カラムが読み取られる場合に限られます。geometry が要求された出力カラムに含まれていない場合 (たとえば SELECT id FROM ...) 、サポートされていないジオメトリであっても形式が正しいかどうかの検証は行われますが、この処理はトリガーされません。つまり、ジオメトリ値は実体化されないため、例外はスローされず、NULL も挿入されません。

制限事項

読み取り時には固定スキーマに収まる内容しか反映されないため、一部の GeoJSON 情報は保持されません。

  • 生成されるのは idgeometryproperties のみで、その他のドキュメント構造はカラムとして公開されません。
  • 位置の 3 番目の座標 (標高) とそれ以降の座標は破棄されるため、位置は [longitude, latitude] になります。
  • bbox と外部メンバー (トップレベルの namecrs、または Feature 内の追加メンバーなど) は無視されます。
  • 数値の id はテキストとして保存されるため、文字列と数値の区別は失われます。id が存在しない場合や null の場合は NULL になります。
  • GeometryCollection は表現できません。詳しくは サポートされていないジオメトリ型の処理 を参照してください。

データの書き込み

結果セットを書き込むと、単一の GeoJSON FeatureCollection が生成され、各行が 1 つの Feature になります。

結果のカラムは、次のように各 Feature にマッピングされます。

Feature member Built from Notes
type 常に "Feature" です。
geometry the single geometry-typed column geometry 型のカラムが 1 つだけ必要です。そうでない場合、クエリは拒否されます。NULL の geometry は null として書き込まれます。
id a column named id 値が NULL の場合は省略されます。String カラムは JSON 文字列として、数値カラムは JSON 数値として書き込まれます。
properties all remaining columns properties という名前の単一カラムで、その型が object 系 (JSONMap、または名前付き Tuple) の場合は、properties キーの下にネストせず、properties オブジェクトとして直接書き込まれます。それ以外の場合は、残りの各カラムが、そのカラム名をキーとする 1 つのプロパティになります (該当するカラムがない場合は空オブジェクトになります) 。

geometry 型のカラムには、Geometry のバリアントまたは特定の geo 型を使用でき、それぞれ次の GeoJSON ジオメトリ型 に対応します。

ClickHouse type GeoJSON "type"
Point Point
MultiPoint MultiPoint
LineString LineString
MultiLineString MultiLineString
Polygon Polygon
MultiPolygon MultiPolygon
Ring Polygon (a single リング)
Geometry the active variant's type (or null)

Ring は GeoJSON の ジオメトリ型 ではありません。linear リングPolygon の構成要素であるため、Ring の値は単一リングの Polygon として書き込まれます。

上で作成した london テーブルを引き続き使用すると、通常の属性カラムをエクスポートした際に、idgeometry 以外のすべてのカラムがプロパティになります。

Querysql
SELECT id, geometry, name, feature_type
FROM london
ORDER BY id
FORMAT GeoJSON;
Responseresponse
{"type":"FeatureCollection","features":[{"type":"Feature","id":"1","geometry":{"type":"Point","coordinates":[-0.0761,51.5081]},"properties":{"name":"Tower of London","feature_type":"landmark"}},{"type":"Feature","id":"2","geometry":{"type":"LineString","coordinates":[[-0.25,51.47],[-0.18,51.49],[-0.12,51.506],[-0.07,51.505],[0,51.51]]},"properties":{"name":"River Thames","feature_type":"river"}},{"type":"Feature","id":"3","geometry":{"type":"Polygon","coordinates":[[[-0.188,51.5074],[-0.1533,51.5074],[-0.1533,51.5153],[-0.188,51.5153],[-0.188,51.5074]]]},"properties":{"name":"Hyde Park","feature_type":"park"}}]}

properties という名前の object 型カラムが 1 つだけある場合は、それが直接書き出されるため、GeoJSONファイルを読み込んでそのまま書き戻すと、元のドキュメントが再現されます (このファイルに対して推論されるカラムは idgeometryproperties です) :

Querysql
SELECT * FROM file('london.geojson', GeoJSON) FORMAT GeoJSON;
Responseresponse
{"type":"FeatureCollection","features":[{"type":"Feature","id":"1","geometry":{"type":"Point","coordinates":[-0.0761,51.5081]},"properties":{"feature_type":"landmark","name":"Tower of London","year_built":1078}},{"type":"Feature","id":"2","geometry":{"type":"LineString","coordinates":[[-0.25,51.47],[-0.18,51.49],[-0.12,51.506],[-0.07,51.505],[0,51.51]]},"properties":{"feature_type":"river","length_km":346,"name":"River Thames"}},{"type":"Feature","id":"3","geometry":{"type":"Polygon","coordinates":[[[-0.188,51.5074],[-0.1533,51.5074],[-0.1533,51.5153],[-0.188,51.5153],[-0.188,51.5074]]]},"properties":{"area_km2":1.42,"feature_type":"park","name":"Hyde Park"}}]}

数値の id カラムは、JSON の数値として記述されます (NULLNullable id は完全に省略されます) :

Querysql
SELECT 42 AS id, (-0.1276, 51.5072)::Point AS geometry FORMAT GeoJSON;
Responseresponse
{"type":"FeatureCollection","features":[{"type":"Feature","id":42,"geometry":{"type":"Point","coordinates":[-0.1276,51.5072]},"properties":{}}]}

Ring は、単一リングの Polygon として表記します:

Querysql
SELECT [(0., 0.), (10., 0.), (10., 10.), (0., 0.)]::Ring AS geometry FORMAT GeoJSON;
Responseresponse
{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,0]]]},"properties":{}}]}

ファイルへの書き込み

INTO OUTFILEを使用して、クライアント側からGeoJSONファイルに書き出します。

Querysql
SELECT id, geometry, properties
FROM london
ORDER BY id
INTO OUTFILE 'london_export.geojson'
FORMAT GeoJSON;

サーバーは、file テーブル関数を使って自らファイルに書き込めます (.geojson 拡張子によりフォーマットが自動的に自動選択されます) :

Querysql
INSERT INTO FUNCTION file('london_export.geojson', GeoJSON)
SELECT id, geometry, properties FROM london;

制限事項

出力に反映されるのは、ClickHouse に格納されている内容のみです。

  • 読み取り時に失われた情報 — 位置の標高、bbox、外部メンバー、および id の文字列と数値の区別 — は復元できません。詳しくは 読み取りの制限事項 を参照してください。
  • 座標は、Float64 の値から、往復変換可能な最短表現で書き出されます。
  • JSON カラムから直接取得した properties オブジェクトは、JSON 型の canonical なキー順で出力されるため、入力時の順序と異なる場合があります。

ジオメトリは格納されているとおりに正確に書き出され、座標順序と 巻き方向 は保持されます。デフォルトでは、書き込み時に GeoJSON shape の妥当性が検証されます (Geometry validation を参照) 。そのため、1 点しか持たない LineString や閉じていない Polygon ring など、有効な GeoJSON shape ではないジオメトリは、書き出したドキュメントを再度読み込めるように拒否されます。代わりにそのようなジオメトリをそのまま出力し、構造上は有効でも仕様には準拠しない GeoJSON を生成するには、format_geojson_validate_geometry = 0 を設定してください。右手系ルール (巻き方向) の不変条件は、いずれの場合も強制されません。また、null と空の properties オブジェクトの違いは保持されます。

ジオメトリの検証

設定 format_geojson_validate_geometry は、このフォーマットで RFC 7946 のジオメトリ形状ルールを、読み書きの両方向で適用するかどうかを制御します。既定では有効です。

有効な場合、GeoJSON の形状ルールに違反するジオメトリは拒否されます。たとえば、点が 2 つ未満の LineString (または MultiLineString 内のライン) 、点が 4 つ未満の Polygon または MultiPolygon のリング、先頭と末尾の点が異なるリング (閉じていないリング) 、あるいは空の MultiLineStringPolygonMultiPolygon です。これらのルールは、そのようなドキュメントを読み取る場合にも、そのような ClickHouse の値を書き出す場合にも同様に適用されるため、書き出したドキュメントは常に再度読み込めます。

無効な場合、これらの形状ルールはどちらの方向でも適用されません。退化したジオメトリは、そのまま読み取られ、そのまま書き出されます。これにより、有効な GeoJSON ジオメトリではない ClickHouse のジオメトリ値でも、このフォーマットを通して往復できますが、その代わりに有効な GeoJSON ではないドキュメントが生成されます。

この検証は構造面のみを対象とします。確認するのは、点の数とリングが閉じているかどうかだけです。形状の幾何学的な正しさまでは検査しないため、構造的には有効でも幾何学的には退化しているジオメトリは、どちらの方向でも受け入れられます。たとえば、面積が 0 の polygon、自己交差するリング、または holes (内側のリング) が外側のリングの外にある polygon です。同様に、polygon のリングの 右手系ルール (巻き方向) も適用されることはありません。

1 つの検査はこの設定とは無関係です。有限でない座標 (NaNInf) は、JSON の数値として表現できないため、常に拒否されます。

Navigation