GeoJSON と Mapbox Vector Tile の id に関する整理

# はじめに

この記事は Mapbox Vector Tile のそれぞれの Feature に対して id を付与する場合に、どういった値であれば安全であるかを、各種仕様をもとにとりまとめたものです。

# RFC7946 The GeoJSON Format

Mapbox Vector Tile を生成する前につくるであろう、 GeoJSON です。

<https://datatracker.ietf.org/doc/html/rfc7946>

> If a Feature has a commonly used identifier, that identifier
> SHOULD be included as a member of the Feature object with the name
> "id", and the value of this member is either a JSON string or
> number.

仕様によれば、GeoJSON の Feature は id プロパティを持つことができ、値は **文字列** または **数値** とされています。

# Mapbox Vector Tile

Mabox社による、vector-tile-spec です。

<https://github.com/mapbox/vector-tile-spec/tree/master/2.1>

> A feature MAY contain an id field. If a feature has an id field, the value of the id SHOULD be unique among the features of the parent layer.

MVT の Feature は id フィールドを持つ。その値は同じレイヤーに所属する Feature の中でユニークであるべき、とされています。
この説明文だけでは値域がよくわかりませんが、同仕様では以下のような prtocol buffer が定義されています。


<https://github.com/mapbox/vector-tile-spec/blob/c8d178da65cce0ea474e3d99e3368970ce217093/2.1/vector_tile.proto#L32>

```

        message Feature {
                optional uint64 id = 1 [ default = 0 ];

                // Tags of this feature are encoded as repeated pairs of
                // integers.
                // A detailed description of tags is located in sections
                // 4.2 and 4.4 of the specification
                repeated uint32 tags = 2 [ packed = true ];

                // The type of geometry stored in this feature.
                optional GeomType type = 3 [ default = UNKNOWN ];

                // Contains a stream of commands and parameters (vertices).
                // A detailed description on geometry encoding is located in
                // section 4.3 of the specification.
                repeated uint32 geometry = 4 [ packed = true ];
        }
```

ここでは Feature の id の値は明示的に **uint64** と規定されています。
`0` から `2^64-1` の間の値であれば、 MVT 仕様的には valid ということになります。


# JavaScript における安全に扱える Integer の最大値

<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER>

JavaScript の Number として整数の値を扱う場合に、正確に扱えるような最大の値 `MAX_SAFE_INTEGER` は `2^53-1` とされています。

たとえば mapbox-gl-js や maplibre-gl-js のような JavaScript ライブラリでは、 MVT 仕様上は許容される **uint64** の範囲の整数値を正確に扱えない可能性があることに注意が必要です。



# JSON において相互運用性を損なわずに扱える整数値の範囲

<https://datatracker.ietf.org/doc/html/rfc8259>

JSON 仕様では整数値の値について、特に桁数などの上限は設定されていません。
ただし、上述のようなソフトウェアでの整数値の制限を受けて、以下のような相互運用性に関するノートが付与されています。

> Note that when such software is used, numbers that are integers and
   are in the range [-(2**53)+1, (2**53)-1] are interoperable in the
   sense that implementations will agree exactly on their numeric
   values.

相互運用性のために安全な整数の範囲は `-2^53+1` から `2^53-1` の間となっています。

# まとめ

以上の情報を整理すると

- GeoJSON の Feature id は文字列または数字
- Mapbox Vector Tile の Feature id は `0` から `2^64-1` (uint64)
- JavaScript で安全に扱える整数値は  `-2^53+1` から `2^53-1` の間
- 相互運用性を考慮する場合、JSON の整数値は `-2^53+1` から `2^53-1` だと安全

mapbox-gl-js や maplibre-gl-js のような JavaScript ベースの処理系で扱うことを考えた場合、
Mapbox Vector Tile の Feature id は `0` から `2^53-1` の間であれば安全と考えられます。

なお `2^53-1 = 9,007,199,254,740,991` なので、目安としては **15桁以内の数字でできた ID** であれば Mapbox Vector Tile の Feature id として採用できそうです。