【Groongaメモ・3】C言語ライブラリを使用し緯度経度周辺検索を行う
POSTED BY
2024-10-17
2024-10-17
【Groongaメモ・2】データを作成し緯度経度周辺検索を行うの続きです。
前回の、東京駅(35.681454,139.767200)周辺10km以内にある駅を、近い順に距離(m)つきで100個出力する、というのをC言語APIを使用し実現します。コマンドコンソールでは以下のようなSQLでした。
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
C言語APIについては以下にリファレンスがあるのですが
https://groonga.org/ja/docs/reference/api.html
これがすこぶるわかりづらい。。まずはライブラリのインストールが済んでいる必要があります。
sudo apt install libgroonga-dev
ヘッダファイルが/usr/include/groongaに入りますので、g++コンパイル時 -I/usr/include/groongaとします。
以下、上記を実現するサンプルソースです。
C/C++ | groonga_test.c | GitHub Source |
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <time.h> #include <sys/time.h> #include <groonga.h> double getMicroTime(void) { struct timeval tv; gettimeofday(&tv, NULL); return (((double)tv.tv_sec)*((double)1000000)+((double)tv.tv_usec)); } //grn_obj* getSelectParam(grn_ctx *ctx, grn_obj *obj, int index, const char *value) { grn_obj* getSelectParam(grn_ctx *ctx, grn_obj *obj, const char *name, const char *value) { // grn_obj *ret = grn_expr_get_var_by_offset(ctx, obj, index); grn_obj *ret = grn_expr_get_var(ctx, obj, name, strlen(name)); grn_obj_reinit(ctx, ret, GRN_DB_TEXT, 0); GRN_TEXT_PUTS(ctx, ret, value); return ret; } int main (int argc, char **argv) { grn_ctx ctx; grn_obj *db; grn_ctx_info info; const char *path = "/home/hogeuser/grn/db"; double mt1,mt2; mt1 = getMicroTime(); grn_init(); grn_ctx_init(&ctx, 0); GRN_DB_OPEN_OR_CREATE(&ctx, path, NULL, db); grn_ctx_set_output_type(&ctx, GRN_CONTENT_JSON); mt2 = getMicroTime(); printf("initialize library (%lfms)\n",(mt2 - mt1) / 1000); mt1 = getMicroTime(); /* grn_obj *obj = grn_ctx_get(&ctx, "select", strlen("select")); grn_obj *table = getSelectParam(&ctx, obj, 0, "EkiPos"); grn_obj *filter = getSelectParam(&ctx, obj, 3, "geo_in_circle(location, \"35.681454,139.767200\", 10000)"); grn_obj *scorer = getSelectParam(&ctx, obj, 4, "_score = geo_distance(location, \"35.681454,139.767200\")"); grn_obj *output_columns = getSelectParam(&ctx, obj, 6, "_key,_score"); grn_obj *sortby = getSelectParam(&ctx, obj, 5, "_score"); grn_obj *offset = getSelectParam(&ctx, obj, 7, "0"); grn_obj *limit = getSelectParam(&ctx, obj, 8, "100"); */ grn_obj *obj = grn_ctx_get(&ctx, "select", strlen("select")); grn_obj *table = getSelectParam(&ctx, obj, "table", "EkiPos"); grn_obj *filter = getSelectParam(&ctx, obj, "filter", "geo_in_circle(location, \"35.681454,139.767200\", 10000)"); grn_obj *scorer = getSelectParam(&ctx, obj, "scorer", "_score = geo_distance(location, \"35.681454,139.767200\")"); grn_obj *output_columns = getSelectParam(&ctx, obj, "output_columns", "_key,_score"); grn_obj *sortby = getSelectParam(&ctx, obj, "sortby", "_score"); grn_obj *offset = getSelectParam(&ctx, obj, "offset", "0"); grn_obj *limit = getSelectParam(&ctx, obj, "limit", "100"); mt2 = getMicroTime(); printf("create sql objects (%lfms)\n",(mt2 - mt1) / 1000); mt1 = getMicroTime(); grn_expr_exec(&ctx, obj, 0); mt2 = getMicroTime(); printf("grn_expr_exec (%lfms)\n",(mt2 - mt1) / 1000); mt1 = getMicroTime(); grn_ctx_info_get(&ctx, &info); printf("%.*s\n", (int)GRN_TEXT_LEN(info.outbuf), GRN_TEXT_VALUE(info.outbuf)); grn_expr_clear_vars(&ctx, obj); grn_obj_unlink(&ctx, obj); mt2 = getMicroTime(); printf("get result print free (%lfms)\n",(mt2 - mt1) / 1000); mt1 = getMicroTime(); grn_obj_close(&ctx, db); grn_ctx_fin(&ctx); grn_fin(); mt2 = getMicroTime(); printf("free library objects (%lfms)\n",(mt2 - mt1) / 1000); return 0; }
流れとしては、ライブラリ・ハンドルの初期化、SELECT文オブジェクトの生成と付随パラメータオブジェクトをどんどん作成していきSELECTオブジェクトに登録してgrn_expr_execでSQL実行、結果文字列を取得し表示、開放です。
コンパイル・実行
g++ -I /usr/include/groonga groonga_test.c -lgroonga ./a.out initialize library (25.814000ms) create sql objects (0.411000ms) grn_expr_exec (2.937000ms) [[[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]]] get result print free (0.026000ms) free library objects (2.995000ms)
コマンドコンソールで打ったのと全く同じ結果が得られました。結果をバイナリ構造体で操作する方法がわからず、返るのはJSON文字列です。parsonなどのパーサにかけるか、自力で文字列処理する感じになるでしょうか。
処理速度に関しては、約1万件の駅緯度経度データから周辺駅検索の結果としては、うーん、それほど速いとは言えない。。(2.93ミリ秒)もちろん呼び方が間違っている可能性も大いにあるわけですが。
あとライブラリの初期化と開放に妙に時間がかかってるのも気になるところ。
【次の記事】Gmailフィルタ設定メモ
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ
※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!ご連絡は以下アドレスまでお願いします★
【キーワード検索】
【最近の記事】【全部の記事】
nohupで常時起動したPythonスクリプトがログを出力しない場合Intel Macbook2020にBootCampで入れたWindows11 Pro 23H2のBluetoothを復活させる
Windowsのデスクトップ画面をそのまま配信するための下準備
WindowsでGPUの状態を確認するには(ASUS系監視ソフトの自動起動を停止する)
CORESERVER v1プランからさくらインターネットスタンダートプランへ引っ越しメモ
さくらインターネットでPython MecabをCGIから使う
さくらインターネットのPHPでAnalytics-G4 APIを使う
インクルードパスの調べ方
【Git】特定ファイルを除外する.gitignore
【Ubuntu/Debian】NVIDIA関係のドライバを自動アップデートさせない
【人気の記事】【全部の記事】
進研ゼミチャレンジタッチをAndroid端末化する【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法
【Apache】サーバーに同時接続可能なクライアント数を調整する
Windows版Google Driveが使用中と言われアンインストールできない場合
Windows11+WSL2でUbuntuを使う【2】ブリッジ接続+固定IPの設定
【C/C++】小数点以下の切り捨て・切り上げ・四捨五入
GitLabにHTTPS経由でリポジトリをクローン&読み書きを行う
cannot guess build type; you must specify oneと言われた場合
VirtualBoxの仮想マシンをWindows起動時に自動起動し終了時に自動サスペンドする
Pythonで処理にかかった時間を計測するには
【カテゴリーリンク】
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ