アペフチ

Groongaでできる検索方法あれこれ

Groongaで学ぶ全文検索 2016-02-26に行って来た。

今日のお題は「select」。selectというのは、Groongaの、全文検索エンジンとして最も重要な機能である検索を行うためのコマンド。

前回、実際のテーブルやデータを見ながら話せたのがよかったという声が多かったので、今回も具体的なGroongaの使い方を、というところからの選択。

まず僕が使っている以下の機能を簡単に紹介したあとで、それ以外のを@ktouさんが紹介するという流れだった。

僕が使っている機能:

  • 全文検索
  • 完全一致検索 … EPUB Searcherの削除機能でレコードを特定する時に使っている
  • snippet_html出力 … この日記で、検索結果中の検索語をハイライトしている
  • グルーピング(ドリルダウン) … EPUB Searcherで著者一覧ページで、著者の下に本一覧を表示するのに使っている
  • カラムの重み付け … この日記の検索で、本文よりタイトルとタグでのヒットを重視している。

以下、@ktouさんが紹介してくれた機能:

クエリー言語として解析

例えばGoogleで「A B C」で検索すると「Aが含まれるかつBが含まれるかつCが含まれるページを探す」という意味になる。「A or B or C」と検索すると「Aが含まれるまたはBが含まれるまたはCが含まれるページを探す」という意味になる。ツイッターで「groonga -lang:ja」みたいな検索を僕はよくしていて、ここでの「lang:ja」(日本語のツイート)「-」(を除外する)というのもある(Groongaでもこの記法そのまま使えるとのこと。lang:jalangテーブルに対するjaでの検索になり、「-」を付けると除外になる)。こうした、クエリーの中に検索語以外の命令を含められる時、この命令を表現する物がクエリー言語と呼ばれる。Groongaにもこのクエリー言語を理解する能力がある。

集計機能

グルーピングした際、グループそれぞれについて、何件のレコードがヒットしたかを集計することもできる。件数を数えるほか、あるカラムの値の合計、平均、最大値、最小値を求めることもできる。

忘れていたけど、この、件数を取得して表示するのはEPUB Searcherで使っていた。

クエリー展開

「焼き肉」で検索した時、勝手に「焼き肉 OR 焼肉 OR やきにく」というクエリーに変更して検索してくれる機能。「焼き肉と焼肉とやきにくを同一視する」ということ自体はユーザー(アプリケーション開発者)が予め登録しておく必要がある(どうやって?)。何を同一視したいかというのは、アプリケーションによって変わるからだ。

重みの底上げ

いい名前が付いていないと言っていた。

検索時にカラムごとに重みを設定して(タイトルは重くする、本文はそれほどでもない、など)最終的にレコードごとに総合スコアを出す。これが通常の重み付け。

その総合スコアの計算の後に、更に重みの数値を足すことができる。例えば、キャンペーンフラグカラムがONだと重み+10する、など。

通常の重み付けはカラムに対しての指定だが、この底上げはレコード一つ一つに対しての指定となる点が特徴となる。

使い方例も紹介されたが公開していいかどうか分からないとのことだったのでここでは他の例で説明する。Google検索では、過去に検索して閲覧したことがあるページが、次からの検索で上位になりやすいようになっている。これは、「閲覧した回数」といったカラムを持っておいて、総合スコアを計算し終わった後にそのカラムの値を追加して検索上位に持ってくる、というふうに、Groongaを使う場合は実装することができる。

ソート

ソートできる。

途中から結果を出せる

オフセットとかページネーションとかいうやつ。

参照先でも検索できる

SQLだとJOINするようなのがGroongaはJOINせずに検索できる。

記事テーブルとコメントテーブルがあって、記事に対してコメントが結び付いているとする。この時、SQLだと記事の主キーとコメントの主キーをJOINで結び付ける。

  1. 記事とコメントがくっついたテーブルを作る(と見做すことができる)
  2. コメントテーブルの該当カラムに対して検索を実施し、
  3. 「くっついたテーブル」の記事テーブルの使いたいカラムを取得する

となる。

Groongaはコメントテーブルに記事への参照を記事テーブルにコメントへの参照を(発表していて逆だねって指摘してもらった)直接保持させることができる。だから、JOINのような追加の命令無く

  1. コメントに対して検索し、
  2. そのコメントが付いている記事を取得する

ということができる。

記事に対して、後から関連商品みたいなテーブルを加えたくなることがあるかも知れない。この時、RDBMSであれば(正規化されていれば)単にそのためのテーブルを作成し、検索時にJOINで結び付けるようにすることができる。記事テーブルには変更が必要ない。

Groongaの場合は記事テーブルに関連商品テーブルへの参照を持たせることになる(か逆方向の参照を持たせる。方向はアプリケーションによる)。既存の記事テーブルに対する変更が発生する。しかし、Groongaはカラム指向データベースなので、こうしたカラムの追加操作は低コストでできるので問題にならない(RDBMSでALTER TABLEとなると、件数によってはおおごとだ)。

「Solrはこうしたテーブル跨ぎの検索はうまくできないんでは?」と@ktouさんが言っていたので識者の指摘を待ちたい。