[groonga-dev,03401] Re: PGroongaでPostgreSQLの関数としてpgroonga.snippet_htmlを作りたい

アーカイブの一覧に戻る

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/




groonga-dev メーリングリストの案内
アーカイブの一覧に戻る