elasticsearchは全文検索サーバとしても知名度を獲得しており、次のような記事も人気を集めています。
- elasticsearchを全文検索サーバとして活用するなら読んでおきたい、5つのブログ記事をピックアップ - Y-Ken Studio
http://y-ken.hatenablog.com/entry/essential-japanese-blogs-for-elasticsearch-study
MySQLでは実現の難しかったLuceneならではの次のような特徴を兼ね備えたelasticsearchはとても魅力ですよね。
ファセット検索 (Facet)
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets.html柔軟な日本語処理 (kuromoji)
https://github.com/elasticsearch/elasticsearch-analysis-kuromojiオートコンプリート (Completion Suggester)
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
しかしながらelasticsearchを中核となるデータベースとして扱うにはまだ日が浅いことは事実です。
そこで、私と同様にMySQLを補う形でelasticsearchを使いたいという方にとって有用な情報を本日お届けしたいと思います。
インストール/アップデート方法
Fluentdのプラグインとしての利用の他、独立したRPMパッケージとしても提供しております。
### システム側のRubyにインストールする場合 gem install fluent-plugin-mysql-replicator ### td-agentにインストールする場合 /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-mysql-replicator ### RPMパッケージ、Yamabikoでアップデートする場合 # インストールについては右記記事をご参照ください https://github.com/y-ken/yamabiko/releases /usr/lib64/yamabiko/ruby/bin/fluent-gem install fluent-plugin-mysql-replicator
こちらの記事も参考になります。
- MySQLテーブルへの更新/削除イベントを逐次取得するFluentdプラグイン「fluent-plugin-mysql-replicator」をリリースしました - Y-Ken Studio
http://y-ken.hatenablog.com/entry/fluent-plugin-mysql-replicator-has-released
変更内容概要
v0.4.0は、新機能の実装のみです。
- [新機能]ネスト構造化したドキュメントの生成に対応
新機能紹介
今回、「ネスト構造化したドキュメントの生成」に対応しました。
MySQLなどのRDBMSでは、1つの情報に複数のレコードが紐付くスキーマ設計を利用し、JOINを用いて取り出す手法をよく使いますよね。
しかしelasticsearchにはJOINに相当する機能は無く、近しい物として次の手段があります。
nested
メリット - クエリのパフォーマンスが高い
デメリット - 更新が多いときのオーバーヘッドが大きい
用途 - 名前の通り入れ子なデータを扱いたいとき、(rails でいう has_many では使わないと思う)parent/child
メリット - nested と違って更新時に問題を抱えてない
デメリット - クエリのパフォーマンスが落ちる、メモリを多く要する
用途 - 名前の通り親子関係のもの、RDB 的な relation はこちらに近い
引用元: http://engineer.wantedly.com/2014/02/25/elasticsearch-at-wantedly-1.html
parent/childはドキュメント登録時に1つまでの親子関係を予めセットする必要があるため、柔軟性がない事も使いづらいと感じました。
そこでNested Typeと呼ばれる入れ子構造(ネスト構造)の出番です。例えば次のような検索を行う場合にもこのネスト構造を用いると便利です。
- ある会員に複数紐付くデータがある
- そのいずれか1つがある値である
そう、今回の新機能の目玉はこのネスト構造化対応です。
使い方
次の結果となる設定の作り方を、サンプルデータと共に解説します。 これはある会員に紐付く、プログラミング言語のスキル情報です。
MySQL側のテーブル設計
本機能を用いてelasticsearchへ登録したドキュメント
$ curl -XGET http://localhost:9200/sample/member_skill/1?pretty { "_index" : "sample", "_type" : "member_skill", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "member_id" : 1, "member_name" : "ユーザA", "skills" : [ { "skill_name" : "PHP", "skill_url" : "http://php.net/" }, { "skill_name" : "Ruby", "skill_url" : "https://www.ruby-lang.org/" } ] } }
ネスト構造を生成する仕組み
MySQLでは1:N対応となるネスト構造は表現できません。
そこで、クエリの中にプレースホルダを埋め込みそれを都度展開させる処理を行います。
query設定の実行時の結果のfetch時にプレースホルダがあれば、別途プログラムの中でSELECTクエリを発行して結果をマージする処理を行うというものです。
-- prepared_query設定に記述する一時テーブル作成クエリ CREATE TEMPORARY TABLE tmp_member_skill SELECT members.id AS member_id, skills.name AS skill_name, skills.url AS skill_url FROM members LEFT JOIN member_skill_relation ON members.id = member_id LEFT JOIN skills ON skills.id = skill_id; -- query設定に記述する、elasticsearchへ登録するドキュメントを生成するクエリ -- クエリの中に、ネスト構造として納めたいクエリを記述すると処理時に展開します SELECT members.id AS member_id, members.name AS member_name, "SELECT skill_name, skill_url FROM tmp_member_skill WHERE member_id = ${member_id}" AS skills FROM members ;
仕組みとしては、まずquery設定のクエリを実行し、次の結果を得ます。
{ "member_id" : 1, "member_name" : "ユーザA", "skills" : "SELECT skill_name, skill_url FROM tmp_member_skill WHERE member_id = ${member_id}", }
このskills
キーに、プレースホルダ付きのクエリがありますので、続けて${カラム名}
の展開をします。
クエリ実行結果にあるmember_id
の値である1
をプレースホルダに代入し、SQLクエリを実行します。
SELECT skill_name, skill_url FROM tmp_member_skill WHERE member_id = 1
ここではtmp_member_skill
という事前にCREATE TEMPORARY TABLE構文で作成した一時テーブルを利用しています。使わずに都度JOINして結果を得るとパフォーマンスが劣化するため、事前に計算結果をメモリに蓄える手法を利用しています。
そして、実行結果をskillsの値として代入することで、次のネスト構造を得られました。
最後にこのドキュメントをelasticsearchへ登録すれば完了です。
{ "member_id" : 1, "member_name" : "ユーザA", "skills" : [ { "skill_name" : "PHP", "skill_url" : "http://php.net/" }, { "skill_name" : "Ruby", "skill_url" : "https://www.ruby-lang.org/" } ] }
elasticsearch-JDBC-river との違い
実はJDBCドライバを用いて、elasticsearchへ各種制約はありながらもデータ同期が出来るRiverプラグインは存在します。
しかし、このようなネスト構造のサポートは行われておりません。
- Elasticsearch JDBC river
https://github.com/jprante/elasticsearch-river-jdbc
まとめ
このプラグインを用いることで、既存のMySQL環境はそのままに、手軽にelasticsearchを用いた高機能な全文検索を試せる環境が作れます。
実際に弊社内で運用しており、特にトラブルなく稼働しております。今後はドキュメントの拡充を進めていこうと考えております。
この記事をご覧頂いた皆様も是非、まずは開発環境でのトライアルから初めて頂けると幸いです。
不明点等ございましたら、@yoshi_kenまでご連絡ください。
PlanetMySQL Voting: Vote UP / Vote DOWN