Kouhei Sutou
kou****@clear*****
2015年 8月 11日 (火) 22:40:21 JST
須藤です。 In <CAN-D****@mail*****> "[groonga-dev,03398] PGroongaでPostgreSQLの関数としてpgroonga.snippet_htmlを作りたい" on Tue, 11 Aug 2015 18:06:50 +0900, Hiroaki Nakamura <hnaka****@gmail*****> wrote: > Groongaには実験的な機能ですがsnippet_html()という関数が存在しています。 > http://groonga.org/ja/docs/reference/functions/snippet_html.html > > ですが、理想としてはPostgreSQLの関数としてpgroonga.snippet_html()を作 > りたいと > 考えています。というのはcontentというカラムに検索対象のテキストが入っ > ている時に > > select * from テーブル名 where content @@ 'クエリー' > > というSQLで検索するとcontentカラムのデータサイズが大きい時に、データ転 > 送量が > 肥大化してしまうからです。今扱っているデータには数百MBぐらいのものがあ > るので > 丸ごと転送したくないのです。 > もし以下のようなSQLを書ければcontentの値全体の転送は不要でsnippet_html > の > 加工結果の小さいサイズの転送だけですみます。 > > select id, title, snippet_html(content, 他に必要な引数...) as content > from テーブル名 where content @@ 'クエリー' もしかしたら、ですけど、substring(content from 0 for 200)で も十分なのかもしれません。 > とりあえず、PGroongaのコードを見ながら、見よう見まねでクイック&ダーティー > な実装を作ってみました。 > https://github.com/pgroonga/pgroonga/compare/master...hnakamur:add_pgroonga_snippet_html 私も作ってみました。 https://github.com/pgroonga/pgroonga/commit/9c8109a636c473ed2680cdee14bc440290813a19 ↓という感じで使えます。 SELECT id, pgroonga.snippet_html(content, ARRAY['groonga']) FROM memos WHERE content %% 'groonga'; クエリーとして渡さずにユーザーがキーワードのリストを渡すよう にしました。こうすることで引数の数を減らすのと、PGroongaを使っ ていない場合でも使えるようにしています。 使う人は自分でクエリーを分割する必要があるのが、もやっとする ところですが、引数が多くなるよりは使いやすいかなぁと思いまし た。 たとえば、「Groonga OR PostgreSQL」と書いたときは自分で 「Groonga」と「PostgreSQL」に分割して pgroonga.snippet_html(content, ARRAY['Groonga', 'PostgreSQL']) にしないといけません。 もし、↑が面倒だなぁという声が増えたら pgroonga.query.extract_keywords()みたいな関数を作って pgroonga.snippet_html(content, pgroonga.query.extract_keywords(index, column, 'Groonga OR PostgreSQL')) としてもらうのがいいかなぁと思っています。 > しかし、%%の代わりに@@を使うとなぜか0件になってしまうという問題があり > ます。 > > test=# select id, json_extract_path_text(pgroonga.snippet_html(memos, > 'groonga', 'memos_index', 'content')::json, '1', '0', '2', '0', '0') > from memos where content @@ 'groonga'; > id | json_extract_path_text > ----+------------------------ > (0 rows) これはどうしてなんでしょうねぇ。 > いずれにせよ、現状の実装は > https://github.com/hnakamur/pgroonga/blob/f3c284b2643285f002c2b67e5929d139cc558763/pgroonga.c#L1363-L1378 > でpgroonga.command()と同等の処理を行うという手抜き実装なので、Groonga > のCのAPIを使って書きなおすべきかと > 思っております。 私が作ったやつはそうしてみました。 > SQL関数としてのpgroonga.snippet_htmlの引数は > https://github.com/pgroonga/pgroonga/blob/870f0edae912a53e3bb2f232e7e82d7c857d117e/pgroonga.sql#L26-L31 > にあるように > > 1. "row" record > 2. query text > 3. indexName cstring > 4. columnName cstring > > と4つもあります。 > rowはctidを取得するために必要です。 > queryとindexNameとcolumnNameはGroongaのクエリの作成と検索結果の値の取 > 得に必要です。 pgroonga.snippet_html()内でクエリーをパースしないようにする とrowとindexNameとcolumnNameがいらなくなります。代わりに、ス ニペット対象のテキストを受け取ります。 > 本当はSQLのwhere句で同じクエリを作っているので、それを参照したいところ > です。 この方向に頑張るのは現実的ではないんです。 今回のように単純なSQLならいいですが、サブSELECTが使われたり、 WHERE内で content %% 'Groonga' AND content NOT LIKE '%Mroonga%' とかされたときのことも考えるとだいぶツライです。 -- 須藤 功平 <kou****@clear*****> 株式会社クリアコード <http://www.clear-code.com/> Groongaベースの全文検索システムを総合サポート: http://groonga.org/ja/support/ パッチ採用 - プログラミングが楽しい人向けの採用プロセス: http://www.clear-code.com/recruitment/ コードリーダー育成支援 - 自然とリーダブルコードを書くチームへ: http://www.clear-code.com/services/code-reader/