> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> GeoJSONのFeatureCollectionドキュメントに対応する入力および出力フォーマットです。入力時は各地物ごとにid、geometry、propertiesの各カラムを持つ1行を生成し、出力時は各行ごとに1つの地物を生成します。

# GeoJSON

| 入力 | 出力 | エイリアス |
| -- | -- | ----- |
| ✔  | ✔  |       |

<div id="description">
  ## 説明
</div>

[GeoJSON](https://geojson.org/) データは、単一の [`FeatureCollection`](https://datatracker.ietf.org/doc/html/rfc7946#section-3.3) ドキュメントとしてやり取りされ、ClickHouse ではこれを 3 つのカラム — `id`、`geometry`、`properties` — に対応付けます。各 `Feature` につき 1 組です。ドキュメントを[読み込む](#reading-data)と、`Feature` ごとに 1 行が生成されます。[書き込む](#writing-data)と、1 行ごとに 1 つの `Feature` が生成されます。

<div id="reading-data">
  ## データの読み取り
</div>

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

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

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

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

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

スキーマ推論では上記の固定スキーマが返されるため、`DESCRIBE` や `SELECT ... FROM format(...)` は table definition なしで動作します。

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

```json theme={null}
{
    "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}
        }
    ]
}
```

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

```sql title="Query" theme={null}
SELECT id, properties.name AS name, variantType(geometry) AS geo_type
FROM file('london.geojson', GeoJSON);
```

```response title="Response" theme={null}
┌─id─┬─name────────────┬─geo_type───┐
│ 1  │ Tower of London │ Point      │
│ 2  │ River Thames    │ LineString │
│ 3  │ Hyde Park       │ Polygon    │
└────┴─────────────────┴────────────┘
```

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

```sql title="Query" theme={null}
SELECT id, properties.name AS name, variantType(geometry) AS geo_type
FROM file('london.geojson');
```

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

```sql title="Query" theme={null}
SELECT properties.name AS name, geometry, variantType(geometry)
FROM file('london.geojson', GeoJSON);
```

```response title="Response" theme={null}
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
```

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

```sql title="Query" theme={null}
SELECT properties.name AS name, variantType(geometry), geometry.Point, geometry.LineString, geometry.Polygon
FROM file('london.geojson', GeoJSON);
```

```response title="Response" theme={null}
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 データをテーブルに取り込むこともできます。

```sql title="Query" theme={null}
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);
```

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

```sql title="Query" theme={null}
SELECT name, feature_type, variantType(geometry) AS geo_type
FROM london
ORDER BY id;
```

```response title="Response" theme={null}
┌─name────────────┬─feature_type─┬─geo_type───┐
│ Tower of London │ landmark     │ Point      │
│ River Thames    │ river        │ LineString │
│ Hyde Park       │ park         │ Polygon    │
└─────────────────┴──────────────┴────────────┘
```

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

```sql title="Query" theme={null}
DESCRIBE format(GeoJSON, '{"type":"FeatureCollection","features":[]}');
```

```response title="Response" theme={null}
┌─name───────┬─type─────────────┐
│ id         │ Nullable(String) │
│ geometry   │ Geometry         │
│ properties │ Nullable(JSON)   │
└────────────┴──────────────────┘
```

<div id="unsupported-geometry">
  ### サポートされていないジオメトリ型の処理
</div>

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

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

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

<div id="reading-limitations">
  ### 制限事項
</div>

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

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

<div id="writing-data">
  ## データの書き込み
</div>

結果セットを書き込むと、単一の GeoJSON [`FeatureCollection`](https://datatracker.ietf.org/doc/html/rfc7946#section-3.3) が生成され、各行が 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 系 (`JSON`、`Map`、または名前付き `Tuple`) の場合は、`properties` キーの下にネストせず、`properties` オブジェクトとして直接書き込まれます。それ以外の場合は、残りの各カラムが、そのカラム名をキーとする 1 つのプロパティになります (該当するカラムがない場合は空オブジェクトになります) 。 |

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

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

`Ring` は GeoJSON の ジオメトリ型 ではありません。[linear リング](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6) は `Polygon` の構成要素であるため、`Ring` の値は単一リングの `Polygon` として書き込まれます。

<div id="writing-examples">
  ### 例
</div>

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

```sql title="Query" theme={null}
SELECT id, geometry, name, feature_type
FROM london
ORDER BY id
FORMAT GeoJSON;
```

```response title="Response" theme={null}
{"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ファイルを読み込んでそのまま書き戻すと、元のドキュメントが再現されます (このファイルに対して推論されるカラムは `id`、`geometry`、`properties` です) :

```sql title="Query" theme={null}
SELECT * FROM file('london.geojson', GeoJSON) FORMAT GeoJSON;
```

```response title="Response" theme={null}
{"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 の数値として記述されます (`NULL` の `Nullable` `id` は完全に省略されます) :

```sql title="Query" theme={null}
SELECT 42 AS id, (-0.1276, 51.5072)::Point AS geometry FORMAT GeoJSON;
```

```response title="Response" theme={null}
{"type":"FeatureCollection","features":[{"type":"Feature","id":42,"geometry":{"type":"Point","coordinates":[-0.1276,51.5072]},"properties":{}}]}
```

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

```sql title="Query" theme={null}
SELECT [(0., 0.), (10., 0.), (10., 10.), (0., 0.)]::Ring AS geometry FORMAT GeoJSON;
```

```response title="Response" theme={null}
{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,0]]]},"properties":{}}]}
```

<div id="writing-to-a-file">
  ### ファイルへの書き込み
</div>

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

```sql title="Query" theme={null}
SELECT id, geometry, properties
FROM london
ORDER BY id
INTO OUTFILE 'london_export.geojson'
FORMAT GeoJSON;
```

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

```sql title="Query" theme={null}
INSERT INTO FUNCTION file('london_export.geojson', GeoJSON)
SELECT id, geometry, properties FROM london;
```

<div id="reading-limitations">
  ### 制限事項
</div>

<Note>
  ClickHouse の geo types には座標参照系の情報がないため、出力では座標がすでに WGS84 の経度/緯度で、[RFC 7946](https://datatracker.ietf.org/doc/html/rfc7946#section-4) で規定されている `[longitude, latitude]` の順序になっているものと見なされます。再投影や軸の入れ替えは行われないため、投影座標や `(latitude, longitude)` として格納されたデータは、構造上は有効でも仕様には準拠しない GeoJSON になります。
</Note>

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

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

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

<div id="geometry-validation">
  ## ジオメトリの検証
</div>

設定 `format_geojson_validate_geometry` は、このフォーマットで [RFC 7946](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1) のジオメトリ形状ルールを、読み書きの両方向で適用するかどうかを制御します。既定では有効です。

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

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

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

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