CodeIgniterの学習 29 - 住所←→郵便番号 の相互検索機能ヘルパを作る(その1 元データの準備)

今日から数回にわたって、

  • 住所の一部を入れて郵便番号を検索する機能
  • 郵便番号の一部を入れて住所を検索する機能

を作ることにする。

理由、目的

CodeIgniterのヘルパとして、上記のアシスト機能が欲しくなったから。

テキストエリアに郵便番号or住所の一部を入力すると、xajax経由で住所or郵便番号が返ってくる機能がいいな。
ついでにxajaxを利用しないでも使えるヘルパにしたいな。


データの準備

郵便番号データは、日本郵便からダウンロード出来る。
http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh

列定義はhttp://www.post.japanpost.jp/zipcode/dl/readme.html


CodeIgniter側でデータ取り込み機能を作ってみたがやめた

出来ればphpだけで何とかしたかったので、
CodeIgniterのライブラリを作って、実際取り込むところまでは適当ながらも作ってみた。

でもループでDBにインサートしてると非常に時間が掛かるので、10分くらいたったところでPHP取り込み方式は中止した。
(10分で3万件位だった。総件数は122561件)


あと、lzhで圧縮されているんでlzhの解凍のところで、
system('lha -eq …');を呼ばざるをえなかったり、
CSVが、半角カナ入りのShift-JISファイルなんで、全角カナに変換しなくてはならなかったりして、
なんかもうPHPでやるのがあほらしくなったので、投げやりなシェルスクリプトで取り込むことにした。

(ウチの環境は専用環境なので、何を使うのも自由だから特に問題はないが、レンサバだとそうはいかないよね。)


シェルスクリプトで取り込む方式

結論からすると、元データがcsv形式なので、LOAD DATA INFILE … を使った方が断然速かった。
(大体30秒以内に終わる。)

mysql側でLOAD DATA INFILEを使える権限 + nkf + wget + sed +awk の環境が必要だが一応貼っておく。(Fedora8環境)

#!/bin/sh
#DB(mysql)関連、FILEを読み書き出来る権限が必要
DB_NAME="DB名"
DB_USER="-uユーザ名"
DB_PASS="-pパスワード"

#ファイル名
LZH_FILE_NAME=ken_all.lzh
CSV_FILE_NAME=ken_all.csv

#作業ディレクトリを作る
DIR_NAME=`mktemp -d`
echo $DIR_NAME
chmod 755 $DIR_NAME

#lzhファイルを取得
cd $DIR_NAME
wget -q http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh

#カレントディレクトリに解凍
lha -eqw=./ $LZH_FILE_NAME

#nkfでutf8-LFに変換 同時に半角カナは全角カナに変換してくれる
#その後CSVの中身をLOAD DATA INFILE出来る形に整形
nkf --utf8 -Lu $CSV_FILE_NAME \
|sed -e 's/"\([0-9]*\)\s*"/\1/g' -e 's/"//g' \
|awk '{printf "%d,%s\n",NR,$0}' > tmp.csv

#zipコードテーブルをトランケート後、CSVを読み込ませる
echo "TRUNCATE TABLE zipcode ;LOAD DATA INFILE '$DIR_NAME/tmp.csv' INTO TABLE zipcode FIELDS TERMINATED BY ',';" \
|mysql $DB_USER $DB_PASS $DB_NAME

#ゴミの片付け
#cd ../
#rm -rf $DIR_NAME;


郵便番号テーブル(zipcode)のddl

CSVエンコードはShift-JIS,CR+LFだが、
格納テーブルはエンコードUTF-8,半角カタカナは全角カタカナに変換

CREATE TABLE zipcode (
id INTEGER(10) UNSIGNED NOT NULL auto_increment,
code VARCHAR(6) NOT NULL,          #  1. 全国地方公共団体コード(JIS X0401、X0402)……… 半角数字
old_zipcode VARCHAR(5) NOT NULL,   #  2. (旧)郵便番号(5桁)…… 半角数字、空白トリム
zipcode VARCHAR(7) NOT NULL,       #  3. 郵便番号(7桁)………… 半角数字
kana_pref VARCHAR(64) NOT NULL,    #  4. 都道府県名 ………… 全角カタカナ(コード順に掲載)
kana_city VARCHAR(127) NOT NULL,   #  5. 市区町村名 ………… 全角カタカナ(コード順に掲載)
kana_street VARCHAR(127) NOT NULL, #  6. 町域名 ……………… 全角カタカナ(五十音順に掲載)
pref VARCHAR(64) NOT NULL,         #  7. 都道府県名 ………… 漢字(コード順に掲載)
city VARCHAR(127) NOT NULL,        #  8. 市区町村名 ………… 漢字(コード順に掲載)
street VARCHAR(127) NOT NULL,      #  9. 町域名 ……………… 漢字(五十音順に掲載)
f1 INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,   # 10. 一町域が二以上の郵便番号で表される場合の表示 (「1」は該当、「0」は該当せず)
f2 INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,   # 11. 小字毎に番地が起番されている町域の表示(「1」は該当、「0」は該当せず)
f3 INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,   # 12. 丁目を有する町域の場合の表示 (「1」は該当、「0」は該当せず)
f4 INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,   # 13. 一つの郵便番号で二以上の町域を表す場合の表示(「1」は該当、「0」は該当せず)
f5 INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,   # 14. 更新の表示(「0」は変更なし、「1」は変更あり、「2」廃止(廃止データのみ使用))
f6 INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,   # 15. 変更理由 (「0」は変更なし、「1」市政・区政・町政・分区・政令指定都市施行、「2」住居表示の実施、「3」区画整理、「4」郵便区調整等、「5」訂正、「6」廃止(廃止データのみ使用))
del_flg INTEGER(1) UNSIGNED NOT NULL DEFAULT 0,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
modified TIMESTAMP NULL ,
PRIMARY KEY(id)
);

CREATE INDEX idx1_zipcode on zipcode (zipcode,del_flg);
CREATE INDEX idx2_zipcode on zipcode (pref,del_flg);
CREATE INDEX idx3_zipcode on zipcode (pref,city,del_flg);
CREATE INDEX idx4_zipcode on zipcode (pref,city,street,del_flg);
CREATE INDEX idx5_zipcode on zipcode (city,del_flg);
CREATE INDEX idx6_zipcode on zipcode (city,street,del_flg);
CREATE INDEX idx7_zipcode on zipcode (street,del_flg);
CREATE INDEX idx8_zipcode on zipcode (f6,del_flg);
CREATE INDEX idx9_zipcode on zipcode (old_zipcode,del_flg);

長さは適当、容量食っても気にしない。


中身

こんな感じ



今日はここまで。次はこいつを簡単に呼び出して検索出来るようなヘルパとライブラリを作る。

PHPでの取り込みロジックは気が向いたら貼るかも。ださいけど。