Feature #1957

mroonga ノウハウまとめ

Added by Kenji Maruyama over 4 years ago. Updated over 4 years ago.

Status:担当者作業中Start date:10/10/2013
Priority:NormalDue date:
Assignee:Kenji Maruyama% Done:

0%

Category:-
Target version:-

Description

まずは、groonga-devにて、今まで解決された問題についてまとめていきます。

History

#1 Updated by Kenji Maruyama over 4 years ago

  • Status changed from 新規 to 担当者作業中

commit c2258efc6225b68444c671595dd3e4eab5a73974

詳細はinternalの/maru/mroonga/memo.txt にありますが、手動でまとめるのをやめて、groonga-devのアーカイブをdumpし、mroongaを含むメールを抽出するスクリプト を書いてみました。

#2 Updated by Kouhei Sutou over 4 years ago

リストからこれは公式ドキュメントにあった方がいいなぁというのをピックアップしました!(ピックしなかったものの理由を知りたい場合はお伝えできます!)

#3 Updated by Kenji Maruyama over 4 years ago

2013/4 mroongaの検索時エラーについて
例えばまとめるとしたら、こんな感じになるでしょうか。

mmap failed!!!! in GRN_IO_SEG_REF エラーを回避するには

ログファイルに以下のようなmmapエラーが存在する場合があります。:

4524 C|e05d4700|mmap failed!!!! in GRN_IO_SEG_REF(0x7ef135995d50, 0)

この現象は 実行環境ののメモリ不足時に起こります。 例えば以下の操作が起因になります。

複数のテーブルに対して一度に複数の異なるの検索語で検索し、格納されているデータのほぼすべてがヒットする。

この現象がおきる原因を説明すると、groongaはmmapを使ってメモリを管理しています。テーブルやカラムに対応したファイルを1つずつ作り、そこにデータを格納しているわけですが、検索語がほぼすべてのテーブルのデータにヒットする場合、より多くのデータをmmapしている状況になります。mmapは必要になるまでデータをメモリ上にロードしないのですが、Linux OSの通常の設定では実メモリ以上の領域を mmap できないようになっています。 また、groongaはデータベースを閉じるまでは一度mmapした領域をunmapし ません。

解決方法:

  1. SQL文の先頭に 明示的に flush tables; を付与して、unmapします。
  2. sysctl -w vm.overcommit_memory=1 を実行する。 (再起動後も設定を有効するために /etc/sysctl.conf または、/etc/sysctl.d/groonga.conf(任意) に vm.overcommit_memory=1 を追記します。)

    vm.overcommit_memory=1 を実行すると実メモリ以上の領域を mmapしようとしてもエラーにならなくなります。 mmapしても使われなければエラーになりませ ん。(使われたらエラーになります。)

#4 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

2013/4 mroongaの検索時エラーについて


例えばまとめるとしたら、こんな感じになるでしょうか。

方向性はよいと思います!

あとは、前後のつながりと低レイヤーの話についてあまり知らない人でもわかるような粒度の詳細度にするとよいのではないかと思います!

「前後のつながり」の方はフォーマットをテンプレート化することでいい感じになるんじゃないかなぁと思います。例えば、こんな感じはどうでしょうか?(今、考えながら作ったものです。なので、実際にこのフォーマットを使ってみると過不足があるかもしれません。理由をちゃんと説明するとかできるだけ具体的に説明するとかは私が milter managerというソフトウェアのセットアップ手順 を書いた時とかに注意していたことを思い出しながらまとめました。)

# ${タイトル}(一言で簡潔に問題を表すこと)

${サマリー}(多くても数個の文で問題の概要と解決方法の概要を説明する)

## 現象

(問題が発生しているときに起こることを説明する。長さの制限はなし。)

## 確認方法

(問題が起きているかどうかを確認する方法を説明する。問題が解決したかど
うかにも使えるのでこの方法を提供することには重要な意味がある。長さの制
限はなし。)

## 原因

(どうしてこの問題が発生するかを説明する。長さの制限はなし。)

## 解決方法

この問題を解決する方法は${N}個あります。

  * ${解決方法1の名前}
  * ${解決方法2の名前}
  * ...
  * ${解決方法Nの名前}

### 解決方法1: ${解決方法1の名前}

${解決方法1の概要}(問題をどのように解決する方法なのか方針を説明する。
「なんかよくわからないけどこれをやれば直るらしい」ではなく、理由を理解
した上で直せるような情報を提供する。長さの制限はなし。)

#### 作業内容

${解決方法1を実現する方法}(できるだけ具体的に書く。感覚的にいうと、
「コピペできるように書く」とか、「条件分岐なしで書く」という感じ。「適
切な値を入力」や、「任意の値を入力」とかにしない。どんな値でもよいなら
「○○を入力」とかにして、そのまま使えるようにする。「自分のユーザー名
を入力」とかなら「$(id --user --name)」とか自動で取得できるようにする。
長さの制限はなし。)

#### 確認方法

${解決方法1をちゃんと実施できているかを確認する方法}(設定を変更したな
ら現在の設定を確認する方法を書く。途中で作業を間違えていた場合はここで
気付けるようにする。長さの制限はなし。)

「解決方法が適切に実施されているので、問題が解消されていることを確認す
る。問題の${確認方法}を実施して○○という結果になることが確認できれば解
決方法1が有効だったことがわかる。」みたいなことを書く。

#### 注意点

${解決方法1を使う場合の注意点を書く}(問題は直るけどメモリー使用量が多
くなるとか副作用があるなら書く。ないなら特に注意する点はないとか副作用
などはないと明記する。長さの制限はなし。)

### 解決方法2: #{解決方法2の名前}

...

「説明の詳細度」の方は、以下のような設定でどうでしょうか!?

  • apt/yumでパッケージをインストールできるけど、Linuxのカーネルとかシステムのパラメーターについてはよく知らない。
  • プログラムについてもよく知らない。
  • SQLについてはINSERT/SELECT/UPDATE/DELETEなコマンドは知っているけど、管理系のコマンドは知らない。

なので、以下のことはわからないだろうなぁという前提になります。

  • mmap/unmap(プログラムについてよく知らないからわからなそう)
  • sysctl(Linuxのカーネルパラメーターについてはよく知らないからわからなそう)
  • vm.overcommit_memory(Linuxのカーネルパラメーターについてはよく知らないからわからなそう)
  • /etc/sysctl.conf, /etc/sysctl.d/groonga.conf(Linuxの起動プロセスでどんな設定がされるかよく知らないからわからなそう)

どうでしょうか!?

#5 Updated by Kenji Maruyama over 4 years ago

ありがとうございます。

http://redmine.groonga.org/issues/1957#note-4

に 基づいて http://redmine.groonga.org/issues/1957#note-2 をまとめてみますね。

それと http://redmine.groonga.org/issues/1957#note-1、mroongaを含むメールを抽出した結果については、mroonga過去versionのFAQのログとして(ローカルで)検索して参照するときに便利かと思いやってみました。 また、internalのメモにてTipsとして途中までまとめたものについても #note-4 に従って ここに書いてみます。

#6 Updated by Kenji Maruyama over 4 years ago

アウトプットイメージは は Linux FAQ を 想定しています。再現ログは省略してなるべく簡潔に、http://redmine.groonga.org/issues/1957#note-4 の方針 で まとめたいと思います。

internalの途中までのメモは以下になっています.(β版)


* 2013/4 mroongaの検索時エラーについて
http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-April/001293.html
問題:現在、約2.1GBのテキストがそれぞれ格納されたファイル120個を原料に、120個のmroongaのテーブルを作成して使用しております。通常は問題無く検索できるのですがバッチ処理にして、複数の検索語を次々検索するという事を行いますと、時々エラーが出ます。概ね、3回検索するとエラーが1回出る感じです。
解答:roongaはテーブルやカラムに対応したファイルをそれぞれ1つ作り、
そこにデータを格納します。ただ、ファイルサイズが1GBを超える
と別のファイルを作り、そちらにもデータを保存します。別ファイ
ルになったデータは必要になったときにmmapして利用します。つま
り、必要になるまではメモリ上にロードされないということです。

さて、今回のケースではたくさんのテーブルに対してたくさんの検
索語で検索しているということなので、格納されているデータがま
んべんなくヒットし、より多くのデータをmmapしている状況だと考
えられます。

実データが2.1GB * 120で240GBで、それのインデックスは少なくと
も2倍以上にはなっているのではないかと思います。実メモリが
32GBということなので、多くのデータがロードされる場合はメモリ
不足になります。

groongaはデータベースを閉じるまでは一度mmapした領域をunmapし
ません。mroongaで言えばFLUSH TABLESを実行するとgroongaのデー
タベースを一度閉じています

エラーが起きたら明示的にFLUSH TABLESを実行しても回避できるのではないかと思います。
(MySQLは自動的にFLUSH TABLES相当のことをするのでしょう
か。。。)

以下を実行するとそもそもこの現象が起こら
なくなるかもしれません。
  sysctl -w vm.overcommit_memory=1

これを実行すると実メモリ以上の領域をmmapしようとしてもエラー
にならなくなります。mmapしても使われなければエラーになりません。(使われたらエラーになります。)

なお、Redisも同じ設定を推奨しています。
もし、これでうまく動くようになったら、/etc/sysctl.confか
/etc/sysctl.d/groonga.confとかいうファイルを作ってそこ
に以下を記述しておくと再起動後も設定が有効になります。

  vm.overcommit_memory = 1

* 2013/4 mroongaのログレベルについて
http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-April/001290.html
問題:ログレベルをERRORにして、大量のmroongaのテーブル作成処理したら、大きなログ・ファイルとなってしまいました。ログレベルをNONEに設定しても、>相変わらずログが出続けています。ERRORでもありませんし、ましてやNONEでもないです。
解答:最新版では修正済みだが、mroonga3.0.0ではログレベルを変えてもログが出続ける。説明文をつけました。

* 2013/4 mroongaの制限事項について
http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-April/001281.html
問題:groongaの日付型に関する制限, レコード件数の制限はmroongaにも適用されるのか。それとも、何らかの内部的な回避策が取られているのでしょうか。
解答:mroongaにも適用されます!内部的に回避したりはしていません。mroongaの場合はSpiderと連携し、1ホストあたりで扱うデータ量を減らすことで回避することができます。mroongaの制限事項の所に追記しました。
問題:mroongaのレコード数の制限は、テーブル単位、DB単位、サイト単位のどれか。
解答:テーブル単位です

* 2012/4 wingリポジトリ用 groonga 3.0.2 mroonga 3.02
http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-April/001276.html
問題:groongaのsrpmをリビルドしている時に、ある現象に遭遇しました。それは、64bit環境でビルドしていた時に、大したエラーも無く突然expr.cをごにょ>ごにょしている時に落ちるという現象です。
解答:メモリー不足. el6では1GB、el5では1.5GBを割り当ててエラーは出なくなりました. ソースコンパイル、srpmをリビルドする時の参考になればと思いま>す。最適化アリのビルドだとメモリをたくさん使うんです。

* 2012/2 全文検索カラム以外を含んだ検索について
http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-February/000693.html
問題: Fulltext_index対象以外のカラムを含んだ検索をする場合の動作は、まず全文検索を実行した後、検索対象の通常カラムのみを読み込んで、対象行を特定するのか
解答:はい。MySQLのクエリ実行プランを考えているところも関係するので、
全体のレコード数やヒット件数によっては異なるかもしれません。

さて、Tritonnの2ind機能では以下の4種類の問題を解決していまし
た。
  http://qwik.jp/tritonn/userguide.html#0cb0baa8b27d86e9233f601a9cc9cc4f

1. limit指定で出力を制限しても応答が遅い問題
     select columns from table where match(a) against(b) limit 1000, 10
2. count(*)等で件数を取得するだけでも応答が遅い問題
     select count(*) from table where match(a) against(b);
3. 全文検索以外の条件で絞り込む処理が遅い問題
     select columns from table where match(a) against(b) and c like 'hoge%';
4. 全文検索以外の条件でソートする処理が遅い問題
     select columns from table where match(a) against(b) order by c;

今回のケースは3.にあたるかと思います。

mroongaでは、このうち1.と2.のみを実装していますが、3.と4.は
未実装です。

1.に相当する「全文検索時の ORDER BY LIMIT 高速化」:
  http://mroonga.github.com/ja/docs/userguide/storage.html#optimisation-for-order-by-limit-in-full-text-search
2.に相当する「行カウント高速化」:
  http://mroonga.github.com/ja/docs/userguide/storage.html#optimisation-for-counting-rows

で、3.についてはcond pushという仕組みで実現できそうなのです
が、まだ手を付けられていません。4.についてはまだ検討していま
せん。

ORDER BY LIMITを指定すると
http://mroonga.github.com/ja/docs/userguide/storage.html#optimisation-for-order-by-limit-in-full-text-search
と同じ論理で高速化するようにしました。これまでは、whereには全文検索条件1つのときしか「ORDER BY
LIMIT 高速化」ができなかったのですが、全文検索条件と「簡単な
式」のwhereなら高速化するようにしました。

今のところ、「簡単な式」のところは「カラム名 = INTの値」のみ
だけサポートしています。が、ここは難しいというよりも手を動か
していけば対応種類を増やせるところなので、要望が大きいところ
から対応していく進め方が現実的かと思っています。(たとえば、
DOUBLEの値に対応することや「カラム名 < INTの値」などに対応す
ることも難しくありません。)

* 2012/2 ストレージエンジンモードのメモリ使用について
http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-February/000692.html
問題:mroongaストレージエンジンモードでは、何かパラメータオプションなどは存在しますでしょうか?
解答:パラメータはいくつかありますが、バッファサイズを指定するとか
そういったパフォーマンスチューニングの類のパラメータではなく、
もう少しユーティリティ的な感じのパラメータです。
  http://mroonga.github.com/ja/docs/reference.html#list-of-server-variables
問題:ストレージエンジンモードのテーブルに、Fulltext_indexとB-tree_indexを貼った場合、メモリ領域を共有するかどうか。
解答:まず、ストレージエンジンモードでは大きく分けてインデックスは
以下の4パターンがあります。

  * 全文検索用インデックス:
    CREATE FULLTEXT INDEXに対応。USINGは無視で、常にパトリシ
    アトライを使用。

  * 位置情報検索用インデックス:
    CREATE SPATIAL INDEXに対応。USINGを指定してはいけない。
    常にパトリシアトライを使用。

  * 検索・ソート用インデックス:
    CREATE INDEX(USINGなし)またはCREATE INDEX ... USING
    BTREEに対応。範囲検索やソートにも使える。内部的にはBツリー
    ではなくパトリシアトライを使用。

  * 検索用インデックス:
    CREATE INDEX ... USING HASHに対応。範囲検索やソートには
    使えない。が、完全一致検索は検索・ソート用インデックスよ
    り高速。

それぞれのパターンでキーになるものが変わってきます。これは主
にどのようにトークナイズするかどうかで変わってきます。(位置
情報検索用のインデックスは別。)

例えば、全文検索用インデックスの場合は、値そのものではなく、
値をトークナイズし、トークンそれぞれがキーになりますが、検索・
ソート用インデックスや検索用インデックスではトークナイズせず
に値そのものがキーになります。

で、この「どのようにトークナイズするか」は各インデックス毎に
異なる情報なので、別々に管理しています。そのため、使用するメ
モリ領域も別々になっています。


なお、同じ種類のインデックス間ではキー管理の部分を共有するこ
ともできるのですが、今はまだそこは実装されていません。
(groongaを直接使う場合はそのようなことができます。)

ただし、その場合でも全文検索用のインデックスと検索用のインデッ
クスなどのように違う種類のインデックス間ではメモリ領域を共有
することはできません。

* 2012/2 boolean modeでのプラグマ指定について
http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-February/000691.html
問題:boolean modeでのプラグマ指定について、最新のバージョンでも対応しているコマンドは[*D]のみという事になるか
解答:はい。

* 2012/1 ディレクトリカスタマイズでコンパイルするとINSTALL PLUGINでエラー
http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-January/000670.html
問題: mroongaコンパイルを、ディレクトリをカスタマイズして導入すると、
INSTALL PLUGINで以下のように失敗します。mroonga+mysqldを都合上rpmで入れたくありません。
解答:CCとCXXをなしにするとINSTALL PLUGINいけました. 実はGROONGA_CFLAGS/LIBSを指定するのではなくて、

  export PKG_CONFIG_PATH=/usr/local/groonga129/lib/pkgconfig

とpkg-configのパスをgroongaの${prefix}/lib/pkgconfigに通すほ
うがオススメなんです。そうすると、もし、groonga側でビルドオ
プションが変わったときでもそれに追従してくれます。
GROONGA_CFLAGS/LIBSを直接指定していると自分でビルドオプショ
ンを設定しないといけないのです。

* 2012/1 mroonga make 時エラー
http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-January/000674.html
問題:make時にha_mroonga.cc:692: warning: type-punning to incomplete type might break
strict-aliasing rules
解答:-Wno-strict-aliasing をMakefileに追加


#7 Updated by Kenji Maruyama over 4 years ago

#8 Updated by Kenji Maruyama over 4 years ago

Q: ストレージエンジンモードのテーブルにFulltext_indexとB-tree_indexを貼った場合メモリ領域を共有しますか?

A: 共有しません。

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-February/000692.html )

まず、ストレージエンジンモードでは大きく分けてインデックスは 以下の4パターンがあります。

  • 全文検索用インデックス: CREATE FULLTEXT INDEXに対応。USINGは無視で、常にパトリシ アトライを使用。

  • 位置情報検索用インデックス: CREATE SPATIAL INDEXに対応。USINGを指定してはいけない。 常にパトリシアトライを使用。

  • 検索・ソート用インデックス: CREATE INDEX(USINGなし)またはCREATE INDEX ... USING BTREEに対応。範囲検索やソートにも使える。内部的にはBツリー ではなくパトリシアトライを使用。

  • 検索用インデックス: CREATE INDEX ... USING HASHに対応。範囲検索やソートには 使えない。が、完全一致検索は検索・ソート用インデックスよ り高速。

それぞれのパターンでキーになるものが変わってきます。これは主 にどのようにトークナイズするかどうかで変わってきます。(位置 情報検索用のインデックスは別。)

例えば、全文検索用インデックスの場合は、値そのものではなく、 値をトークナイズし、トークンそれぞれがキーになりますが、検索・ ソート用インデックスや検索用インデックスではトークナイズせず に値そのものがキーになります。

で、この「どのようにトークナイズするか」は各インデックス毎に 異なる情報なので、別々に管理しています。そのため、使用するメ モリ領域も別々になっています。

なお、同じ種類のインデックス間ではキー管理の部分を共有するこ ともできるのですが、今はまだそこは実装されていません。 (groongaを直接使う場合はそのようなことができます。)

ただし、その場合でも全文検索用のインデックスと検索用のインデッ クスなどのように違う種類のインデックス間ではメモリ領域を共有 することはできません。

Q: mroonga の性能で判明している問題、解決済の問題教えてください。

A: 4つの問題が分かっています。1, と 2 については 対応済みです。3 と 4 については未対応 です。

  1. limit指定で出力を制限しても応答が遅い問題 select columns from table where match(a) against(b) limit 1000, 10
  2. count(*)等で件数を取得するだけでも応答が遅い問題 select count(*) from table where match(a) against(b);
  3. 全文検索以外の条件で絞り込む処理が遅い問題 select columns from table where match(a) against(b) and c like 'hoge%';
  4. 全文検索以外の条件でソートする処理が遅い問題 select columns from table where match(a) against(b) order by c;

解説 (http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-February/000693.html)

  1. に相当する「全文検索時の ORDER BY LIMIT 高速化」 http://mroonga.github.com/ja/docs/userguide/storage.html#optimisation-for-order-by-limit-in-full-text-search
  2. に相当する「行カウント高速化」: http://mroonga.github.com/ja/docs/userguide/storage.html#optimisation-for-counting-rows

で、3.についてはcond pushという仕組みで実現できそうなのです が、まだ手を付けられていません。4.についてはまだ検討していま せん。

Q: boolean modeでのプラグマ指定で対応しているのは?

A: DとWプラグマ です。

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-February/000691.html )

使い方については http://qwik.jp/senna/query.html か?

Q: mroongaでの分かち書き検索方法を教えて下さい。

A: mroonga では 検索するときに複数の検索方法を組み合わせています。完全に一致するレコードがヒットしなかったら少しずつゆるい条件にしながら検索します。

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-May/000846.html )

検索の挙動について http://groonga.org/ja/docs/spec/search.html を参考にしてください。

挙動を確認したい場合は、

mysql> SET GLOBAL mroonga_log_level = DEBUG;

というようにログレベルをあげて、

mysql> select ... match(japanese_splitted) against ('引火');

というように検索してください。

${MySQLのデータディレクトリ}/groonga.logに

2012-05-11 22:48:47.924024|i|7f6ce700|grn_ii_sel > (引火) 2012-05-11 22:48:47.924106|i|7f6ce700|exact: 0 2012-05-11 22:48:47.924241|i|7f6ce700|n=1 (引火) 2012-05-11 22:48:47.924326|i|7f6ce700|unsplit: 1 2012-05-11 22:48:47.924347|i|7f6ce700|hits=1

というようなログがでるはずです。

exact: 0

が完全一致検索では1つもレコードが見つからなかったことを表し ています。

unsplit: 1

が前方一致検索で1件ヒットしたことを表しています。

hits=1

が最終的にヒット数が1だということを表しています。

空白区切りでトークナイズされたデータに対し該当するトークン「だけ」マッチするようには groongaを--with-match-escalation-threshold=-1付きでconfigure してビルドするとそのような挙動にできます。

参考: match_escalation_threshold http://groonga.org/ja/docs/commands/select.html#match-escalation-threshold

この場合、groonga.logは以下のようになり、完全一致で1件もヒッ トしない場合でもそれ以上検索しなくなります。

2012-05-11 23:26:30.517740|i|933d9700|grn_ii_sel > (引火) 2012-05-11 23:26:30.517807|i|933d9700|exact: 0 2012-05-11 23:26:30.517835|i|933d9700|hits=0

ただ、それでは大変だと思うので、以下のように動的に match-escalation-thresholdの値を変えられるようにしておきます!

mysql> SET mroonga_match_escalation_threshold = -1;

Q: 検索スコアの数値の持つ意味について教えて下さい

A: 類似文書検索のスコアとなります。

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-June/000964.html, http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-October/001058.html )

スコアは以下のように算出しています。

(1) クエリをトークンに分割する (2) マッチしないトークンを除去する (3) トークン毎の重みを計算する (4) 重みが大きい上位nトークンを取り出す (5) 上位nトークンについて、トークンが出現する文書に重みを足す → すべての重みを足したものが各文書のスコア

例を使って説明します。ドキュメントと同じ以下のデータがあると します。

SET NAMES UTF8; CREATE TABLE diaries ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, content TEXT, FULLTEXT INDEX(content) ) ENGINE mroonga DEFAULT CHARSET UTF8;

INSERT INTO diaries (content) VALUES("明日の天気は晴れでしょう。"); INSERT INTO diaries (content) VALUES("明日の天気は雨でしょう。"); INSERT INTO diaries (content) VALUES("今日は晴れました。明日も晴れるでしょう。"); INSERT INTO diaries (content) VALUES("今日は晴れましたが、明日は雨でしょう。");

このとき、以下のように「今日の天気」で類似文書検索したとしま す。

SELECT *, MATCH (content) AGAINST ("今日の天気") FROM diaries WHERE MATCH (content) AGAINST ("今日の天気") ORDER BY MATCH (content) AGAINST ("今日の天気") DESC;

(1) まず、クエリ「今日の天気」をトークンに分割します。デフォ ルトではバイグラムで分割するので以下の4つのトークンになります。

  • 今日
  • 日の
  • の天
  • 天気

(2) 次に、マッチしないトークンを取り除きます。今回はすべての トークンがどれかの文書に含まれているのでここでは取り除かれま せん。

  • 今日: id=3,4に含まれる
  • 日の: id=1,2に含まれる
  • の天: id=1,2に含まれる
  • 天気: id=1,2に含まれる

(3) 次に、それぞれについて重みを計算します。

  • 今日: 262144 (= 1048576 / 4)
  • 日の: 209715 (= 1048576 / 5)
  • の天: 174762 (= 1048576 / 6)
  • 天気: 149796 (= 1048576 / 7)

(= ...)が重みの計算式です。 「1048576」(= 2 ** 20)は文書全体に含まれるトークン数を表し ています。本当はテーブルなどから情報を取得してくるなどして正 しい値を使いたいところですが、今のところ固定値になっています。 「/」の右辺の「4,5,6,7」は「トークンを含む文書がいくつあるか の概算値」です。本当はすべて「2」ですが、概算値なのでずれて います。

この式でしたいことは、「出現頻度が少ないトークン(= 重要語) の重みを高くする」です。

(もう少し細かいことを言うと、トークンが出現する毎に重みが1 増えます。が、ここでは1は誤差の範囲なので無視します。)

(4) 次に、重みが大きい上位nトークンを取り出します。 nは以下の式で求めています。

n = マッチしたトークン数 / 8 + 1

今回は「マッチしたトークン数」が4なので「4 / 8 + 1 = 1」で n = 1です。

マッチしたトークンを重み順に並び替えると以下の通りです。

  • 今日: 262144 (= 1048576 / 4)
  • 日の: 209715 (= 1048576 / 5)
  • の天: 174762 (= 1048576 / 6)
  • 天気: 149796 (= 1048576 / 7)

このうち上位1件なので

  • 今日: 262144 (= 1048576 / 4)

だけが残ります。

(5) 最後に、トークンが出現する文書に重みを足していき、文書の スコアとします。

  • 今日: id=3,4にマッチ

なので、文書id3,4がヒットし、スコアはどちらも262144です。 (↓の実行例で262144ではなく262145と1大きいのは(3)のところで 無視したトークンの出現回数がカウントされているからです。)

SELECT *, MATCH (content) AGAINST ("今日の天気") FROM diaries WHERE MATCH (content) AGAINST ("今日の天気") ORDER BY MATCH (content) AGAINST ("今日の天気") DESC; id content MATCH (content) AGAINST ("今日の天気") 3 今日は晴れました。明日も晴れるでしょう。 262145 4 今日は晴れましたが、明日は雨でしょう。 262145

以上が算出基準になります。

算出基準が分かれば、スコアから類似度(たとえばパーセンテージや0〜1の数値で表現)が出来ると考えているのですが、

トークン1つ毎の最大値は「1048576」と決まっているのですが、トー クンが複数マッチすることもあるため、残念ですが確実に0-1に収 める方法はありません。

ただ、スコアを大きな数(例えば、16777216 = 2 ** 24)で割るこ とである程度0-1に収めることができるのではないかと思います。

あるいは、logをとるのもよいかもしれません。

  SELECT *,
         MATCH (content) AGAINST ("今日の天気") AS score,
         LOG(MATCH (content) AGAINST ("今日の天気")) AS score_log,
         LOG10(MATCH (content) AGAINST ("今日の天気")) AS score_log10
         FROM diaries
         WHERE MATCH (content) AGAINST ("今日の天気")
         ORDER BY MATCH (content) AGAINST ("今日の天気") DESC;
  id    content score   score_log   score_log10
  3 今日は晴れました。明日も晴れるでしょう。    262145  12.476653064769005  5.4185415786504745
  4 今日は晴れましたが、明日は雨でしょう。   262145  12.476653064769005  5.4185415786504745

注意

2.02からMATCH AGAINST(... IN NATURAL LANGUAGE MODE)でフレーズ 検索ではなく類似文書検索をするようにしました。(IN NATURAL LANGUAGE MODEがデフォルトなのでMATCH AGAINST(...)ではこのモー ドになります。)

http://mroonga.github.com/ja/docs/news.html#release-2-02

  • [非互換][実験的] MATCH AGAINST IN NATURAL LANGUAGE MODE での検索方法をフレーズ検索から類似検索に変更した。

このため、スコアの数値が大きく変わっています。

Q: mroongaエンジンのdatetime型について教えて下さい

A: 以下の点が他のストレージエンジンと挙動が異なりますが、それ以外については同じ挙動 となります。

  • NULLが'1970-01-01 00:00:00'となる
  • 0月0日は1月1日に補正される

解説 (http://sourceforge.jp/projects/groonga/lists/archive/dev/2012-September/001037.html)

Q: mroonga のリストアの方法 を 教えてください。

A: mroonga関連テーブルをダンプして、問題発生時にmroonga関連テーブルとファイルも全削除後にダンプからリストアします。

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-February/001210.html, http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-February/001212.html)

mroonga関連のテーブルがすべて削除されてOKということであれば、*.mrnと*.mrn.xxxを手動で削除しても大丈夫です。ただし、その前にMySQLレベルでmroonga関連のテーブルをすべて削除してあるか確認してください。MySQLレベルにmroonga関連のテーブルの情報が残っ ているとうまくテーブルを作成したりできなくなりそうな気がします。 .mrnがgroongaのデータベースのメタデータを管理しているやつで、*.mrn.xxxが実データが入っているファイルなのですが、*.mrnは新しいテーブルを作成するときになかったら自動で作られるので手動で消しても大丈夫なのです

Q: mroonga の メモリ管理 について教えて下さい。

A:

  • FLUSH TABLESを実行すると groongaのメモリ を解放します。
  • sysctl -w vm.overcommit_memory=1

これを実行すると実メモリ以上の領域をmmapしようとしてもエラー にならなくなります。mmapしても使われなければエラーになりませ ん。(使われたらエラーになります。)

  • 仮想メモリのサイズの肥大については mmap(2)を使っているからなのであまり気にしなくても大丈夫です

解説 (http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-April/001294.html , http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-May/001386.html)

groongaはテーブルやカラムに対応したファイルをそれぞれ1つ作り、 そこにデータを格納します。ただ、ファイルサイズが1GBを超える と別のファイルを作り、そちらにもデータを保存します。別ファイ ルになったデータは必要になったときにmmapして利用します。つま り、必要になるまではメモリ上にロードされないということです。

groongaはデータベースを閉じるまでは一度mmapした領域をunmapし ません。mroongaで言えばFLUSH TABLESを実行するとgroongaのデー タベースを一度閉じています。

Q: mroongaストレージモードでのオートインクリメントの挙動が他のストレージエンジンと異なるのはなぜでしょうか。

A: MySQLのオートインクリメントの挙動は、全ストレージエンジンで共通という訳ではないからです。

解説 (http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-May/001377.html)

Q: mysqldがクラッシュした後mrnファイルがロックされた場合、インデックスの再構築以外にロックを解除させる方法はないでしょうか?

A: 単にロックが残っているだけであれば、以下のSQLでロックを解除できます。

mysql> SELECT mroonga_command("clearlock");

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-May/001402.html )

ただし、ロックが残っているだけではなく、データベースに不整合 が発生している場合はインデックスを再構築しないといけません。

なお、「***.mrn.001」がロックされているときはデータベース内の オブジェクト名(テーブル名やカラム名)を管理している内部のテー ブルキーがロックを持っている状態になります。このときは、ラッ パーモードであれば、

  • mysqldを終了
  • 「*.mrn*」ファイルを全て削除
  • mysqldを起動
  • disable keys
  • enable keys

Q: ラッパーモードにおけるmrnファイルをロストしたときの全文インデックス再構築方法について教えて下さい

A:

  1. データベースにmroongaのテーブルが1つもなく、*.mrnファイルが存在しない場合、まず、適当なmroongaのテーブルを1つ作ります。
  2. select mroonga_command('table_create '); でmroongaのテーブルリストに、対象のテーブルを作ります。これにより、データにアクセスできるようになり、selectやalter tableが通るようになります。
  3. alter table disable keys;→enable keysもしくは、repair tableにより、全文インデックスを再構築します。

解説 ( http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-July/001543.html )

Q: mroongaのトークナイザーの挙動 について教えて下さい

A: 隔週連載groongaでお馴染み吉田さんがこのあたりtokenizeコマンドについても解説記事を書いてくれています。

「groonga/mroongaのトークナイザー(tokenizer)の挙動を追ってみる」 http://y-ken.hatenablog.com/entry/mroonga-tokenizer-behavior

解説 (http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-August/001566.html)

groongaでどうトークナイズされるかというのであれば、そのものずばりtokenizeコマンドがあります。 myisam_ftdumpみたいに統計だとか一覧としては出せませんが。。。

http://groonga.org/ja/docs/reference/commands/tokenize.html

mroongaでやるにはmroonga_commandというのもあって、以下のような感じで groongaのtokenizeコマンドを叩けます。

select mroonga_command("tokenize ....");

というわけで、.mrnファイルをgroongaのselect..で取り出して自前でパースよりかは楽できます。:-)

Q: ベクターカラムに対してオフラインインデックス構築できますか?

A: ベクターカラムへの全文検索用のインデックスはサポートしていません。代わりに、ベクターカラムに入れた値を文字列にしたものを別のカラムに入れてそれに対して全文検索用のインデックスを構築してください。

解説 (http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-September/001783.html)

実は、ベクターカラムへの全文検索用のインデックスはサポートし ていないのです。オンラインインデックス構築で動くのはたまたま なのです。

(mroongaではなく)groongaには入力値をいい感じにキャストして 値を保存する機能があります。ベクターカラムに対して文字列を指 定するといい感じにベクターに分割して保存するのもこの機能を使っ ています。

オンラインインデックス構築では入力値を使ってインデックスを構 築します。今回の場合だと"Linux MySQL groonga"などといった文字 列を使います。

オフラインインデックス構築では保存された値を使ってインデック スを構築します。今回の場合だと["Linux", "MySQL", "groonga"]な どといったベクターを使います。

全文検索用のインデックスを作成するにはトークナイズ対象の文字 列が必要です。

ベクターカラムに文字列を入力として値を保存している場合は、オ ンラインインデックス構築のときは文字列を用意できます。しかし、 ベクターの値を入力としていればオンラインインデックス構築でも 文字列を用意できません。(SQLからはベクターの値を入力とはでき ません。groongaのloadコマンドを使えばできます。)

また、オフラインインデックス構築のときはベクターになった値し か持っていないので文字列を用意できません。

そのためベクターカラムの全文検索用のインデックスはサポートし ていません。

Q: mroonga に メモリーリークの疑いがあるのですが、どうすれば確認できますでしょうか?

A:

  • mroonga_command("status")して、その中に、alloc_countっていう値が入っているんですが、それが増えていっていたらmroongaというかgroongaのメモリーリークが怪しいです。
  • 実行時間を短くしても再現しているなら、ちょっと動かしてvalgrindの結果を確認する。

解説(http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-September/001841.html)

#9 Updated by Kenji Maruyama over 4 years ago

#10 Updated by Kouhei Sutou over 4 years ago

わかりました!

#11 Updated by Kentoku SHIBA over 4 years ago

類似文書検索のスコアの解説について、英語版を対応(できれば早めに)して頂くことはできますでしょうか?

#12 Updated by Kenji Maruyama over 4 years ago

#11

  • もしローカライズ得意な方がいればお願いしたいですが、私でよければ少々時間かかりますが、それでよければ優先的に対応いたします。

  • 作業的には類似文書検索のスコア のまとめを優先的に先に日本語対応して、レビュー後に英語に対応する予定でしたが、ローカライズは翻訳だけでなく、以下検索例のローカライズ と 他の 文書の整合性 もありますね。

#13 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

  • もしローカライズ得意な方がいればお願いしたいですが、私でよければ少々時間かかりますが、それでよければ優先的に対応いたします。

得意な人はいないので、よろしくお願いします!

  • 作業的には類似文書検索のスコア のまとめを優先的に先に日本語対応して、レビュー後に英語に対応する予定でしたが、ローカライズは翻訳だけでなく、以下検索例のローカライズ と 他の 文書の整合性 もありますね。


検索例は、CJKが関係ないところは英語のデータで、CJKが関係あるところは英語の説明の中でも日本語のデータを使うのがよいと思います!

あと、たぶん、翻訳ではなくて、新規にドキュメントを作ることになります!

あと、あと、たぶん、IN BOOLEAN MODE(類似文書検索じゃないGoogle検索みたいな検索)の説明も新規で必要になります。

#14 Updated by Kenji Maruyama over 4 years ago

得意な人はいないので、よろしくお願いします!

わかりました。

検索例は、CJKが関係ないところは英語のデータで、CJKが関係あるところは英語の説明の中でも日本語のデータを使うのがよいと思います!

CJKが関係あるところで日本語のデータを使って説明は日本語がわからない前提でするのは難しそうですね。(個人的には欧米圏の方は英語のデータ(CJK無関係) での説明で十分かと考えていました。CJK関係あるところは、日本語のドキュメントへのリンクを貼る、誘導するなりして、日本語が分かる人は日本語のドキュメントを読めば良いと考えていました。)

あと、あと、たぶん、IN BOOLEAN MODE(類似文書検索じゃないGoogle検索みたいな検索)の説明も新規で必要になります。

このIN BOOLEAN MODE 時 の 説明というのは、"重み付けと全文検索 : http://qiita.com/groonga/items/8bcd5f9647f62b96584f の説明"で よろしいですか。

#15 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

得意な人はいないので、よろしくお願いします!


わかりました。

ありがとうございます!

検索例は、CJKが関係ないところは英語のデータで、CJKが関係あるところは英語の説明の中でも日本語のデータを使うのがよいと思います!


CJKが関係あるところで日本語のデータを使って説明は日本語がわからない前提でするのは難しそうですね。(個人的には欧米圏の方は英語のデータ(CJK無関係) での説明で十分かと考えていました。CJK関係あるところは、日本語のドキュメントへのリンクを貼る、誘導するなりして、日本語が分かる人は日本語のドキュメントを読めば良いと考えていました。)

うーん、そうすると、MariaDBの人など英語圏の人(日本語を読めない人)にMroongaの存在意義を伝えられないのではないかと心配になりました。MariaDBまたはInnoDBのFTSで十分と思われるようであれば、Mroongaは別にいらないと思われてしまうことを心配しています。

心配し過ぎかしら。。。

あと、あと、たぶん、IN BOOLEAN MODE(類似文書検索じゃないGoogle検索みたいな検索)の説明も新規で必要になります。


このIN BOOLEAN MODE 時 の 説明というのは、"重み付けと全文検索 : http://qiita.com/groonga/items/8bcd5f9647f62b96584f の説明"で よろしいですか。

それも含みますが、もっと基本的なことも含んでいるつもりでした。たとえば、「A B」と書けば「A」または「B」を含む文書を検索とか、MySQLでは http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html にあるようにいろんな操作があるけど、Mroongaはどれをサポートしてどれをサポートしていないかとか、同じ機能でも挙動の違いはあるのかとか、プラグマなどMroonga固有の機能とか、そういうもっと全体的なことを考えていました。

#16 Updated by Kenji Maruyama over 4 years ago

うーん、そうすると、MariaDBの人など英語圏の人(日本語を読めない人)にMroongaの存在意義を伝えられないのではないかと心配になりました。MariaDBまたはInnoDBのFTSで十分と思われるようであれば、Mroongaは別にいらないと思われてしまうことを心配しています。

なるほど。MroongaのうりがCJKにも対応ならば、日本語を読めない人に日本語の文法、意味を説明するよりも、日本語(中国語、韓国語)のデータと説明とを載せて、日本語を読めない人には対応しているぞ!ということだけを説明できれば良いかと思いました。CJK対応はその言語を扱える人しか結局扱わないので、CJK読めるかどうかもわからない欧米圏の人達に説明するよりもむしろアジア圏の人達に使ってもらえるように中国語、韓国語のページを充実させた方がよいのではないかと思いました。

それも含みますが、もっと基本的なことも含んでいるつもりでした。たとえば、「A B」と書けば「A」または「B」を含む文書を検索とか、MySQLでは http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html にあるようにいろんな操作があるけど、Mroongaはどれをサポートしてどれをサポートしていないかとか、同じ機能でも挙動の違いはあるのかとか、プラグマなどMroonga固有の機能とか、そういうもっと全体的なことを考えていました。

これは 類似文書検索のスコアの解説 とは 別のドキュメントの方がよいですよね。それとも,類似文書検索のスコアの解説 がこれに含まれる感じ ですか。話が膨らむと、斯波さんの (できれば早めに) が 延びていきそうです。。。とりあえず 類似文書検索のスコアの解説 の CJK なし の説明から 書き始めることにします。 説明の足りない所をあとから追加編集という感じでどうでしょうか。

#17 Updated by Kenji Maruyama over 4 years ago

とりあえず 類似文書検索のスコアの解説 の CJK なし の説明から 書き始めることにします。 説明の足りない所をあとから追加編集という感じでどうでしょうか。

wikiに ページ作りました。: http://redmine.groonga.org/projects/mroonga/wiki/Search_and_Scoring_in_Mroonga?parent=Index

#18 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

うーん、そうすると、MariaDBの人など英語圏の人(日本語を読めない人)にMroongaの存在意義を伝えられないのではないかと心配になりました。MariaDBまたはInnoDBのFTSで十分と思われるようであれば、Mroongaは別にいらないと思われてしまうことを心配しています。


なるほど。MroongaのうりがCJKにも対応ならば、日本語を読めない人に日本語の文法、意味を説明するよりも、日本語(中国語、韓国語)のデータと説明とを載せて、日本語を読めない人には対応しているぞ!ということだけを説明できれば良いかと思いました。CJK対応はその言語を扱える人しか結局扱わないので、CJK読めるかどうかもわからない欧米圏の人達に説明するよりもむしろアジア圏の人達に使ってもらえるように中国語、韓国語のページを充実させた方がよいのではないかと思いました。

なるほど。中国語、韓国語のページを充実させるというのは考えつきませんでした。たしかにそれは一理あると思います。

ただ、中国語、韓国語のページを用意するのはかなりハードルが高そうだなぁと思いました。今のところ、私たちは誰も使えないので。

欧米圏の人に英語で説明するよりも、CJKを使う日本語以外の人向けに英語で説明する、というのが現実的のように思えてきました。

それも含みますが、もっと基本的なことも含んでいるつもりでした。たとえば、「A B」と書けば「A」または「B」を含む文書を検索とか、MySQLでは http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html にあるようにいろんな操作があるけど、Mroongaはどれをサポートしてどれをサポートしていないかとか、同じ機能でも挙動の違いはあるのかとか、プラグマなどMroonga固有の機能とか、そういうもっと全体的なことを考えていました。


これは 類似文書検索のスコアの解説 とは 別のドキュメントの方がよいですよね。それとも,類似文書検索のスコアの解説 がこれに含まれる感じ ですか。話が膨らむと、斯波さんの (できれば早めに) が 延びていきそうです。。。とりあえず 類似文書検索のスコアの解説 の CJK なし の説明から 書き始めることにします。 説明の足りない所をあとから追加編集という感じでどうでしょうか。

別でよいと思います!追加編集でよいと思います!

参考までにですが。。。

現在は、類似文書検索よりよく使われるだろうBOOLEAN MODEのドキュメントがないので、ユーザーにとってみればBOOLEAN MODEの情報の方が有用だと思います。

#19 Updated by Kenji Maruyama over 4 years ago

欧米圏の人に英語で説明するよりも、CJKを使う日本語以外の人向けに英語で説明する、というのが現実的のように思えてきました。

同感です。

現在は、類似文書検索よりよく使われるだろうBOOLEAN MODEのドキュメントがないので、ユーザーにとってみればBOOLEAN MODEの情報の方が有用だと思います。

ありがとうございます。BOOLEAN MODE も優先順位あげておきます。

#20 Updated by Kenji Maruyama over 4 years ago

不明点が3点 4点 あります。

"Q: 検索スコアの数値の持つ意味について教えて下さい" のところで、以下に出てくる 概算値 はどこかで簡単に確認できるものでしょうか。 というのも、英語ドキュメント ( http://redmine.groonga.org/projects/mroonga/wiki/Search_and_Scoring_in_Mroonga ) の例で ここの所について 説明が書けないでいます。

(3) 次に、それぞれについて重みを計算します。

    今日: 262144 (= 1048576 / 4)
    日の: 209715 (= 1048576 / 5)
    の天: 174762 (= 1048576 / 6)
    天気: 149796 (= 1048576 / 7)

(= ...)が重みの計算式です。 「1048576」(= 2 ** 20)は文書全体に含まれるトークン数を表しています。 本当はテーブルなどから情報を取得してくるなどして正しい値を使いたいところですが、今のところ固定値になっています。 「/」の右辺の「4,5,6,7」は「トークンを含む文書がいくつあるかの概算値」です。 本当はすべて「2」ですが、概算値なのでずれています。

Wプラグマの演算子のところで、以下のスキーマとデータを用いて http://qwik.jp/senna/query.html の 演算子 が使える仮定で試してみました。

CREATE TABLE books (
  `id` INTEGER AUTO_INCREMENT,
  `title` text,
  `comment` text,
  PRIMARY KEY(`id`),
  FULLTEXT INDEX content_index (title, comment)
) engine=mroonga default charset utf8;

INSERT INTO books (title, comment) VALUES ('[groonga入門]', 'groongaの初歩的な内容のみ。');
INSERT INTO books (title, comment) VALUES ('[mroonga入門]', 'mroongaの初歩的な内容のみ。groongaについ>ても触れている。');
INSERT INTO books (title, comment) VALUES ('[実践groonga - groonga入門の次のステップ]', '入門を卒業し>たら読む本。');
INSERT INTO books (title, comment) VALUES ('[実践rroonga]', '入門の次に読むべき本。すぐに使える実践的>な内容が売り。');
INSERT INTO books (title, comment) VALUES ('[mroongaのレシピ]', '入門の次に読むべき実践的な本');
INSERT INTO books (title, comment) VALUES ('[groongaのレシピ]', 'いわゆるレシピブック。');

  • OR groonga と書くと、以下となります。
failed to parse fulltext search keyword: <*W0:10,1:1 OR groonga>: <Syntax error! (OR groonga)>

くっつけるとOK ですが、これは仕様的には正しいでしょうか?

SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 ORgroonga' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 ORgroonga' IN BOOLEAN MODE) DESC;
  • 以下の演算子らを使おうとすると、failed to parse fulltext search keyword となりました。これは仕様的には正しいでしょうか? それとも使い方が間違っているのか。。。
SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 ~groonga' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 ~groonga' IN BOOLEAN MODE) DESC;

SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 <groonga' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 <groonga' IN BOOLEAN MODE) DESC;

SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 >groonga' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 >groonga' IN BOOLEAN MODE) DESC;

SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 *S[1]"groonga"' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 *S[1]"groonga"' IN BOOLEAN MODE) DESC;

SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 *N[1]"groonga"' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 *N[1]"groonga"' IN BOOLEAN MODE) DESC;

mroongaエンジンのdatetime型 の 0月0日 は 1月1日 に補正されます。のところで、スキーマと データはhttp://redmine.groonga.org/projects/mroonga/wiki/%E5%88%A9%E7%94%A8%E8%80%85%E5%90%91%E3%81%91_FAQ/edit?section=4 の設定、mysqld_safe モードですと、

INSERT INTO diaries (uptime) VALUES('99/00/00 00:00:00');

でmysqld_safe mysqld restarted になってしまいます。mysqld ですと問題なしですが。

2013/11/19 追加

SELECT * FROM books WHERE
MATCH (title) AGAINST('*D- 入門' IN BOOLEAN MODE) ORDER BY
MATCH (title) AGAINST('*D- 入門' IN BOOLEAN MODE) DESC;

すると、以下のように否定になっていないように見えます。

id  title
1   [groonga入門]
2   [mroonga入門]
3   [実践groonga - groonga入門の次のステップ]

#21 Updated by Kouhei Sutou over 4 years ago

Redmineからdiffが流れないので同じコメントを編集して追記するのではなく、新しいコメントにしてもらえるとうれしいです><

#22 Updated by Kenji Maruyama over 4 years ago

#21

了解です。

#23 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

"Q: 検索スコアの数値の持つ意味について教えて下さい" のところで、以下に出てくる 概算値 はどこかで簡単に確認できるものでしょうか。 というのも、英語ドキュメント ( http://redmine.groonga.org/projects/mroonga/wiki/Search_and_Scoring_in_Mroonga ) の例で ここの所について 説明が書けないでいます。

簡単には確認できません!

Groongaのselectコマンドでインデックスを出力すれば確認できます。

mysql> SELECT mroonga_command("select diaries-content --query '_key:fine OR _key:today'--output_columns _key,index --limit -1") AS groonga_response;
+---------------------------------------------------------------------------+
| groonga_response                                                          |
+---------------------------------------------------------------------------+
| [[[2],[["_key","ShortText"],["index","diaries"]],["FINE",9],["TODAY",8]]] |
+---------------------------------------------------------------------------+
1 row in set (0.01 sec)

↑の場合、FILEが9でTODAYが8です。

Wプラグマの演算子のところで、以下のスキーマとデータを用いて http://qwik.jp/senna/query.html の 演算子 が使える仮定で試してみました。

Wプラグマには演算子はしていできません!Dプラグマと混ざっている気がします!

  • OR groonga と書くと、以下となります。

failed to parse fulltext search keyword: <*W0:10,1:1 OR groonga>: <Syntax error! (OR groonga)>

くっつけるとOK ですが、これは仕様的には正しいでしょうか?


SELECT * FROM books WHERE
MATCH (title,comment) AGAINST('*W0:10,1:1 ORgroonga' IN BOOLEAN MODE) ORDER BY
MATCH (title,comment) AGAINST('*W0:10,1:1 ORgroonga' IN BOOLEAN MODE) DESC;

はい、正しいです。

「*W0:10,1:1 OR groonga」はプラグマを抜くと「OR groonga」になり、Groongaでは左辺のないORはエラーになるので、「Syntax error! (OR groonga)」となるのは正しいです。

「*W0:10,1:1 ORgroonga」はプラグマを抜くと「ORgroonga」になり、「ORgroonga」という1つの単語で検索ということになる(「OR」というキーワードがあるとは認識されない)ので、エラーにならないのは正しいです。

  • 以下の演算子らを使おうとすると、failed to parse fulltext search keyword となりました。これは仕様的には正しいでしょうか? それとも使い方が間違っているのか。。。

はい、正しいです。未実装なのです。

mroongaエンジンのdatetime型 の 0月0日 は 1月1日 に補正されます。のところで、スキーマと データはhttp://redmine.groonga.org/projects/mroonga/wiki/%E5%88%A9%E7%94%A8%E8%80%85%E5%90%91%E3%81%91_FAQ/edit?section=4 の設定、mysqld_safe モードですと、


INSERT INTO diaries (uptime) VALUES('99/00/00 00:00:00');

でmysqld_safe mysqld restarted になってしまいます。mysqld ですと問題なしですが。

むむ。クラッシュしているかもしれません。

2013/11/19 追加



SELECT * FROM books WHERE
MATCH (title) AGAINST('*D- 入門' IN BOOLEAN MODE) ORDER BY
MATCH (title) AGAINST('*D- 入門' IN BOOLEAN MODE) DESC;

すると、以下のように否定になっていないように見えます。


id title
1 [groonga入門]
2 [mroonga入門]
3 [実践groonga - groonga入門の次のステップ]

2つ以上語を指定しないといけない気がします。

#24 Updated by Kenji Maruyama over 4 years ago

ありがとうございます。

Groongaのselectコマンドでインデックスを出力すれば確認できます。

なるほど。こういう呼び出し方できるんですね。

Wプラグマには演算子はしていできません!Dプラグマと混ざっている気がします!

Wプラグマと Dプラグマ と MySQL ブール全文検索の機能でサポートしている演算子 hhttp://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html と 同じ演算子 が使える(未実装な演算子あり) の 3種類 があるんですね。

「*W0:10,1:1 OR groonga」はプラグマを抜くと「OR groonga」になり、Groongaでは左辺のないORはエラーになるので、「Syntax error! (OR groonga)」となるのは正しいです。

すみません。こんなボケボケな質問に答えて頂いて。。。OR でこんな使い方しませんよね。。。

未実装なのです。

了解です。

2つ以上語を指定しないといけない気がします。

使い方を間違っていました。一つの語でもいけました。Dプラグマと演算子-をつける必要ありですね。結果も予想通りの結果になりました。

SELECT * FROM books WHERE
MATCH (title) AGAINST('*D- -groonga' IN BOOLEAN MODE) ORDER BY
MATCH (title) AGAINST('*D- -groonga' IN BOOLEAN MODE) DESC;

id  title
2   [mroonga入門]
4   [実践rroonga]
5   [mroongaのレシピ]

#25 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

すみません。こんなボケボケな質問に答えて頂いて。。。OR でこんな使い方しませんよね。。。

いえいえ!

2つ以上語を指定しないといけない気がします。


使い方を間違っていました。一つの語でもいけました。Dプラグマと演算子-をつける必要ありですね。結果も予想通りの結果になりました。


SELECT * FROM books WHERE
MATCH (title) AGAINST('*D- -groonga' IN BOOLEAN MODE) ORDER BY
MATCH (title) AGAINST('*D- -groonga' IN BOOLEAN MODE) DESC;
id title
2 [mroonga入門]
4 [実践rroonga]
5 [mroongaのレシピ]

む。これなら「*D-」を削って「-groonga」だけでも同じ結果になりませんか?

あ、「-XXX」みたいに「XXX」が含まれていないレコード全部、というクエリーは重いので、気を付けて使ってね!と注意書きを入れておいてもらえるとうれしいです!(最初にすべてのレコードを用意して、そこからマッチしたレコードを抜く、みたいな動きになるので、レコード数が多いとその分時間がかかります。)

#26 Updated by Kenji Maruyama over 4 years ago

む。これなら「*D-」を削って「-groonga」だけでも同じ結果になりませんか?

なります。となると、*D- A B で使えということでしょうか。その場合期待する挙動はどうなりますでしょうか。

#27 Updated by Kenji Maruyama over 4 years ago

あ、「-XXX」みたいに「XXX」が含まれていないレコード全部、というクエリーは重いので、気を付けて使ってね!と注意書きを入れておいてもらえるとうれしいです!

了解です。

#28 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

む。これなら「*D-」を削って「-groonga」だけでも同じ結果になりませんか?


なります。となると、*D- A B で使えということでしょうか。その場合期待する挙動はどうなりますでしょうか。

「A - B」だと思います!

#29 Updated by Kenji Maruyama over 4 years ago

「A - B」だと思います!

ありがとうございます。 実際に http://redmine.groonga.org/projects/mroonga/wiki/%E5%88%A9%E7%94%A8%E8%80%85%E5%90%91%E3%81%91_FAQ の Q: boolean modeでのプラグマ指定で対応しているのは? にあるような データで実行してみると、「*D- A B」の使い方間違っていなければ「*DOR A B」と同じ挙動 になりました。

ha_mroonga.cpp を見てみると、同じ GRN_OP_OR になっているようです。

 7574   } else if (keyword_length >= 1 && keyword[0] == '-') {
 7575     *default_operator = GRN_OP_OR;
 7576     *consumed_keyword_length = 1;
 7577   } else if (keyword_length >= 2 && memcmp(keyword, "OR", 2) == 0) {
 7578     *default_operator = GRN_OP_OR;
 7579     *consumed_keyword_length = 2;

#30 Updated by Kenji Maruyama over 4 years ago

  • Q: ベクターカラムに対してオフラインインデックス構築できますか? の 答えとして、ベクターカラムに入れた値を文字列にしたものを別のカラムに入れてそれに対して全文検索用のインデックスを構築してください。の サンプルとして、

http://qiita.com/groonga/items/f41cd8cfbe7bd158d5da

を参考にしましたが、このまま実行すると

ERROR 1191 (HY000) at line 22: Can't find FULLTEXT index matching the column list

になるようです。

CREATE TABLE Bugs (
  id INT PRIMARY KEY AUTO_INCREMENT,
  tags TEXT COMMENT 'flags "COLUMN_VECTOR", type "Tags"',
  FULLTEXT INDEX(tags) <=== ここが抜けているっぽいです。
) DEFAULT CHARSET=utf8;

#31 Updated by Kenji Maruyama over 4 years ago

#30

補足: mroonga 3.09, mysql 5.6.14-debug Source distribution

#32 Updated by Kenji Maruyama over 4 years ago

#31 と同じ環境にて

  • ドキュメントの mroonga のリストアのサンプルを作っているときに、ストレージエンジンmroongaを使ったデータベースを
mysqldump -uroot mrn_sample > dumpfile.sql 

すると、mysqld が落ちて再起動する。

mysqldump: Got error: 2013: Lost connection to MySQL server during query when using LOCK TABLES
  • スキーマとデータは以下
USE mrn_sample;
DROP TABLE IF EXISTS diaries;
SET NAMES UTF8;
CREATE TABLE diaries (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    content TEXT,
    FULLTEXT INDEX(content) )
    ENGINE mroonga DEFAULT CHARSET UTF8;

INSERT INTO diaries (content) VALUES("明日の天気は晴れでしょう。");
INSERT INTO diaries (content) VALUES("明日の天気は雨でしょう。");
INSERT INTO diaries (content) VALUES("今日は晴れました。明日も晴れるでしょう。");
INSERT INTO diaries (content) VALUES("今日は晴れましたが、明日は雨でしょう。");
  • ちなみに innodb engine を使った スキーマ ですと、同じように mysqldump しても 普通にできます。
  • また、mysqldump --single-transaction -uroot mrn_sample > dumpfile.sql とすると、ダンプできますが、ダンプされたsql内に LOCK TABLES と UNLOCK TABLES の行があり、これをコメントアウトしないと 今度はリストア時に落ちます。mroonga ストレージモードはトランザクションサポートしていないので、このダンプの方法よろしくないのですが。。。

#33 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

「A - B」だと思います!


ありがとうございます。
実際に http://redmine.groonga.org/projects/mroonga/wiki/%E5%88%A9%E7%94%A8%E8%80%85%E5%90%91%E3%81%91_FAQ の Q: boolean modeでのプラグマ指定で対応しているのは? にあるような データで実行してみると、「*D- A B」の使い方間違っていなければ「*DOR A B」と同じ挙動 になりました。


ha_mroonga.cpp を見てみると、同じ GRN_OP_OR になっているようです。


7574 } else if (keyword_length >= 1 && keyword[0] == '-') {
7575 *default_operator = GRN_OP_OR;
7576 *consumed_keyword_length = 1;
7577 } else if (keyword_length >= 2 && memcmp(keyword, "OR", 2) == 0) {
7578 *default_operator = GRN_OP_OR;
7579 *consumed_keyword_length = 2;

これは… 実装を直した方がよい気がしました!

あと、「*D- A +B C」は「-A +B -C」という挙動でよい気がしてきました!

http://qwik.jp/senna/query.html によると、Dは「演算子の既定値(演算子を省略した場合にどの演算を行うか)を指定します。」ということなので、演算子を指定していないときは「-」を付けるのが自然な気がしてきました。

#34 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

  • Q: ベクターカラムに対してオフラインインデックス構築できますか? の 答えとして、ベクターカラムに入れた値を文字列にしたものを別のカラムに入れてそれに対して全文検索用のインデックスを構築してください。の サンプルとして、

http://qiita.com/groonga/items/f41cd8cfbe7bd158d5da


を参考にしましたが、このまま実行すると


ERROR 1191 (HY000) at line 22: Can't find FULLTEXT index matching the column list

になるようです。


CREATE TABLE Bugs (
id INT PRIMARY KEY AUTO_INCREMENT,
tags TEXT COMMENT 'flags "COLUMN_VECTOR", type "Tags"',
FULLTEXT INDEX(tags) <=== ここが抜けているっぽいです。
) DEFAULT CHARSET=utf8;

ありがとうございます!追加しました!

#35 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

#31 と同じ環境にて


  • ドキュメントの mroonga のリストアのサンプルを作っているときに、ストレージエンジンmroongaを使ったデータベースを

mysqldump -uroot mrn_sample > dumpfile.sql

すると、mysqld が落ちて再起動する。


mysqldump: Got error: 2013: Lost connection to MySQL server during query when using LOCK TABLES
  • スキーマとデータは以下

USE mrn_sample;
DROP TABLE IF EXISTS diaries;
SET NAMES UTF8;
CREATE TABLE diaries (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
content TEXT,
FULLTEXT INDEX(content) )
ENGINE mroonga DEFAULT CHARSET UTF8;
INSERT INTO diaries (content) VALUES("明日の天気は晴れでしょう。");
INSERT INTO diaries (content) VALUES("明日の天気は雨でしょう。");
INSERT INTO diaries (content) VALUES("今日は晴れました。明日も晴れるでしょう。");
INSERT INTO diaries (content) VALUES("今日は晴れましたが、明日は雨でしょう。");
  • ちなみに innodb engine を使った スキーマ ですと、同じように mysqldump しても 普通にできます。
  • また、mysqldump --single-transaction -uroot mrn_sample > dumpfile.sql とすると、ダンプできますが、ダンプされたsql内に LOCK TABLES と UNLOCK TABLES の行があり、これをコメントアウトしないと 今度はリストア時に落ちます。

これはバグだと思うので、別チケットをたてましょう!

#36 Updated by Kouhei Sutou over 4 years ago

「*D-」も別チケットがいいですね!

#37 Updated by Kouhei Sutou over 4 years ago

ところで、現在は、このチケットの作業はどんな感じで進めているか教えてもらってもよいでしょうか!? (残作業をどのような手順で進めるかと、それぞれの手順にどのくらいかかりそうか、があるとうれしそうな気がします。)

個人的にはずっとWikiでやっているのではなく、まとまったものから順次公式ドキュメントの方に取り込んでいくのがいいんじゃないかと思っています。そうすれば、Mroongaは毎月リリースされているので、まとまったものをすぐにユーザーが利用できるようになるからです。

#38 Updated by Kenji Maruyama over 4 years ago

個人的にはずっとWikiでやっているのではなく、まとまったものから順次公式ドキュメントの方に取り込んでいくのがいいんじゃないかと思っています。

了解しました。すべて一回書いたあとにレビューして頂く予定でしたが、まとまっているものと分けると、現状は以下になっています。

  • 利用者向け FAQ 80%
    • 今後、 *D- の実行例 を除いてレビューして頂いて、OKでしたら、公式ドキュメント(git) の方に移す。
  • Search and Scoring in Mroonga 30%
    • CJK なしのドキュメント 80%
      • レビューして頂いて、OKでしたら、公式ドキュメント(git) の方に移す。
    • CJK ありのドキュメント 0%
      • 着手する
    • Boolean モード の説明 (InnoDB FTS との機能比較) 20%
      • InnoDB FTS の機能調査
  • 開発者向け 0%
    • 着手する

#39 Updated by Kouhei Sutou over 4 years ago

Kenji Maruyama wrote:

個人的にはずっとWikiでやっているのではなく、まとまったものから順次公式ドキュメントの方に取り込んでいくのがいいんじゃないかと思っています。


了解しました。すべて一回書いたあとにレビューして頂く予定でしたが、まとまっているものと分けると、現状は以下になっています。

整理してもらってありがとうございます!

  • 利用者向け FAQ 80%
    • 今後、 *D- の実行例 を除いてレビューして頂いて、OKでしたら、公式ドキュメント(git) の方に移す。

FAQは項目が多いので、1つずつチケットを切りましょうか!1つの項目が調整中のためすべてのFAQが公式ドキュメントに移らなくなると切ないので。

  • Search and Scoring in Mroonga 30%
    • CJK なしのドキュメント 80%
      • レビューして頂いて、OKでしたら、公式ドキュメント(git) の方に移す。

これも、これ用のチケットを切ってそっちで進めましょう!

  • CJK ありのドキュメント 0%
    • 着手する
  • Boolean モード の説明 (InnoDB FTS との機能比較) 20%
    • InnoDB FTS の機能調査
      • 開発者向け 0%
  • 着手する

これらはできた都度チケットを切っていきましょう!

#40 Updated by Kenji Maruyama over 4 years ago

#39

了解です。レビューのためのチケット切って行きます。

#41 Updated by Kenji Maruyama over 4 years ago

現在は、類似文書検索よりよく使われるだろうBOOLEAN MODEのドキュメントがないので、ユーザーにとってみればBOOLEAN MODEの情報の方が有用だと思います。

まず日本語版を書いて、レビュー後 英語版にという流れを考えています。wiki ページを作りました。

http://redmine.groonga.org/projects/mroonga/wiki/Mroonga_full_text_Search_in_Boolean_mode?parent=Index

cjk をおける全文検索のドキュメントも 同じ流れでまず日本語版を作りたいと思います。 wiki ページは以下です。

http://redmine.groonga.org/projects/mroonga/wiki/Mroonga_Search_with_Chinese_Japanese_and_Korean_language_documents?parent=Index

Also available in: Atom PDF