<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2015年8月11日 22:40 Kouhei Sutou <span dir="ltr"><<a href="mailto:kou****@clear*****" target="_blank">kou****@clear*****</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In <<a href="mailto:CAN-DUMRVh9Hp9xwfN%2B313cAa1OosGqhjovX3-iLo%2B4RW****@mail*****">CAN-D****@mail*****</a>><br>
"[groonga-dev,03398] PGroongaでPostgreSQLの関数としてpgroonga.snippet_htmlを作りたい" on Tue, 11 Aug 2015 18:06:50 +0900,<br>
Hiroaki Nakamura <<a href="mailto:hnaka****@gmail*****">hnaka****@gmail*****</a>> wrote:<br>
<br>
> Groongaには実験的な機能ですがsnippet_html()という関数が存在しています。<br>
> <a href="http://groonga.org/ja/docs/reference/functions/snippet_html.html" rel="noreferrer" target="_blank">http://groonga.org/ja/docs/reference/functions/snippet_html.html</a><br>
><br>
> ですが、理想としてはPostgreSQLの関数としてpgroonga.snippet_html()を作<br>
> りたいと<br>
> 考えています。というのはcontentというカラムに検索対象のテキストが入っ<br>
<span class="">> ている時に<br>
><br>
> select * from テーブル名 where content @@ 'クエリー'<br>
><br>
> というSQLで検索するとcontentカラムのデータサイズが大きい時に、データ転<br>
> 送量が<br>
> 肥大化してしまうからです。今扱っているデータには数百MBぐらいのものがあ<br>
> るので<br>
> 丸ごと転送したくないのです。<br>
> もし以下のようなSQLを書ければcontentの値全体の転送は不要でsnippet_html<br>
> の<br>
> 加工結果の小さいサイズの転送だけですみます。<br>
><br>
> select id, title, snippet_html(content, 他に必要な引数...) as content<br>
> from テーブル名 where content @@ 'クエリー'<br>
<br>
</span>もしかしたら、ですけど、substring(content from 0 for 200)で<br>
も十分なのかもしれません。<br></blockquote><div><br></div><div>単に先頭から一部を表示するのではなく、できれば検索キーワードにヒットした部分を</div><div>強調表示したいので、やはりsnippet_htmlが欲しいところです。</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">> とりあえず、PGroongaのコードを見ながら、見よう見まねでクイック&ダーティー<br>
> な実装を作ってみました。<br>
> <a href="https://github.com/pgroonga/pgroonga/compare/master...hnakamur:add_pgroonga_snippet_html" rel="noreferrer" target="_blank">https://github.com/pgroonga/pgroonga/compare/master...hnakamur:add_pgroonga_snippet_html</a><br>
<br>
私も作ってみました。<br>
<a href="https://github.com/pgroonga/pgroonga/commit/9c8109a636c473ed2680cdee14bc440290813a19" rel="noreferrer" target="_blank">https://github.com/pgroonga/pgroonga/commit/9c8109a636c473ed2680cdee14bc440290813a19</a><br></blockquote><div><br></div><div>おお、素早い対応ありがとうございます。</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
↓という感じで使えます。<br>
<br>
SELECT id, pgroonga.snippet_html(content, ARRAY['groonga'])<br>
FROM memos<br>
WHERE content %% 'groonga';<br>
<br>
クエリーとして渡さずにユーザーがキーワードのリストを渡すよう<br>
にしました。こうすることで引数の数を減らすのと、PGroongaを使っ<br>
ていない場合でも使えるようにしています。<br>
<br>
使う人は自分でクエリーを分割する必要があるのが、もやっとする<br>
ところですが、引数が多くなるよりは使いやすいかなぁと思いまし<br>
た。<br>
<br>
たとえば、「Groonga OR PostgreSQL」と書いたときは自分で<br>
「Groonga」と「PostgreSQL」に分割して<br>
<br>
pgroonga.snippet_html(content, ARRAY['Groonga', 'PostgreSQL'])<br>
<br>
にしないといけません。<br>
<br>
もし、↑が面倒だなぁという声が増えたら<br>
pgroonga.query.extract_keywords()みたいな関数を作って<br>
<br>
pgroonga.snippet_html(content,<br>
pgroonga.query.extract_keywords(index, column, 'Groonga OR PostgreSQL'))<br>
<br>
としてもらうのがいいかなぁと思っています。<br></blockquote><div><br>pgroonga.query.extract_keywords()は欲しいです。クエリの解釈をPGroongaの外部で実装すると</div><div>将来クエリ構文が変更になった時に整合性がとれなくなる危険性が高いからです。</div><div>PGroongaのほうで提供されていれば、クエリ構文の変更と同時にpgroonga.query.extract_keywords()</div><div>の実装も変更すれば、アプリケーション側は変更不要で済むので、保守を考えるとそちらのほうが</div><div>ありがたいです。</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">> しかし、%%の代わりに@@を使うとなぜか0件になってしまうという問題があり<br>
<span class="">> ます。<br>
><br>
> test=# select id, json_extract_path_text(pgroonga.snippet_html(memos,<br>
> 'groonga', 'memos_index', 'content')::json, '1', '0', '2', '0', '0')<br>
> from memos where content @@ 'groonga';<br>
> id | json_extract_path_text<br>
> ----+------------------------<br>
> (0 rows)<br>
<br>
</span>これはどうしてなんでしょうねぇ。<br></blockquote><div><br></div><div>GroongaのC APIを使ってちゃんと作った版だと出ないかもしれないので、深くは調べてないですが、</div><div><div>where content @@ 'groonga' のクエリ実行中にpgroonga.snippet_htmlからもpgroonga.commandを</div><div>実行することで</div><div>static slist_head PGrnScanOpaques = SLIST_STATIC_INIT(PGrnScanOpaques);<br></div></div><div>か何かのstatic変数が途中で変更されてしまうことで何か問題があるのかもと漠然と思っていました。</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
> いずれにせよ、現状の実装は<br>
> <a href="https://github.com/hnakamur/pgroonga/blob/f3c284b2643285f002c2b67e5929d139cc558763/pgroonga.c#L1363-L1378" rel="noreferrer" target="_blank">https://github.com/hnakamur/pgroonga/blob/f3c284b2643285f002c2b67e5929d139cc558763/pgroonga.c#L1363-L1378</a><br>
> でpgroonga.command()と同等の処理を行うという手抜き実装なので、Groonga<br>
> のCのAPIを使って書きなおすべきかと<br>
> 思っております。<br>
<br>
</span>私が作ったやつはそうしてみました。<br></blockquote><div><br></div><div>ありがとうございます!<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
> SQL関数としてのpgroonga.snippet_htmlの引数は<br>
> <a href="https://github.com/pgroonga/pgroonga/blob/870f0edae912a53e3bb2f232e7e82d7c857d117e/pgroonga.sql#L26-L31" rel="noreferrer" target="_blank">https://github.com/pgroonga/pgroonga/blob/870f0edae912a53e3bb2f232e7e82d7c857d117e/pgroonga.sql#L26-L31</a><br>
> にあるように<br>
><br>
> 1. "row" record<br>
> 2. query text<br>
> 3. indexName cstring<br>
> 4. columnName cstring<br>
><br>
> と4つもあります。<br>
> rowはctidを取得するために必要です。<br>
> queryとindexNameとcolumnNameはGroongaのクエリの作成と検索結果の値の取<br>
> 得に必要です。<br>
<br>
</span>pgroonga.snippet_html()内でクエリーをパースしないようにする<br>
とrowとindexNameとcolumnNameがいらなくなります。代わりに、ス<br>
ニペット対象のテキストを受け取ります。<br>
<br>
> 本当はSQLのwhere句で同じクエリを作っているので、それを参照したいところ<br>
> です。<br>
<br>
この方向に頑張るのは現実的ではないんです。<br>
今回のように単純なSQLならいいですが、サブSELECTが使われたり、<br>
WHERE内で<br>
<br>
content %% 'Groonga' AND content NOT LIKE '%Mroonga%'<br>
<br>
とかされたときのことも考えるとだいぶツライです。<br></blockquote><div><br></div><div>確かにこういうのは無理ですね。</div><div><br></div><div>私の考えている使い方はユーザが入力した</div><div>title @@ 'クエリ' OR content @@ 'クエリ'</div><div>とクエリ構文で書いた同じクエリを複数カラムで検索するというものです。</div><div>これであれば、クエリ構文のクエリ文字列を引数に渡して</div><div><a href="http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html">http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html</a><br></div></div><div>の仕様にそってキーワードの配列を返す関数として</div><div>pgroonga.query.extract_keywords(query text)<br>を用意するというのは実現できそうに思いますが、いかがでしょうか?<br><br></div><div class="gmail_extra">-- </div><div class="gmail_extra">中村 弘輝 )Hiroaki Nakamura)</div><div><br></div>
</div></div>