<div dir="ltr">こんにちは、中村です。<div><br>PGroongaでPostgreSQLの関数としてpgroonga.snippet_htmlを作りたいと</div><div>思っているのですが、実装方法について相談させください。</div><div><br></div><div>Groongaには実験的な機能ですがsnippet_html()という関数が存在しています。</div><div><a href="http://groonga.org/ja/docs/reference/functions/snippet_html.html" target="_blank">http://groonga.org/ja/docs/reference/functions/snippet_html.html</a><br><br><div><div>ですが、理想としてはPostgreSQLの関数としてpgroonga.snippet_html()を作りたいと</div><div>考えています。というのはcontentというカラムに検索対象のテキストが入っている時に</div><div><br></div><div>select * from テーブル名 where content @@ &#39;クエリー&#39;</div><div><br></div><div>というSQLで検索するとcontentカラムのデータサイズが大きい時に、データ転送量が</div><div>肥大化してしまうからです。今扱っているデータには数百MBぐらいのものがあるので</div><div>丸ごと転送したくないのです。</div><div><br></div><div>もし以下のようなSQLを書ければcontentの値全体の転送は不要でsnippet_htmlの</div><div>加工結果の小さいサイズの転送だけですみます。</div><div><br></div><div><div>select id, title, snippet_html(content, 他に必要な引数...) as content from テーブル名 where content @@ &#39;クエリー&#39;</div></div><div><br></div><div>とりあえず、PGroongaのコードを見ながら、見よう見まねでクイック&ダーティーな実装を作ってみました。<br><a href="https://github.com/pgroonga/pgroonga/compare/master...hnakamur:add_pgroonga_snippet_html" target="_blank">https://github.com/pgroonga/pgroonga/compare/master...hnakamur:add_pgroonga_snippet_html</a><br></div><div><br><a href="https://github.com/pgroonga/pgroonga" target="_blank">https://github.com/pgroonga/pgroonga</a> の「基本的な使い方」のテーブルとデータがある</div><div>状態で、以下のSQLを実行すればデータが取得できるようになりました。</div><div><br></div><div><div>test=# select id, json_extract_path_text(pgroonga.snippet_html(memos, &#39;groonga&#39;, &#39;memos_index&#39;, &#39;content&#39;)::json, &#39;1&#39;, &#39;0&#39;, &#39;2&#39;, &#39;0&#39;, &#39;0&#39;) from memos where content %% &#39;groonga&#39;;</div><div> id |</div><div>json_extract_path_text</div><div>----+-------------------------------------------------------------------------------------------------------------------------------------</div><div>  2 | &lt;span class=&quot;keyword&quot;&gt;Groonga&lt;/span&gt;は日本語対応の高速な全文検索エンジンです。</div><div>  3 | P&lt;span class=&quot;keyword&quot;&gt;Groonga&lt;/span&gt;はインデックスとして&lt;span class=&quot;keyword&quot;&gt;Groonga&lt;/span&gt;を使うためのPostgreSQLの拡張機能です。</div><div>  4 | &lt;span class=&quot;keyword&quot;&gt;groonga&lt;/span&gt;コマンドがあります。</div><div>(3 rows)</div><div><br></div><div>しかし、%%の代わりに@@を使うとなぜか0件になってしまうという問題があります。</div><div><br></div><div>test=# select id, json_extract_path_text(pgroonga.snippet_html(memos, &#39;groonga&#39;, &#39;memos_index&#39;, &#39;content&#39;)::json, &#39;1&#39;, &#39;0&#39;, &#39;2&#39;, &#39;0&#39;, &#39;0&#39;) from memos where content @@ &#39;groonga&#39;;</div><div> id | json_extract_path_text</div><div>----+------------------------</div><div>(0 rows)<br><br>いずれにせよ、現状の実装は<br><a href="https://github.com/hnakamur/pgroonga/blob/f3c284b2643285f002c2b67e5929d139cc558763/pgroonga.c#L1363-L1378" target="_blank">https://github.com/hnakamur/pgroonga/blob/f3c284b2643285f002c2b67e5929d139cc558763/pgroonga.c#L1363-L1378</a><br>でpgroonga.command()と同等の処理を行うという手抜き実装なので、GroongaのCのAPIを使って書きなおすべきかと</div></div><div>思っております。</div><div><br></div><div>SQL関数としてのpgroonga.snippet_htmlの引数は<br></div><div><a href="https://github.com/pgroonga/pgroonga/blob/870f0edae912a53e3bb2f232e7e82d7c857d117e/pgroonga.sql#L26-L31" target="_blank">https://github.com/pgroonga/pgroonga/blob/870f0edae912a53e3bb2f232e7e82d7c857d117e/pgroonga.sql#L26-L31</a><br>にあるように</div><div><div><br>1. &quot;row&quot; record</div><div>2. query text</div><div>3. indexName cstring</div><div>4. columnName cstring</div></div><div><br></div><div>と4つもあります。<br>rowはctidを取得するために必要です。<br>queryとindexNameとcolumnNameはGroongaのクエリの作成と検索結果の値の取得に必要です。</div><div>本当はSQLのwhere句で同じクエリを作っているので、それを参照したいところです。</div><div>が、SQLの関数から参照する方法が見つけられないので、Groongaのクエリ作成に必要な情報を</div><div>引数で渡して行ごとにクエリを作っています。</div><div><br></div><div>PGroongaのソースもPostgreSQLのソースも読み始めたばかりなので、もっと良い方法がありそうな</div><div>気はしています。</div><div><br></div><div>ということで、仕様や実装についてアドバイスやご意見ありましたら、ぜひフィードバックを</div><div>お願いします。</div><div><br></div><div><div>-- </div><div>中村 弘輝 )Hiroaki Nakamura)</div><div><br></div></div>
</div></div></div>