[jq] GPS情報データベースから、現在地(指定地点)から半径100キロ以内のデータを取得する方法

2020年3月18日

jq テクノロジー プログラミング

ユゲタです。 「GPS」とかけまして、 「流行のウィルス」とときます。 そのココロは・・・ エイセイ(衛生と衛星)管理が重要です。

GPS検索は、リアル連携サービスの基本作法

なんちゃらGO!系のゲームアプリを始めとして、スマートフォンで誰もがGPSの恩恵を受けて、おもろいゲームや、便利なサービスを受けられる時代になりました。 いまさらGPSがなんじゃろ?という人は、今回の記事はお控えください。 全国の薬局の一覧データを厚労省のサイトから取得できることが分かったのですが、 その一覧データには、郵便番号と住所と電話番号しか情報が無かったため、GPS値を付ける処理をつなげて、かなり利用頻度の高いいい感じのリストデータを作ることに成功しました。 そして、それを自分のスマートフォンで見た時に、近くの薬局を検索するモードを付ける機能を作っているんですが、 利便性を考えて、jsonデータで保存しているデータを、jqコマンドで、一定距離以内のデータのみ取得して、ついでにそれを距離数でソートして、近い順リストを作ろうと考えました。 思いの外、簡単にできたので、そのソースコードを惜しまず掲載したいと思います。 ※一覧リストデータは、お手持ちのGPSデータをお使いください。

データとソース

{"lat":35.168599,"lon":136.938189,"address":"〒464-0850名古屋市千種区今池5-2-3共栄ビル1階","medicalId":"010,058,1や千種58","pref":"aichi"} {"lat":35.166803,"lon":136.946011,"address":"〒464-0848名古屋市千種区春岡1-5-6池下ヤママンビル1階","medicalId":"010,084,7や千種84","pref":"aichi"} {"lat":35.166370,"lon":136.962207,"address":"〒464-0037名古屋市千種区楠元町2-33","medicalId":"010,110,0や千種110","pref":"aichi"} {"lat":39.708790,"lon":140.119910,"address":"〒010-0011秋田市南通亀の町14-20","medicalId":"01・4015・9","pref":"akita"} {"lat":40.819890,"lon":140.747278,"address":"〒030-0822青森市中央二丁目13-14","medicalId":"01-4029-3青薬29","pref":"aomori"} {"lat":35.581225,"lon":140.127128,"address":"〒260-0834千葉市中央区今井1-20-9","medicalId":"01-0086-7","pref":"chiba"} {"lat":33.836017,"lon":132.769322,"address":"〒790-0012松山市湊町三丁目7の5番地","medicalId":"01-4018-4","pref":"ehime"} {"lat":36.061672,"lon":136.220448,"address":"〒910-0006福井市中央1-9-30","medicalId":"01-40055","pref":"fukui"} {"lat":33.602265,"lon":130.414716,"address":"〒812-0044福岡県福岡市博多区千代1丁目17-1","medicalId":"034,001,2","pref":"fukuoka"} {"lat":37.830996,"lon":140.453785,"address":"〒960-0201福島市飯坂町十綱町7","medicalId":"0140272","pref":"fukushima"} {"lat":35.445873,"lon":136.774539,"address":"〒502-0817岐阜市長良福光2667","medicalId":"01,0004,7岐薬4","pref":"gifu"} {"lat":36.391233,"lon":139.075371,"address":"〒371-0016前橋市城東町4-3-1","medicalId":"01,0011,5前薬11","pref":"gunma"} {"lat":34.392842,"lon":132.459442,"address":"〒730-0035広島市中区本通8-29","medicalId":"01,4056,8","pref":"hiroshima"} 上記のように、latとlonというkeyに緯度(lat)経度(lon)情報をそれぞれ格納してあります。 ※全国データが膨大なので、一部抜粋にしています。 これを、jqで以下のようにすることで、半径100キロメートル以内のデータのみを取得することができます。 $ jq --slurp --raw-output '[.[] | {distance : ( (((.lat | tonumber - %現在地の緯度 | pow(.;2) | tonumber) + (.lon | tonumber - %現在地の経度 | pow(.;2) | tonumber))) | sqrt *100) | select(. <= 100) , address:.address} ] | sort_by(.distance)' lists.json

解説

jqコマンドの中身を順を追って解説します。 まず、latとlonの値から、現在値の緯度経度をそれぞれ差分を求めます。 次に、それをそれぞれ2乗して、足します。 ※2乗は、pow(.;2)です。 その値を平方根処理(sqrt)して100を掛けることで、距離が出力されます。 さらに、その計算後の値をselectで100(km)以下の条件をつけて、sort_byでdistanceにセットすると、完了です。 ちなみに、このデータは、厳密な100kmでの判定ではなく、GPS値の1°を大体100kmとして計算するようにしています。 注意点としては、100mぐらいの誤差が出てしまいますが、もっと厳密にしたい方は、内部の計算式を厳密パターンを作ってみてください。 全国で5万件オーバーぐらいの調剤薬局のリストですが、jqコマンドが意外と早い事にビックリすることでしょう。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。