今日から始めるSenna QL API
Senna QL API(Senna Query Language API)を使ったプログラムを書くための下調べとして、簡単なサンプルプログラムを書いてみました。以下、ソースとコメントをあわせてご覧下さい。SennaQLを文字列そのまま投げる感じが伺えると思います。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <senna/senna.h> const char *dbpath = "hoge.SEN"; int dbcreate_flag = 0; sen_encoding db_encoding = sen_enc_utf8; int ctx_flag = SEN_CTX_USEQL; /* 必須 */ sen_db *db; sen_ctx *ctx; /* SennaQL実行用の関数 */ void hoge(const char *str) { char *ql; char *res; unsigned int res_len; int res_flags; char *buf; unsigned int ql_len = strlen(str); ql = (char*) malloc(ql_len); /* auto変数の文字列リテラルをそのまま渡すと問題が起きるので */ strncpy(ql,str,ql_len); /* heap上にコピーしてます。普通は入力データはheap上にあると思われ。*/ sen_ctx_send(ctx,ql,ql_len,0); /* SennaQLの実行 */ do { sen_ctx_recv(ctx,&res,&res_len,&res_flags); buf = (char*) calloc(1,1024); printf("%s => %s\n",str,strncat(buf,res,res_len)); free(buf); } while (res_flags & SEN_CTX_MORE); /* 結果が複数レコードある場合にはSEN_CTX_MOREフラグが立っています */ free(ql); } int main() { sen_init(); /* Senna APIを使う時には必ず最初に呼ぶ */ db = sen_db_open(dbpath); /* サンプルなのでファイルがなかったら作る */ if (!db) { db = sen_db_create(dbpath,dbcreate_flag,db_encoding); } ctx = sen_ctx_open(db,ctx_flag); /* テーブル定義 */ hoge("(ptable '<items>)"); hoge("(<items> ::def :title <text>)"); hoge("(<items> ::def :body <text>)"); /* レコードを追加 */ hoge("(<items> ::new \"key1\")"); hoge("((<items> : \"key1\") :title \"hoge fuga\")"); hoge("((<items> : \"key1\") :body \"fuga uho ii fuga\")"); /* レコードを追加 */ hoge("(<items> ::new \"key2\")"); hoge("((<items> : \"key2\") :title \"aaa\")"); hoge("((<items> : \"key2\") :body \"bbb uho uho bbb\")"); /* テーブル内のレコード件数を取得 */ hoge("(<items> ::nrecords)"); /* N-Gramインデックスを追加 */ hoge("(ptable '<terms> :ngram)"); hoge("(<terms> ::def :item_body :as '(<items>.body ::match ()))"); /* 検索実行(結果をJSON形式で表示)(主キーのみ)*/ hoge("(disp (<terms>.item_body : \"uho\") :json)"); /* 検索実行(結果をtab区切り形式で表示)(主キーのみ)*/ hoge("(disp (<terms>.item_body : \"uho\") :tsv)"); /* レコードの追加を1行でやるべく関数を定義 */ hoge("(define (add_items items_key items_title items_body)(<items> ::new items_key :title items_title :body items_body))"); /* 関数を利用したレコードの追加 */ hoge("(add_items \"key3\" \"dondon\" \"ai ue o uho eee\")"); /* 検索時に主キー以外のカラムも同時に取得するための関数を定義 */ hoge("(define (sen-output . x)(disp (car x).:nr :tsv)(disp (cons : x) :tsv))"); /* 検索実行 */ hoge("(sen-output (<terms>.item_body : \"uho\") '(.:key .title .body))"); sen_ctx_close(ctx); sen_db_close(db); sen_fin(); return 0; }
実行結果
(ptable '<items>) => #t (<items> ::def :title <text>) => #t (<items> ::def :body <text>) => #t (<items> ::new "key1") => #p<0000900001> ((<items> : "key1") :title "hoge fuga") => "hoge fuga" ((<items> : "key1") :body "fuga uho ii fuga") => "fuga uho ii fuga" (<items> ::new "key2") => #p<0000900002> ((<items> : "key2") :title "aaa") => "aaa" ((<items> : "key2") :body "bbb uho uho bbb") => "bbb uho uho bbb" (<items> ::nrecords) => 2 (ptable '<terms> :ngram) => #t (<terms> ::def :item_body :as '(<items>.body ::match ())) => #t (disp (<terms>.item_body : "uho") :json) => ["key1", "key2"] (disp (<terms>.item_body : "uho") :json) => #t (disp (<terms>.item_body : "uho") :tsv) => key1 (disp (<terms>.item_body : "uho") :tsv) => key2 (disp (<terms>.item_body : "uho") :tsv) => #t (define (add_items items_key items_title items_body)(<items> ::new items_key :title items_title :body items_body)) => add_items (add_items "key3" "dondon" "ai ue o uho eee") => #p<0000900003> (define (sen-output . x)(disp (car x).:nr :tsv)(disp (cons : x) :tsv)) => sen-output (sen-output (<terms>.item_body : "uho") '(.:key .title .body)) => 3 (sen-output (<terms>.item_body : "uho") '(.:key .title .body)) => key1 hoge fuga fuga uho ii fuga (sen-output (<terms>.item_body : "uho") '(.:key .title .body)) => key2 aaa bbb uho uho bbb (sen-output (<terms>.item_body : "uho") '(.:key .title .body)) => key3 dondon ai ue o uho eee (sen-output (<terms>.item_body : "uho") '(.:key .title .body)) => #t