on-ze.comにて openweathermap.org のリストが紹介されていたが、本家はリンク切れ。本家を探すとjsonデータなどは出てくる。
simplemaps.comは有償が150万都市だが、無償版の12000都市では名古屋の隣が浜松、津といった具合。対するopenweathermapは74000都市で、名古屋の隣は春日井、小牧、瀬戸、知立、大府といった具合。(simplemaps.comは無償版もバックリンク等を紹介しろという条件。)
ウィキペディアから抜き出すという方法もあるが意外と形式が様々で割と難航するという記事が。(kesin.hatenablog.com)
ウィキペディア等ユーザー提出による場合は重複や重要性による取捨も検討しておかないと無駄にデータベースが巨大化しそう。わけのわからない字名だされるより疎なデータベースでTokyoとだけ出るほうがわかりやすい場合もある。用途による。
データベースのデータも完全に綺麗ではない。
headしてみたら出だしからFirozpur Jhirka。
819827 Razvilka 55.591667 37.740833 RU 524901 Moscow 55.752220 37.615555 RU 1271881 Firozpur Jhirka 27.799999 76.949997 IN 1283240 Kathmandu 27.716667 85.316666 NP 703448 Kiev 50.433334 30.516666 UA 1282898 Pokhara 28.233334 83.983330 NP 3632308 Merida 8.598333 -71.144997 VE 1273294 Delhi 28.666668 77.216667 IN 502069 Reshetnikovo 56.450001 36.566666 RU
とりあえず
head city_list.txt|awk '{printf $(NF-1)"; "$(NF-2)"; "$NF";";$1="";$(NF-2)="";$(NF-1)="";$NF="" ;print $0}'|awk -F"; " '{printf ("%4.2f",$1);printf ";";printf ("%4.2f",$2);printf ";";printf $3";"$4"\n"}'|sed 's| $||g'
として
37.74;55.59;RU;Razvilka 37.62;55.75;RU;Moscow 76.95;27.80;IN;Firozpur Jhirka 85.32;27.72;NP;Kathmandu 30.52;50.43;UA;Kiev 83.98;28.23;NP;Pokhara -71.14;8.60;VE;Merida 77.22;28.67;IN;Delhi 36.57;56.45;RU;Reshetnikovo
一度111kmなので小数点以下ふた桁でkm,三桁とると100mスケールになってくるので、無駄なデータは捨てとく。(この処理で3.1MBが1.9MBになった。)
あとは
sort -hk1
で経度順にでも並べておいたりする。
だいたい、コンマは地名にありふれているので絶対使えない。
grep ",*," city_list.txt 1690086 Poblacion, San Felipe 15.062220 120.070000 PH 2516372 Xeraco,Jaraco 39.033329 -0.216670 ES 6292397 Rueti / Dorfzentrum, Suedl. Teil 47.253681 8.856540 CH 6615444 Oliver-Valdefierro, Oliver, Valdefierro 41.644539 -0.933490 ES 4140963 Washington, D. C. 38.895111 -77.036369 US 7874740 Villa Presidente Frei, Nunoa, Santiago, Chile -33.460690 -70.580238 CL 2949482 Beverstedt, Flecken 53.434132 8.819150 DE
grep ";JP;"|wc -l
とすると日本国内は丁度770都市ですね。
同様に調べると、KR 120,KP 74,CN 1020,TW 20、となっているので、日本国内は面積の割にかなり密にデータがある印象。他の国ではかなり雑なデータという印象を与える可能性も。
cat city_list.txt|awk '{printf $(NF-1)"; "$(NF-2)"; "$NF";";$1="";$(NF-2)="";$(NF-1)="";$NF="" ;print $0}'|awk -F"; " '{printf ("%4.2f",$1);printf ";";printf ("%4.2f",$2);printf ";";printf $3";"$4"\n"}'|sed 's| $||g'|sort -hk1 > tmp
ターミナルからデータベースを指定して開始。
sqlite3 /home/username/city.db
.show
と打ってセパレーターなど確認。
先ほどセパレーターは;セミコロンにしたから、
.separator ;
としてセパレーターを切り替えておく。
CREATE TABLE IF NOT EXISTS city(`LNG`, `LAT`, `COUNTRY`, `CITY`);
四項目のテーブルcityをつくる。行末は必ずコロン。
で、
.import "tmp" city
とすると、先ほどの/home/username/city.dbが2.5MBに膨らみました。
.import .quit のような命令は行末セミコロンが不要ですが行頭ピリオドが必須。
各列、データの型を指定できるので、数値をテキストではないと明言すればデータサイズは減らせるはずですが、
CREATE TABLE IF NOT EXISTS city(`LNG` NUMERIC, `LAT` NUMERIC, `COUNTRY` TEXT, `CITY` TEXT);
とすると逆に2.9MBに膨らんでしまいました。
sqliteのデータベースはcatしても平文で投げ込まれてるだけなので、なんか芸がないなという感じです。
ここで
select abs(lat-35)+abs(lng-137),city FROM city ORDER by abs(lat-35)+abs(lng-137) asc limit 1;
とすれば簡易的に最も近い地名を得られますね。極めて雑な計算ですが。
select abs(lat-35)+abs(lng-137),city FROM (select * from city where lng like '13%') ORDER by abs(lat-35)+abs(lng-137) asc limit 1;
とすれば計算が減って早くなる。
2018-12-18