MySQL 8.0でMroonga

: author

須藤功平

: institution

クリアコード

: content-source

MyNA会 2018年7月

: date

2018-07-23

: start-time

2018-07-23T21:05:00+09:00

: end-time

2018-07-23T21:15:00+09:00

: theme

.

Mroonga

MySQLのn ストレージn エンジン

ストレージエンジン

* C++で実装
* MySQLのハンドラーAPIを使う
  * (('note:ハンドラーAPIっていう名前なの?'))

ハンドラーAPI

* すごくよく変わる
* メジャーバージョンアップ
  * (('wait'))絶対変わる
* MyNAバージョンアップ
  * (('wait'))たまに変わる

MySQL 8.0対応

(1) ビルドエラー修正
    * API変更に対応
(2) (('wait'))新機能対応
    * 新COLLATION対応とか
(3) (('wait'))テストをパスするようにする
    * ビルドができても期待通りに動くとは限らない

制約

対応MySQL族でn Mroongaのテストをn すべてパスし続ける

対応MySQL族

* MySQL
  * 5.5, 5.6, 5.7
* MariaDB
  * 5.5, 10.0, 10.1, 10.2, 10.3
* Percona Server for MySQL
  * 5.6, 5.7

Travis CI

# img
# src = images/travis-ci.png
# relative_height = 100

AppVeyor

# img
# src = images/appveyor.png
# relative_width = 100

MySQL 8.0対応の現状

(1) ビルドエラー修正
    * (('wait'))完了
(2) 新機能対応
    * (('wait'))完了
(3) テストをパスするようにする
    * (('wait'))未完(('note:(全然おわんねーの)'))

ビルドエラー修正までの道

90コミット

API変更パターン

(1) (('wait'))ふつうのC++になった
    * すごくよいこと
(2) (('wait'))名前が変わった
(3) (('wait'))新しいなにかが増えた

ふつうのC++

* (({my_bool}))→(({bool}))
* 必要なヘッダーだけ(({#include}))
* (({HASH}))→(({std::unordered_map}))
* (({std::string}))を使える!
* (({auto}))を使える!

名前が変わった

* 型:(({st_select_lex}))→(({SELECT_LEX}))
* API:
  * (({order->direction == ORDER_ASC}))
  * (({order->direction == ORDER::ORDER_ASC}))
  * (({order->asc}))

対応方針

* ((*上位*))互換APIを用意して使う
  * 使わない引数は単に無視
* コード中で(({#if}))しない
  * メンテナンスできないコードのできあがり!😇

互換型

# coderay cpp
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
  class SELECT_LEX;
  typedef SELECT_LEX mrn_select_lex;
#else
  typedef st_select_lex mrn_select_lex;
#endif

// mrn_select_lex *select_lex = table_list->select_lex;

互換API

# coderay cpp

#if MYSQL_VERSION_ID >= 80011
#  define MRN_ORDER_IS_ASC(order) \
     ((order)->direction == ORDER_ASC)
#elif MYSQL_VERSION_ID >= 50603
#  define MRN_ORDER_IS_ASC(order) \
     ((order)->direction == ORDER::ORDER_ASC)
#else
#  define MRN_ORDER_IS_ASC(order) ((order)->asc)
#endif

// if (MRN_ORDER_IS_ASC(order)) {...}

新しいなにかが増えた

* (({dd::*}))が増えた
  * (('wait'))data dictionaryだって
  * (('wait'))テーブル定義の取得方法が変わった
* (('wait'))(({handler}))にメンバー関数追加
  * 実装して対応しないといけない

対応方針

説明が面倒にn なってきたのでn 省略

新機能対応

* 新COLLATION対応
  * (({utf8mb4_0900_ai_ci}))
  * (({utf8mb4_0900_as_ci}))
  * (({utf8mb4_0900_as_cs}))
  * (({utf8mb4_ja_0900_as_cs}))
  * (({utf8mb4_ja_0900_as_cs_ks}))

groonga-normalizer-mysql

1.1.4で全部対応!

テストデータ

# coderay sql

CREATE TABLE x (
  a text,
  FULLTEXT INDEX (a)
) ENGINE=Mroonga;
INSERT INTO x VALUES ("はひふへほ");
INSERT INTO x VALUES ("ばびぶべぼ");
INSERT INTO x VALUES ("ハヒフヘホ");
INSERT INTO x VALUES ("バビブベボ");
INSERT INTO x VALUES ("ハヒフヘホ");
INSERT INTO x VALUES ("バビブベボ");

確認方法

# coderay sql
SELECT * FROM x
 WHERE MATCH(a)
     AGAINST('+バビブベボ' IN BOOLEAN MODE);

(({utf8mb4_0900_ai_ci}))

# coderay sql

ALTER TABLE x MODIFY COLUMN a text
  COLLATE utf8mb4_0900_ai_ci;
-- +--------------------------------+
-- | a                              |
-- +--------------------------------+
-- | はひふへほ                     |
-- | ばびぶべぼ                     |
-- | ハヒフヘホ                     |
-- | バビブベボ                     |
-- | ハヒフヘホ                          |
-- | バビブベボ                     |
-- +--------------------------------+

(({utf8mb4_0900_as_cs}))

# coderay sql

ALTER TABLE x MODIFY COLUMN a text
  COLLATE utf8mb4_0900_as_cs;
-- +-----------------+
-- | a               |
-- +-----------------+
-- | バビブベボ      |
-- +-----------------+

(({utf8mb4_ja_0900_as_cs}))

# coderay sql

ALTER TABLE x MODIFY COLUMN a text
  COLLATE utf8mb4_ja_0900_as_cs;
-- +-----------------+
-- | a               |
-- +-----------------+
-- | ばびぶべぼ      |
-- | バビブベボ      |
-- +-----------------+

(({utf8mb4_ja_0900_as_cs_ks}))

# coderay sql

ALTER TABLE x MODIFY COLUMN a text
  COLLATE utf8mb4_ja_0900_as_cs_ks;
-- +-----------------+
-- | a               |
-- +-----------------+
-- | バビブベボ      |
-- +-----------------+

Mroongaの正規化

* MySQLとはステージが違う
* 濁点とかひらがなとかカタカナとか小文字とか絵文字とかそういうステージじゃないから

使用Unicodeのバージョン

* MySQL: 9.0.0
* Mroonga: 10.0.0

(('note:2018-07時点の最新Unicodeバージョン:11.0.0'))

使い方

# coderay sql

CREATE TABLE x (
  a text,
  FULLTEXT INDEX (a)
-- MariaDBだとNORMALIZER='NormalizerNFKC100'と書ける!
    COMMENT='normalizer "NormalizerNFKC100"'
) ENGINE=Mroonga;

デフォルト

# coderay sql
AGAINST('+バビブベボ' IN BOOLEAN MODE)
-- +-----------------+
-- | a               |
-- +-----------------+
-- | バビブベボ      |
-- | バビブベボ      |
-- +-----------------+

(({unify_kana}))

# coderay sql
-- COMMENT='normalizer
--   "NormalizerNFKC100(\'unify_kana\', true)"'
AGAINST('+バビブベボ' IN BOOLEAN MODE)
-- +-----------------+
-- | a               |
-- +-----------------+
-- | ばびぶべぼ      |
-- | バビブベボ      |
-- | バビブベボ      |
-- +-----------------+

(({unify_voiced_sound_mark}))

# coderay sql
-- COMMENT='normalizer
--   "NormalizerNFKC100(\'unify_voiced_sound_mark\', true)"'
AGAINST('+バビブベボ' IN BOOLEAN MODE)
-- +--------------------------------+
-- | a                              |
-- +--------------------------------+
-- | ハヒフヘホ                     |
-- | バビブベボ                     |
-- | ハヒフヘホ                          |
-- | バビブベボ                     |
-- +--------------------------------+

(({unify_kana_case}))

# coderay sql
INSERT INTO x VALUES ("やゆよ");
INSERT INTO x VALUES ("ゃゅょ");
INSERT INTO x VALUES ("ヤユヨ");
INSERT INTO x VALUES ("ャュョ");
INSERT INTO x VALUES ("ヤユヨ");
INSERT INTO x VALUES ("ャュョ");

(({unify_kana_case}))

# coderay sql
-- COMMENT='normalizer
--   "NormalizerNFKC100(\'unify_kana_case\', true)"'
AGAINST('+ヤユヨ' IN BOOLEAN MODE)
-- +-----------+
-- | a         |
-- +-----------+
-- | ヤユヨ    |
-- | ャュョ    |
-- | ヤユヨ       |
-- | ャュョ       |
-- +-----------+

(({unify_hyphen}))

* ハイフンっぽい文字を
  * -˗֊‐‑‒–⁃⁻₋−
* ハイフンへ
  * -(U+002D)
* ユースケース:電話番号検索

(({unify_prolonged_sound_mark}))

* 長音記号っぽい文字を
  * ー—―─━ー
* 長音記号へ
  * ー(U+30FC)
* ユースケース:電話番号検索

(({unify_hyphen_and_}))n(({prolonged_sound_mark}))

* ハイフンっぽい文字と
  * -˗֊‐‑‒–⁃⁻₋−
* 長音記号っぽい文字を
  * ー—―─━ー
* ハイフンへ
  * -(U+002D)

(({unify_middle_dot}))

* 中点っぽい文字を
  * ·ᐧ•∙⋅⸱・・
* 中点へ
  * ·(U+00B7)
* ユースケース:外来語検索

(({unify_katakana_v_sounds}))

* ヴァヴィヴヴェヴォを
* バビブベボへ
* ユースケース:外来語検索(ワイン名)

(({unify_katakana_bu_sound}))

* ヴァヴィヴヴェヴォを
* ブへ
* ユースケース:外来語検索(ワイン名)

オプションは組み合わせ可能

# coderay sql
-- ワイン名検索用
-- COMMENT='normalizer
--   "NormalizerNFKC100(
--      \'unify_middle_dot\', true,
--      \'unify_katakana_bu_sound\', true)"'

トークナイザー

* MySQLとはステージが違う
* ゆるく検索するモード
  * 電話番号・ワイン名検索に便利

ゆるく検索

* (({loose_symbol}))
  * 記号の有無に関係なくマッチ
* (({loose_blank}))
  * 空白文字の有無に関係なくマッチ

書き方

# coderay sql
-- MariaDBだと↓と書ける!
--   TOKENIZER='TokenNgram("loose_symbol", true)'
-- COMMENT='tokenizer
--   "TokenNgram(\'loose_symbol\', true)"'

電話番号検索例

# coderay sql
INSERT INTO x VALUES ('(123)4567-8901');
INSERT INTO x VALUES ('123-4567-8901');
INSERT INTO x VALUES ('12345678901');
INSERT INTO x VALUES ('(123)4567−8901');
INSERT INTO x VALUES ('123 4567 8901');

電話番号検索例

# coderay sql
-- NormalizerNFKC100('unify_hyphen_and_prolonged_sound_mark', true)
-- TokenNgram('loose_symbol', true,
--            'loose_blank', true)
AGAINST('+1234567ー8901' IN BOOLEAN MODE)
-- +--------------------------------------------+
-- | a                                          |
-- +--------------------------------------------+
-- | (123)4567-8901                             |
-- | 123-4567-8901                              |
-- | 12345678901                                |
-- | (123)4567−8901                |
-- | 123 4567 8901                              |
-- +--------------------------------------------+

ワイン名検索例

# coderay sql
INSERT INTO x VALUES ('セーヴェル エ メーヌ');
INSERT INTO x VALUES ('セブルエメーヌ');
INSERT INTO x VALUES ('セーブル・エ・メーヌ');
INSERT INTO x VALUES ('セーヴル エメーヌ');

ワイン名検索例

# coderay sql
-- NormalizerNFKC100('unify_middle_dot', true,
--                   'unify_hyphen_and_prolonged_sound_mark', true,
--                   'unify_katakana_bu_sound', true)
-- TokenNgram('loose_symbol', true,
--            'loose_blank', true)
AGAINST('+セーヴェルエメーヌ' IN BOOLEAN MODE)
-- +--------------------------------+
-- | a                              |
-- +--------------------------------+
-- | セーヴェル エ メーヌ           |
-- | セブルエメーヌ                 |
-- | セーブル・エ・メーヌ           |
-- | セーヴル エメーヌ             |
-- +--------------------------------+

テストがパスしない原因

* そもそも動かない
* 動くけどクラッシュする
* 動くけど期待通りじゃない
* 動くし期待通りだけど期待通りじゃない

そもそも動かない例

* (({mysql-test/include/*}))が減った
  * (({have_innodb.inc})):InnoDB必須だから
  * (({not_embedded.inc})):libmysqldを辞めたから
* 互換(({.inc}))を用意

動くけどクラッシュする例

* JSON型のカラムの更新
* ラッパーモード
  * 使っている人いる?
  * 削除していい?

動くけど期待通りじゃない例

* (({FOREIGN KEY}))の制約チェック
  * (({dd::*}))からうまく主キー情報を\n
    取得できていない

動くし期待通りだけどn期待通りじゃない例

* デフォルト値変更→期待結果も変わる
  * 例:COLLATIONの変更
  * (({SHOW CREATE TABLE}))の結果が変わる
* テスト方法・結果の変更で対応
  * 例:非デフォルトCOLLATIONを使う
  * ただただ面倒

テストがまだパスしていない要因

* テスト実行が遅くなった
* JSONのやつがなんで動かなくなったか\n
  わからん
* (({dd::*}))の使い方がわからん

テスト実行が遅い

* mysql-test-runが遅くなった
  * テスト実行開始まで30秒くらい
  * メモリー3GB食うようになった
  * Mroongaのテストは約770個
* gdbの起動が遅くなった
  * mysqldのシンボル読込に15秒くらい

テストがパスするための支援方法

* クリアコードに開発案件を発注
* 仕事の時間で開発できる!

次回リリース

* 8月か9月の肉の日かなぁ
* db tech showcase Tokyo 2018の前に\n
  リリースできるといいなぁ