0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Mroongaで凝ったNormalizeをしたときのsnippet取得

Last updated at Posted at 2020-11-30

※頂いたコメントを元に改訂予定です。必ずコメントまで読んで下さい (2020-12-01)

Mroongaの文字列正規化はオプション豊富な NFKC100 があって、いい感じの手広く当てにいく検索インデックスを作れます。

MroongaのNormalizer/Tokenizer/TokenFilter 2020-02-25

以前の記事で採用した例

  • 長音記号を正規化
  • 中点を"·" (U+00B7 MIDDLE DOT)に正規化
  • "ヴァヴィヴヴェヴォ"を"バビブベボ"に正規化
  • 全角ひらがな、全角カタカナ、半角カタカナの文字を同一視
  • かなカナの小さな文字を大きな文字と同一視
  • ハイフンを"-" (U+002D HYPHEN-MINUS)に正規化

Mroonga には UDF として mroonga_snippet_html(document, key_word) が実装されていて、簡単にGoogleみたいな検索結果画面をつくれます。
※「実験的機能」の但し書きつき

MroongaByGoogle.png

document の中から key_word を含む周辺のテキストを切り取って、 key_word 部分を強調表示のmark-upをつけて返してくれます。

しかし、mroonga_snippet_html の中で document 中の key_word を探すときにはデフォールトのアルファベット大小同一程度の正規化処理になっているようで、インデックス作成時に NFKC100 を使っていると空振りすることがあります。

「バイオリン」でdocument中の「ヴァイオリン」にヒットしたのに、snippet が出てこないとかです。

Mroonga v10.07 (2020-10-02)まで

インデクシング時に NFKC100 で凝った正規化をしたなら、 mroonga_snippet_html の引数にはどちらも、同様の正規化変換をした文字列を与える必要があります。

同じく UDF で mroonga_normalize(string, normalizer_name) があるのですが、これに NFKC100 のオプションをつけて実行する方法がわかりませんでした。

FULLTEXT INDEX につけてるのはこんな感じですから。

normalizer "NormalizerNFKC100(
   \'unify_prolonged_sound_mark\', true,
   \'unify_middle_dot\', true,
   \'unify_katakana_v_sounds\', true)"
,
  token_filters "TokenFilterNFKC100(
   \'unify_kana\', true,
   \'unify_kana_case\', true,
   \'unify_hyphen\', true)"

そういうときには、一段抽象化を下げて、汎用の mroonga_command で groonga command を使います。

SELECT mroonga_command('normalize \'NormalizerNFKC100(
"unify_prolonged_sound_mark", true,
"unify_middle_dot", true, 
"unify_katakana_v_sounds", true)\' "ヴァイオリン"');

{"normalized":"バイオリン","types":[],"checks":[]}

JSONで返ってくるので、SQLの中での取り回しがちょっと難しいです。ホスト言語(ここの場合はJava)で取り回すことにします。

// NormalizeオプションはFULLTEXT INDEXの定義に合わせること
private static final String MROONGA_NORMALIZER = "normalize 'NormalizerNFKC100(" +
			"\"unify_prolonged_sound_mark\", true," +
			"\"unify_middle_dot\", true, " +
			"\"unify_katakana_v_sounds\", true)' \"";
private static final String MROONGA_TOKENFILTER = "normalize 'NormalizerNFKC100(" +
			"\"unify_kana\", true, " +
			"\"unify_kana_case\", true, " +
			"\"unify_hyphen\", true)' \"";

...
	String words = condition.getFulltextExpression();

	StringBuilder command = new StringBuilder();
	command.append(MROONGA_NORMALIZER).append(words).append("\"");
	String normalizedQuery = mapper.mroongaCommand(command.toString());
	command.setLength(0);
	command.append(MROONGA_TOKENFILTER).append(normalizedQuery).append("\"");
	String filteredQuery = mapper.mroongaCommand(command.toString());

	String originalText = mapper.getTextByFulltextId(docInfo.getFullTextId());
	command.setLength(0);
	command.append(MROONGA_NORMALIZER).append(originalText).append("\"");
	String normalizedText = mapper.mroongaCommand(command.toString());
	command.setLength(0);
	command.append(MROONGA_TOKENFILTER).append(normalizedText).append("\"");
	String filteredText = mapper.mroongaCommand(command.toString());
...

正規化オプションの適用順序については、ソースまで読まないといけないのかもしれません。
"ヴァヴィヴヴェヴォ"を変換してから、unify_kana変換することが確実になるように、2段変換しています。

Mapper中のSQL

SELECT mroonga_command(#{command});
...
SELECT mroonga_snippet_html(#{text}, #{keyword});

Mroonga v10.09 (2020-12-02)以降

2020-12-26に追記
@ktou さんから新版 v10.09 を勧めるコメントもらっていながら、他事に紛れてなかなか確認できませんでしたが、ようやく v10.09 でのありがたい新機能を確認しました。

@ktou
次のMroongaからはmroonga_snippet_html(column, 'diaries' as table_name, 'content' as index_name, '...' as query)で指定したインデックスに設定されているノーマライザーの情報を使ってくれるようになります。

更新前の状態

2.5.18. CentOS 7(MariaDB 10.4のパッケージを利用) でインストールした9.12でした。

MariaDB [(none)]> SHOW VARIABLES LIKE 'mroonga_version';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| mroonga_version | 9.12  |
+-----------------+-------+

yum update

$ yum info --enablerepo=epel mariadb-10.4-mroonga
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
196 packages excluded due to repository priority protections
Installed Packages
Name        : mariadb-10.4-mroonga
Arch        : x86_64
Version     : 9.12
Release     : 1.el7
Size        : 534 k
Repo        : installed
...

Available Packages
Name        : mariadb-10.4-mroonga
Arch        : x86_64
Version     : 10.09
...
$ sudo yum update --enablerepo=epel mariadb-10.4-mroonga
...
Updated:
  mariadb-10.4-mroonga.x86_64 0:10.09-1.el7

Dependency Updated:
  MariaDB-client.x86_64 0:10.4.17-1.el7.centos
  MariaDB-server.x86_64 0:10.4.17-1.el7.centos

Complete!

$ sudo systemctl daemon-reload
$ sudo mysql < /usr/share/mroonga/install.sql
$ sudo mysql
MariaDB [(none)]> SHOW VARIABLES LIKE 'mroonga_version'\G
*************************** 1. row ***************************
Variable_name: mroonga_version
Value: 10.09


### Normalize

> @ktou
ただ、unify_kanaとunify_katakana_v_soundsは一緒には使えない(unify_kanaでカタカナがすべてひらがなになってしまいunify_katakana_v_sounds対象の文字がなくなってしまう)ので、unify_kanaをunify_to_katakanaにしてください。これで、ノーマライザーとトークンフィルターにわけなくてもよくなります。

```sql
ALTER TABLE t_content ADD FULLTEXT INDEX ftx_ngram(t_ngram) COMMENT
'tokenizer "TokenBigram",
 normalizer "NormalizerNFKC100(
   \'unify_prolonged_sound_mark\', true,
   \'unify_middle_dot\', true,
   \'unify_katakana_v_sounds\', true,
   \'unify_to_katakana\', true,
   \'unify_kana_case\', true,
   \'unify_hyphen\', true)"'
;

normalizer と token_filters の2段構えにしたのは「よみがな検索」もやってみたくて、TokenMecab を使おうとしていたためです。
カタカナとひらがなをどちらかに統制してしまうと、TokenMecab のような形態素解析は外来語や外来固有名詞の区切りを文字種変化に頼っているので悲惨なことになります。normalizer - Mecab - token_filters の順で加工する必要があります。今回の更新で mroonga_snippet_html が参照するのは normalizer だけみたいなので、 TokenMecab のときにかなカナ同一視をしたいなら、前節の後付けのsnippet補完処理が依然として必要です。

TokenBigram ならその心配はないので、normalizer に一本化します。

SQL

snippetCommand = " mroonga_snippet_html(tc.t_ngram, 't_content' as table_name, 'ftx_ngram' as index_name, '" + words + "' as query) ";

10.09のmroonga_snippet_htmlのメリット

  • FULLTEXT INDEXで設定した Normalizeオプションを完全再現した snippet_html取得になる
    • 多数あるオプションを引き渡すのが10.07以前は難しかった
  • SQLひとつで検索結果とヒットした近くのテキスト(snippet_html)を同時に得られるようになった
    • 後付けのsnippet補完処理が不要になった
    • SQL request数が最小で済む
  • snippet_html内容が元テキストのまま
    • 後付けの補完処理では、 noramlize変換したテキスト上でのnormalize変換した検索語が強調される
    • カナかな同一視の normalizeをかけると日本語テキストして不自然だった

mroonga_snippet_html() 使うにあたって 10.09 への update を強く勧めてもらえて助かりました。

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?