PyCon JP 2018のセッション「Integrate Full-text Search service with Django」の参加メモです。
ElasticsearchをDjangoアプリケーションに導入したときのノウハウなどを中心に紹介されたセッションでした。
スライド
池内孝啓さん(@iktakahiro)
株式会社 catabira - Founder & CEO
PyDataTokyo - Organizer
Elasticsearchを活用したDjangoのWebサービスの活用方法や苦労など
宿泊事業者向けの運用管理システムで、ゲスト-ホスト間のメッセージを全文検索できるようにしたい。
Resourceを中心とした設計アプローチ。
今回のケースでは「スレッド」と「メッセージ」というResource起点に設計する。
RESTfulに設計しようとすると自ずとこうなる。
各DBのテーブルに対してIndexを設計する。
(thread/message/guest)
ElasticsearchではRDBでいうところのJOINがやりにくい。(同一Index内のDocumentのみが対象になるなど)
サービスを1つの単位とした設計アプローチ。
そもそもユーザーに必要なサービスは何か?という観点からスタートする。
(今回の場合、ホストが受信したメッセージを検索したい)
基本的に非正規化することになるのでデータサイズが大きくなる。
またマスターが更新された場合、関連するDocumentを全部更新しないといけなくなる。
RDBとElasticsearchをどのように同期するか。
- そもそも誰がやる?
- バッチ?
- Webアプリ?
- どのタイミングで同期する
- リアルタイム?
- 一定時間おき?
MySQLのbinlogを監視して、Insert/Update/Deleteが有ったらデータ転送イベントを発火する。
- pros
- 物理削除も対象にできる
- テーブル更新からラグが少ない
- const
- テーブル単位で転送対象が決まるのでROAの場合はいいが、SOAだとつらい
LogstashからSELECT文を定期的に発行して最終発行より新しいタイムスタンプのレコードがあればデータ転送を発火
- pros
- Selectを自分で組み立てられる→非正規化に対応できる
- cons
- 物理削除されたのはわからない
elasticsearch-dsl
- High-level APIを提供するPythonのパッケージ
- Indexをクラスとして定義
- IndexやMappingの生成も行う
(たぶん、そこまで頭のいいMigrationはできないが、Pythonコード上でMappingとかができるのはデカい)
-> ElasticsearchのSearch APIを透過的に提供しよう
とはいえIndexを勝手に見られるとまずい。。。
→ということでSerializer(Djangoの)を使う
→ 不要なキーを削除したり、権限のない情報が見られないようにする
→ ElasticsearchのAPIを使うときのホワイトリストをDjangoのSerializerで作るイメージ
#### 同期時間の短縮化
Logstashの場合、走査はcronで行われるのでタイムラグが起こる。
Webアプリで同期的にElasticsearchを使う場合は、Signalを使えば良いのでは?
post_saveやpost_deleteを使っておくと、Modelが更新されたら「XXをやる」みたいなイベントハンドリングを簡単にできる。
##### この方法の課題
- エラー処理とか色々と考える必要がある。。。
- 非正規化されたdocumentに対して更新すると、定義箇所が多くなって複雑に。。。
- Elasticsearch側のパフォーマンス
この辺、ボーッとしてたので異同あるかも
Q. go-mysql-elasticsearchのように、イベントのトリガーとしてMySQLのbinlogを監視するのが良かったのでは?
A. 検討はした。処理が色々なところに散らばっちゃったり処理が複雑になるのが怖い
Q. Djangoでデータを保存したときにSelect文を非同期で発行する仕組みにすればエラー箇所とかも特定しやすくてよさそう
A. 将来リアルタイムにやるのであればそれがよさそう。Logstashに任せると安心な部分が多いので今はそうしている。
将来こういう機能要件が出てきたときに、「こんなのElasticsearchで簡単にできるやろ」みたいな感じで甘く考えてると、ヤバいことになるな、と思った。
特にデータの同期をちゃんと考えて設計しないと炎上する。
要件決めの時に「どの程度のラグだったら許せるのか」とか「データによっては多少結果がズレてもいいか」みたいなことをちゃんと確認したい。
創作支援ツールとかを作ってます。(Python) https://www.world-type.com 歴史成分多め。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント