アプリケーション開発ポータルサイト
ServerNote.NET
Amazon.co.jpでPC関連商品タイムセール開催中!
カテゴリー【GroongaDebianPHP
【Groongaメモ・2】データを作成し緯度経度周辺検索を行う
POSTED BY
2023-10-17

【Groongaメモ・1】Debianインストール・動作確認の続きです。

全国駅名緯度経度Groonga用ファイル作成

全国駅名の緯度経度データベースをまず作成します。

【Redisメモ・5】位置情報関数GEOADD・GEORADUSを使う

の、station_tsv_to_redis.phpを改造してgroonga入れ込み用JSONデータを吐くようにします。キー重複のエラーが出たら困るので、行番号-駅名というキーフィールドにします。
テーブル形式は _key, value, location とし、_key = 行番号-駅名、value = 駅名、location = 10進表現緯度経度(世界測地系)、テーブル名はEkiPosとします。

PHPstation_tsv_to_groonga.phpGitHub Source
<?php date_default_timezone_set('Asia/Tokyo');

$file = new SplFileObject('station20151215free.txt', 'r');
$file->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY | SplFileObject::READ_AHEAD);
$file->setCsvControl("\t");

foreach ($file as $line)
{
    $fields[] = $line;
}

$n = count($fields);
$i = 9; // fields[9]からが実データ

echo "load --table EkiPos\n";
echo "[\n";
echo "[\"_key\", \"value\", \"location\"],\n";

for( ; $i < $n; $i++ ){
    // fields[i][10]=経度,[11]=緯度,[3]=駅名,[7]=都道府県番号
    // 駅名は同一駅名があるため、行番号-駅名 という感じでキー出力する。
    // $pref_no = $fields[$i][7];
    //if(strlen($pref_no) <= 1){
    //  $pref_no = "0" . $pref_no;
    //}
    echo "[\"" . ($i - 9 + 1) . "-" . $fields[$i][3] . "\",";
    echo " \"" . $fields[$i][3] . "\",";
    echo " \"" . $fields[$i][11] . "," . $fields[$i][10] . "\"],\n";
}

echo "]\n";

上記Redis記事にあるstation20151215free.txtをカレントに用意し、phpを実行しINSERT JSONファイルを生成します。

#生成

php station_tsv_to_groonga.php > station_tsv_to_groonga.out.txt

#確認

head station_tsv_to_groonga.out.txt

load --table EkiPos
[
["_key", "value", "location"],
["1-函館", "函館", "41.773709,140.726413"],
["2-五稜郭", "五稜郭", "41.803557,140.733539"],
["3-桔梗", "桔梗", "41.846457,140.722952"],
["4-大中山", "大中山", "41.864641,140.71358"],
["5-七飯", "七飯", "41.886971,140.688556"],

tail station_tsv_to_groonga.out.txt

["10819-おもろまち", "おもろまち", "26.222701,127.698391"],
["10820-古島", "古島", "26.230919,127.703079"],
["10821-市立病院前", "市立病院前", "26.227548,127.710003"],
["10822-儀保", "儀保", "26.224663,127.719039"],
["10823-首里", "首里", "26.219191,127.725492"],
["10824-九州鉄道記念館", "九州鉄道記念館", "33.944392,130.962439"],
["10825-出光美術館", "出光美術館", "33.947792,130.965292"],
["10826-ノーフォーク広場", "ノーフォーク広場", "33.955973,130.964254"],
["10827-関門海峡めかり", "関門海峡めかり", "33.960627,130.967347"],
]

テーブル定義ファイル作成

以下のようなEkiPosテーブル作成スクリプトファイルを作成。

sourceEkiPos.grnGitHub Source
table_create --name EkiPos --flags TABLE_HASH_KEY --key_type ShortText
column_create --table EkiPos --name value --type Text
column_create --table EkiPos --name location --flags COLUMN_SCALAR --type WGS84GeoPoint

table_create --name R_EkiPos --flags TABLE_PAT_KEY --key_type WGS84GeoPoint
column_create --table R_EkiPos --name index --flags COLUMN_INDEX --type EkiPos --source location

最初の3行がメインテーブルで_key, value, locationを定義。
後の2行で範囲検索用インデックステーブルを定義しメインテーブルに紐づけ。

データベースファイル作成・データインサート

準備は整ったので、データベースを作成しテーブル定義、駅緯度経度データのインサートを行います。

データベースディレクトリの作成

一般ユーザ権限で普通に任意のディレクトリ(ここではgrn)を作成します。

mkdir /home/hogeuser/grn

データベース作成とテーブル定義入れ込み

groonga -n /home/hogeuser/grn/db < EkiPos.grn

[[0,1602934934.084508,0.001341819763183594],true]
[[0,1602934934.085888,0.001025915145874023],true]
[[0,1602934934.086941,0.00133514404296875],true]
[[0,1602934934.088305,0.001463413238525391],true]
[[0,1602934934.089791,0.002823352813720703],true]

確認

groonga /home/hogeuser/grn/db

table_list --output_pretty yes
column_list EkiPos --output_pretty yes
column_list R_EkiPos --output_pretty yes

緯度経度データファイルの入れ込み

いよいよ最初に作成した全国駅データファイル入れ込み。

groonga /home/hogeuser/grn/db < station_tsv_to_groonga.out.txt
[[0,1602935537.968298,0.1011497974395752],10827]

緯度経度範囲指定検索の実行

コマンドコンソールで実行してみる。東京駅(35.681454,139.767200)周辺10km以内にある駅を、近い順に距離(m)つきで100個出力する。RDBMSのようにOFFSET, LIMITページャー指定が使える。

groonga /home/hogeuser/grn/db

select EkiPos --filter 'geo_in_circle(location, "35.681454,139.767200", 10000)' --scorer '_score = geo_distance(location, "35.681454,139.767200")' --output_columns '_key,_score' --sortby _score --offset 0 --limit 100 --output_pretty yes

[
  [
    0,
    1602936879.14628,
    0.003387689590454102
  ],
  [
    [
      [
        538
      ],
      [
        [
          "_key",
          "ShortText"
        ],
        [
          "_score",
          "Int32"
        ]
      ],
      [
        "1501-東京",
        99
      ],
      [
        "1448-東京",
        99
      ],
      [
        "1411-東京",
        99
      ],
      [
        "1261-東京",
        99
      ],
      [
        "1572-東京",
        99
      ],
      [
        "1898-東京",
        99
      ],
      [
        "1959-東京",
        99
      ],
      [
        "2213-東京",
        99
      ],
      [
        "2012-東京",
        99
      ],
      [
        "1305-東京",
        99
      ],
      [
        "5839-東京",
        227
      ],
      [
        "5888-大手町",
        384
      ],
      [
        "5913-二重橋前",
        475
      ],
      [
        "7638-大手町",
        537
      ],
      [
        "5820-日本橋",
        573
      ],
      [
        "5889-日本橋",
        573
      ],
      [
        "5838-大手町",
        574
      ],
      [
        "5821-京橋",
        574
      ],
      [
        "5912-大手町",
        623
      ],
      [
        "5957-三越前",
        658
      ],
      [
        "5956-大手町",
        661
      ],
      [
        "5940-有楽町",
        728
      ],
      [
        "1306-有楽町",
        733
      ],
      [
        "2013-有楽町",
        733
      ],
      [
        "7622-日本橋",
        768
      ],
      [
        "7621-宝町",
        782
      ],
      [
        "5941-銀座一丁目",
        788
      ],
      [
        "5819-三越前",
        851
      ],
      [
        "7637-日比谷",
        884
      ],
      [
        "1573-新日本橋",
        969
      ],
      [
        "5873-日比谷",
        990
      ],
      [
        "5840-銀座",
        1089
      ],
      [
        "5822-銀座",
        1089
      ],
      [
        "5872-銀座",
        1089
      ],
      [
        "5914-日比谷",
        1105
      ],
      [
        "1502-神田",
        1122
      ],
      [
        "1304-神田",
        1122
      ],
      [
        "2011-神田",
        1122
      ],
      [
        "5869-八丁堀",
        1146
      ],
      [
        "5890-茅場町",
        1169
      ],
      [
        "5868-茅場町",
        1169
      ],
      [
        "1899-八丁堀",
        1213
      ],
      [
        "7620-東銀座",
        1330
      ],
      [
        "5871-東銀座",
        1330
      ],
      [
        "5942-新富町",
        1353
      ],
      [
        "5887-竹橋",
        1385
      ],
      [
        "5818-神田",
        1386
      ],
      [
        "5866-小伝馬町",
        1444
      ],
      [
        "7623-人形町",
        1462
      ],
      [
        "5867-人形町",
        1462
      ],
      [
        "5939-桜田門",
        1485
      ],
      [
        "5837-淡路町",
        1551
      ],
      [
        "7663-小川町",
        1557
      ],
      [
        "5870-築地",
        1558
      ],
      [
        "5958-水天宮前",
        1643
      ],
      [
        "7636-内幸町",
        1666
      ],
      [
        "5874-霞ケ関",
        1694
      ],
      [
        "5915-霞ケ関",
        1694
      ],
      [
        "5841-霞ケ関",
        1694
      ],
      [
        "5823-新橋",
        1744
      ],
      [
        "7664-岩本町",
        1746
      ],
      [
        "7639-神保町",
        1759
      ],
      [
        "7662-神保町",
        1827
      ],
      [
        "5955-神保町",
        1827
      ],
      [
        "7665-馬喰横山",
        1835
      ],
      [
        "7590-築地市場",
        1837
      ],
      [
        "5911-新御茶ノ水",
        1846
      ],
      [
        "1412-新橋",
        1862
      ],
      [
        "2014-新橋",
        1862
      ],
      [
        "1262-新橋",
        1862
      ],
      [
        "1307-新橋",
        1862
      ],
      [
        "7619-新橋",
        1895
      ],
      [
        "7791-新橋",
        1896
      ],
      [
        "1574-馬喰町",
        1902
      ],
      [
        "7624-東日本橋",
        1980
      ],
      [
        "1303-秋葉原",
        1982
      ],
      [
        "2010-秋葉原",
        1982
      ],
      [
        "1551-秋葉原",
        1982
      ],
      [
        "5865-秋葉原",
        1997
      ],
      [
        "5824-虎ノ門",
        1999
      ],
      [
        "1550-御茶ノ水",
        2024
      ],
      [
        "1503-御茶ノ水",
        2024
      ],
      [
        "7765-秋葉原",
        2036
      ],
      [
        "7666-浜町",
        2044
      ],
      [
        "7591-汐留",
        2056
      ],
      [
        "5954-九段下",
        2085
      ],
      [
        "7661-九段下",
        2085
      ],
      [
        "5886-九段下",
        2085
      ],
      [
        "5836-御茶ノ水",
        2145
      ],
      [
        "5916-国会議事堂前",
        2149
      ],
      [
        "5842-国会議事堂前",
        2149
      ],
      [
        "7792-汐留",
        2161
      ],
      [
        "5953-半蔵門",
        2352
      ],
      [
        "1552-浅草橋",
        2354
      ],
      [
        "7588-月島",
        2396
      ],
      [
        "5943-月島",
        2396
      ],
      [
        "5817-末広町",
        2421
      ],
      [
        "5952-永田町",
        2446
      ],
      [
        "5938-永田町",
        2446
      ],
      [
        "5975-永田町",
        2446
      ]
    ]
  ]
]

同じ駅名が連続するのは元データの路線名が違うので出てきてしまっているが、一応期待した結果は得られた。

次回は【Groongaメモ・3】C言語ライブラリを使用し緯度経度周辺検索を行うです。

※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!
ご連絡は以下アドレスまでお願いします★

☆ServerNote.NETショッピング↓
ShoppingNote / Amazon.co.jp
☆お仲間ブログ↓
一人社長の不動産業務日誌
【キーワード検索】