住所クレンジング（住所正規化）用データベースの検討

# 記事作成の背景
* 住所の正規化に取り組む中で思ったことの備忘録を作成したい
* データベース設計の勉強中のため、設計の練習をしたい

# 住所クレンジング（住所正規化）とは
　ひとつづきののアドレス文字列を県／市／（通り名／）大字・町／小字・丁目に分割することを「住所クレンジング」「住所正規化」などと呼びます。日本の住所の正規化は非常に困難であり、多くの先人たちが挑戦し、頭を抱えてきた歴史があります。そして今もなおその挑戦は続いています。

正規化の例を示します。
* 例１）「東京都千代田区永田町１丁目７番地１」（国会議事堂の所在地）の場合
東京都／千代田区／　／千代田／１丁目／７番地１
* 例２）「京都府京都市中京区寺町通御池上る上本能寺前町４８８番地」（京都市役所の所在地）の場合
京都府／京都市中京区／寺町通御池上る／上本能寺前町／４８８番地

時には表記のゆらぎを検出し、同定しなければならないときもあります。
例えば、「埼玉県越谷市越ヶ谷」の場合、
* 埼玉県越谷市越ヶ谷
* 埼玉県越谷市越谷
* 埼玉県越ヶ谷市越ヶ谷
* 埼玉県越ヶ谷市越谷
など、さまざまな表記のゆらぎが想定されます。

# 方針
* 地名辞書を用いて住所を正規化する
* アドレスの妥当性検査（「神奈川県名古屋市」などのでたらめなデータをエラーとする）をできるようにする
* 市町村コード付番（1970年以降）前に廃止となったアドレスは、いったん対象外とする。
* ~~郵便番号は管理しない~~　2023/11/26修正　郵便番号管理にも対応しました。

# 地名に関するマスターデータの現状（2023年11月時点）
代表的なものとして、次の３つが存在します。
<table>
  <thead>
    <tr>
      <th>名前</th>
      <th>公開元</th>
      <th>有償・無償</th>
      <th>通り名・通称</th>
      <th>廃止地名</th>
      <th>備考</th>
    </tr>
  </thead>
  <tr>
    <td>全国町・字ファイル</td>
    <td><a href="https://www.j-lis.go.jp/ipd/machiaza/cms_11034.html">地方公共団体情報システム機構</a></td>
    <td>有償</td>
    <td>○</td>
    <td>△</td>
    <td>1982年3月以降の地名しか収録されていない。
    <br>名称変更履歴が収録されていない。
    <br>2回以上の廃置分合を「町・字コード」と「新町・字コード」の2列で表現できない。</td>
  </tr>
  <tr>
    <td>全国町・字ファイル</td>
    <td><a href="https://www.kokudo.or.jp/master/001.html">公益財団法人国土地理協会</a></td>
    <td>有償</td>
    <td>○</td>
    <td>△</td>
    <td>基本的には地方公共団体情報システム機構のものと同じと思われる。<br>
    旧郵便番号（5桁）が収録されている。<br>
    オプションで番地データファイルがある。</td>
  </tr>
  <tr>
    <td>日本 町字マスター データセット</td>
    <td><a href="https://catalog.registries.digital.go.jp/rc/dataset/ba-o1-000000_g2-000003">デジタル庁</a></td>
    <td><b>無償</b><br>
    <td>×</td>
    <td>×</td>
    <td>2022年4月から試験運用中</td>
  </tr>
</table>

また、地名を管理する目的のものではありませんが、日本郵便が公開している[「住所の郵便番号（1レコード1行、UTF-8形式）（CSV形式）」](https://www.post.japanpost.jp/zipcode/download.html)というものもあります（郵便番号のマスターデータ）。

# 課題
　これらのマスターデータは、**名称履歴、廃置分合履歴を管理していません**。そのため、これらを使用して名称変更前の地名や市町村合併前の地名を正規化することは難しいです。
　この課題を解消しつつ、表記のゆらぎも同定できるようなテーブルを検討してみました。

# 全体像
検討したテーブルとその関係を一つの図にまとめると、次のようになります。

ER図(IE記法)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626423/6b6094c6-2211-a628-2d59-d1a22b1da945.png)

※団体コードは次のサイトをベースにして検討しています。
　[総務省「全国地方公共団体コード」](https://www.soumu.go.jp/denshijiti/code.html)

以下、検討した上でのポイントを記述します。

# ポイント1　都道府県・郡・区・市町村を共通のテーブルで管理
※このポイントは、「地方公共団体」テーブルに関する説明です。

「上位団体コード」にはそれぞれ次の値を設定します。
<table>
  <thead>
    <tr>
      <th>団体の種類</th><th>上位団体コード</th>
    </tr>
  </thead>
  <tr>
    <td>都道府県</td><td>Null</td>
  </tr>
  <tr>
    <td>郡、特別区、政令市以外の市</td><td>都道府県の団体コード</td>
  </tr>
  <tr>
    <td>町村</td><td>郡の団体コード</td>
  </tr>
  <tr>
    <td>行政区</td><td>政令市の団体コード</td>
  </tr>
</table>

# ポイント2　大字・町・小字・丁目を共通のテーブルで管理
※このポイントは、「町字」テーブルに関する説明です。

　市区町村名の直後にビル名等を記載するタイプのアドレスもあるため、ビル等も管理できるようにします。また、「上位町字コード」にはそれぞれ次の値を設定します。
 （ビル等も含まれるので厳密には「町字」ではないのですが、「市区町村名に続くアドレスを指す文字列」を端的に表す言葉が分からなかったので、総称して「町字」としてしまいました。）
<table>
  <thead>
    <tr>
      <th>町字の種類</th><th>上位町字コード</th>
    </tr>
  </thead>
  <tr>
    <td>大字・町</td><td>Null</td>
  </tr>
  <tr>
    <td>小字・丁目</td><td>大字・町の町字コード</td>
  </tr>
  <tr>
    <td>ビル等</td><td>大字・町または小字・丁目の町字コード</td>
  </tr>
</table>

# ポイント3　地方公共団体と町字でテーブルを分ける
※このポイントは、「地方公共団体」テーブル、「町字」テーブルに関する説明です。
 
　全国町・字ファイルや町字マスターは、市区町村内で一意に定まるIDを町字に付番しています。しかしこの運用では、市町村合併が起きたときに合併後の市区町村用にIDを再付番しなければなりません。同じ町字であれば再付番しないで済むよう、団体コードに依存しない番号「町字コード」を付番します。
 　町字コードは地方公共団体の団体コードとコード体系も桁数も異なる想定のため、別テーブルで管理することにしました。
　  なお、同字異音の町名（愛知県大府市北崎町（きたさきまち・きたさきちょう）など）や同形同音の異なる町域（京都府京都市中京区亀屋町（5つある）など）はそれぞれ別の町字コードとして扱う想定です。

# ポイント4　名称履歴管理への対応
※このポイントは、「地方公共団体名」テーブル、「町字名」テーブルに関する説明です。

　地方公共団体（都道府県、市区郡町村）は「団体コード」と「有効期間開始日」が決まれば名称が一意に定まります。また、町字（市区町村の後に続く地名）は「町字コード」と「有効期間開始日」が決まれば名称が一意に定まります。
　そのため、「地方公共団体名」テーブルの主キーは「団体コード」「有効期間開始日」に、「町字名」テーブルの主キーは「町字コード」「有効期間開始日」にしました。

# ポイント5　表記ゆれへの対応
※このポイントは、「地方公共団体名」テーブル、「町字名」テーブル、「通り名辞書」テーブルに関する説明です。

　複数の表記ゆれパターンをすべてテーブルに登録するため、地名そのものも主キーにしました。
　先述の例でいうと、同じ町字コードで「越谷」と「越ヶ谷」のデータを登録できるようにするイメージです。
　ただし、市区町村名の直後に地番が続くアドレスの場合、地名がNullになってしまうため登録することができません。そのようなケースは「町字名」テーブルには登録せず、「町字」テーブルのみ登録し、「町字名Nullフラグ」にTrueを設定します。
　また、名称が正式名称の場合は「正式名称フラグ」にTrueを、表記ゆれの場合はFalseを設定します。

# ポイント6　廃置分合履歴管理への対応
※このポイントは、「町字・市区郡町村対応」テーブルに関する説明です。

　「町字コード」と「有効期間開始日」（廃置分合等の施行年月日）が決まれば、町・字がどの市区町村に属するかが一意に定まります。そのため、「町字コード」と「有効期間開始日」を主キーにしました。

# ポイント7　通り名への対応
※このポイントは、「通り名」テーブル、「通り名辞書」テーブル、「町字・通り名対応」テーブルに関する説明です。

　京都市の一部の町・字は、町・字名の前に「通り名」がついています。アドレス文字列のどこまでが通り名で、どこからが町・字名なのかを判断するために、通り名に関するテーブルを定義しました。
　通り名と町字は多対多の関係にあるので、「町字」テーブルの「町字コード」と「上位町字コード」のみでは表現できないと判断し、別テーブルにしました。
　また、「市区郡町村」テーブルと「通り名」テーブルの間に関連エンティティを作ることも検討しましたが、「町・字市区町村対応」テーブルと「町・字通り名対応」テーブルがあれば十分と判断し、作成しませんでした。

# ポイント8　郵便番号管理対応
　町字と郵便番号は多対多の関係にあります。そのため、「町字郵便番号」テーブルは町字コードと郵便番号をキーにしました。さらに、郵便番号は変更されることがあるため、有効期間開始日も主キーとしました。

# 懸念事項
* 表記ゆれのテーブル登録で気をつけないといけないことが多い
  * 越谷市内の町字に「越ヶ谷」と「越谷」が存在していたら？
  * 「２丁目」の表記ゆれとして「２－」を登録したら、舞浜２－（番地）を舞浜２－（丁目）と誤認する
* 結局、プログラムの実装側でも頑張らないといけないことには変わりない

# 設計してみた感想、思ったことなど
* 履歴管理できるようになっても、そもそも履歴データがない
* J-LISやデジタル庁は、どのようにデータを管理しているのだろう
* 住所クレンジングは難しい