tag:crieit.net,2005:https://crieit.net/tags/PyConJP/feed
「PyConJP」の記事 - Crieit
Crieitでタグ「PyConJP」に投稿された最近の記事
2019-02-18T22:02:08+09:00
https://crieit.net/tags/PyConJP/feed
tag:crieit.net,2005:PublicArticle/14811
2019-02-18T22:02:08+09:00
2019-02-18T22:02:08+09:00
https://crieit.net/posts/Python-5c6aacd0f300a
Pythonで数字を文字列として扱う
<h2 id="Pythonで数字を足す"><a href="#Python%E3%81%A7%E6%95%B0%E5%AD%97%E3%82%92%E8%B6%B3%E3%81%99">Pythonで数字を足す</a></h2>
<p>文字列と文字列を連結して新しい文字列を作成することは出来ますが、文字列と数値を連結することは出来ません。<br />
そこでPythonで数字を文字列として扱いたい。その時に使うのがstr()です。</p>
<pre><code class="Python">price = 100
print(price + '円')
</code></pre>
<h2 id="Pythonで数字を足す方法"><a href="#Python%E3%81%A7%E6%95%B0%E5%AD%97%E3%82%92%E8%B6%B3%E3%81%99%E6%96%B9%E6%B3%95">Pythonで数字を足す方法</a></h2>
<p>str([object])を使えば解決!</p>
<h2 id="実際のコード"><a href="#%E5%AE%9F%E9%9A%9B%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89">実際のコード</a></h2>
<pre><code class="Python">price = 100
print(str(price) + '円')
</code></pre>
<h2 id="動くサンプル"><a href="#%E5%8B%95%E3%81%8F%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB">動くサンプル</a></h2>
<p><a target="_blank" rel="nofollow noopener" href="https://colab.research.google.com/drive/191wx5C3_48NBPY62dSrhYtUMertqF2sY">Python3</a></p>
aocory
tag:crieit.net,2005:PublicArticle/14545
2018-09-18T17:08:48+09:00
2018-10-24T10:09:02+09:00
https://crieit.net/posts/Integrate-Full-text-Search-service-with-Django-PyConJP
参加メモ:「Integrate Full-text Search service with Django」 #PyConJP
<h1 id="Integrate Full-text Search service with Django"><a href="#Integrate+Full-text+Search+service+with+Django">Integrate Full-text Search service with Django</a></h1>
<p><a target="_blank" rel="nofollow noopener" href="https://pycon.jp/2018/">PyCon JP 2018</a>のセッション「Integrate Full-text Search service with Django」の参加メモです。</p>
<p>ElasticsearchをDjangoアプリケーションに導入したときのノウハウなどを中心に紹介されたセッションでした。<br />
<a target="_blank" rel="nofollow noopener" href="https://slideship.com/users/@iktakahiro/presentations/2018/09/DRJxjKfBFEGSRcvYjCA88f/">スライド</a></p>
<p><a href="https://crieit.now.sh/upload_images/ec15714678dca9ab3333d8d29f2604cf5ba0b00b8fbff.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/ec15714678dca9ab3333d8d29f2604cf5ba0b00b8fbff.jpg?mw=700" alt="django x elasticsearch" /></a></p>
<h2 id="登壇者"><a href="#%E7%99%BB%E5%A3%87%E8%80%85">登壇者</a></h2>
<p>池内孝啓さん(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/iktakahiro">@iktakahiro</a>)<br />
株式会社 <a target="_blank" rel="nofollow noopener" href="https://catabira.co/">catabira</a> - Founder & CEO<br />
PyDataTokyo - Organizer</p>
<h2 id="内容"><a href="#%E5%86%85%E5%AE%B9">内容</a></h2>
<p>Elasticsearchを活用したDjangoのWebサービスの活用方法や苦労など</p>
<h3 id="実現したいこと"><a href="#%E5%AE%9F%E7%8F%BE%E3%81%97%E3%81%9F%E3%81%84%E3%81%93%E3%81%A8">実現したいこと</a></h3>
<p>宿泊事業者向けの運用管理システムで、ゲスト-ホスト間のメッセージを全文検索できるようにしたい。</p>
<h3 id="稼働中サービスに検索機能を導入する場合に考えること"><a href="#%E7%A8%BC%E5%83%8D%E4%B8%AD%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AB%E6%A4%9C%E7%B4%A2%E6%A9%9F%E8%83%BD%E3%82%92%E5%B0%8E%E5%85%A5%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AB%E8%80%83%E3%81%88%E3%82%8B%E3%81%93%E3%81%A8">稼働中サービスに検索機能を導入する場合に考えること</a></h3>
<ul>
<li>既存のデータ(RDBに入ってる)</li>
<li>Elasticsearchのindex設計</li>
<li>過去のデータの同期</li>
<li>未来のデータの同期</li>
<li>既存アーキテクチャの非破壊</li>
</ul>
<h4 id="index設計"><a href="#index%E8%A8%AD%E8%A8%88">index設計</a></h4>
<h5 id="設計案1: ROA"><a href="#%E8%A8%AD%E8%A8%88%E6%A1%881%3A+ROA">設計案1: ROA</a></h5>
<p>Resourceを中心とした設計アプローチ。<br />
今回のケースでは「スレッド」と「メッセージ」というResource起点に設計する。<br />
RESTfulに設計しようとすると自ずとこうなる。</p>
<p>各DBのテーブルに対してIndexを設計する。<br />
(thread/message/guest)</p>
<h6 id="この方法の課題"><a href="#%E3%81%93%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%AE%E8%AA%B2%E9%A1%8C">この方法の課題</a></h6>
<p>ElasticsearchではRDBでいうところのJOINがやりにくい。(同一Index内のDocumentのみが対象になるなど)</p>
<h5 id="設計案2: SOA"><a href="#%E8%A8%AD%E8%A8%88%E6%A1%882%3A+SOA">設計案2: SOA</a></h5>
<p>サービスを1つの単位とした設計アプローチ。<br />
そもそもユーザーに必要なサービスは何か?という観点からスタートする。<br />
(今回の場合、ホストが受信したメッセージを検索したい)</p>
<ul>
<li>SOAでElasticsearchのIndexを設計する
<ul>
<li>機能として必要な情報をすべて Indexに登録する</li>
<li>RDBのテーブルをJOINしてElasticsearchのIndexを作る</li>
<li>(機能を満たすIndexを作成)</li>
</ul></li>
</ul>
<h6 id="この方法の課題"><a href="#%E3%81%93%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%AE%E8%AA%B2%E9%A1%8C">この方法の課題</a></h6>
<p>基本的に非正規化することになるのでデータサイズが大きくなる。<br />
またマスターが更新された場合、関連するDocumentを全部更新しないといけなくなる。</p>
<h4 id="データの同期設計"><a href="#%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%90%8C%E6%9C%9F%E8%A8%AD%E8%A8%88">データの同期設計</a></h4>
<p>RDBとElasticsearchをどのように同期するか。<br />
- そもそも誰がやる?<br />
- バッチ?<br />
- Webアプリ?<br />
- どのタイミングで同期する<br />
- リアルタイム?<br />
- 一定時間おき?</p>
<h5 id="同期ツールの選択肢"><a href="#%E5%90%8C%E6%9C%9F%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2">同期ツールの選択肢</a></h5>
<h6><a target="_blank" rel="nofollow noopener" href="https://github.com/siddontang/go-mysql-elasticsearch">go-mysql-elasticsearch</a></h6>
<p>MySQLのbinlogを監視して、Insert/Update/Deleteが有ったらデータ転送イベントを発火する。<br />
- pros<br />
- 物理削除も対象にできる<br />
- テーブル更新からラグが少ない<br />
- const<br />
- テーブル単位で転送対象が決まるのでROAの場合はいいが、SOAだとつらい</p>
<h6><a target="_blank" rel="nofollow noopener" href="https://www.elastic.co/jp/products/logstash">Logstash</a> + <a target="_blank" rel="nofollow noopener" href="https://www.elastic.co/guide/en/logstash/current/plugins-inputs-jdbc.html">JDBC Plugin</a></h6>
<p>LogstashからSELECT文を定期的に発行して最終発行より新しいタイムスタンプのレコードがあればデータ転送を発火<br />
- pros<br />
- Selectを自分で組み立てられる→非正規化に対応できる<br />
- cons<br />
- 物理削除されたのはわからない</p>
<h3 id="Elasticsearch + Django"><a href="#Elasticsearch+%2B+Django">Elasticsearch + Django</a></h3>
<h4 id="Elasticsearch + Python"><a href="#Elasticsearch+%2B+Python">Elasticsearch + Python</a></h4>
<p><a target="_blank" rel="nofollow noopener" href="https://github.com/elastic/elasticsearch-dsl-py">elasticsearch-dsl</a><br />
- High-level APIを提供するPythonのパッケージ<br />
- Indexをクラスとして定義<br />
- IndexやMappingの生成も行う<br />
(たぶん、そこまで頭のいいMigrationはできないが、Pythonコード上でMappingとかができるのはデカい)</p>
<h4 id="Serializer"><a href="#Serializer">Serializer</a></h4>
<ul>
<li>できるだけ柔軟な検索インターフェースを提供したい</li>
<li>q?keyword=ham|egg&name=masaとかのQueryは組み立てもParseも苦しい</li>
</ul>
<p>-> ElasticsearchのSearch APIを透過的に提供しよう<br />
とはいえIndexを勝手に見られるとまずい。。。<br />
→ということでSerializer(Djangoの)を使う<br />
→ 不要なキーを削除したり、権限のない情報が見られないようにする<br />
→ ElasticsearchのAPIを使うときのホワイトリストをDjangoのSerializerで作るイメージ</p>
<p>#### 同期時間の短縮化<br />
Logstashの場合、走査はcronで行われるのでタイムラグが起こる。<br />
Webアプリで同期的にElasticsearchを使う場合は、Signalを使えば良いのでは?</p>
<p>post_saveやpost_deleteを使っておくと、Modelが更新されたら「XXをやる」みたいなイベントハンドリングを簡単にできる。</p>
<p>##### この方法の課題<br />
- エラー処理とか色々と考える必要がある。。。<br />
- 非正規化されたdocumentに対して更新すると、定義箇所が多くなって複雑に。。。<br />
- Elasticsearch側のパフォーマンス</p>
<h3 id="結論というかお勧め"><a href="#%E7%B5%90%E8%AB%96%E3%81%A8%E3%81%84%E3%81%86%E3%81%8B%E3%81%8A%E5%8B%A7%E3%82%81">結論というかお勧め</a></h3>
<ul>
<li>同期はLogstash(ダウンしたりIndexが変わったときの同期にドキドキしなくていいのでとりあえずこれで)</li>
<li>ラグの許容できない箇所はSignalsを検討。</li>
</ul>
<h3 id="質問"><a href="#%E8%B3%AA%E5%95%8F">質問</a></h3>
<p>この辺、ボーッとしてたので異同あるかも<br />
Q. go-mysql-elasticsearchのように、イベントのトリガーとしてMySQLのbinlogを監視するのが良かったのでは?<br />
A. 検討はした。処理が色々なところに散らばっちゃったり処理が複雑になるのが怖い<br />
Q. Djangoでデータを保存したときにSelect文を非同期で発行する仕組みにすればエラー箇所とかも特定しやすくてよさそう<br />
A. 将来リアルタイムにやるのであればそれがよさそう。Logstashに任せると安心な部分が多いので今はそうしている。</p>
<h3 id="感想"><a href="#%E6%84%9F%E6%83%B3">感想</a></h3>
<p>将来こういう機能要件が出てきたときに、「こんなのElasticsearchで簡単にできるやろ」みたいな感じで甘く考えてると、ヤバいことになるな、と思った。</p>
<p>特にデータの同期をちゃんと考えて設計しないと炎上する。</p>
<p>要件決めの時に「どの程度のラグだったら許せるのか」とか「データによっては多少結果がズレてもいいか」みたいなことをちゃんと確認したい。</p>
iotas𓆡創作支援アプリ運営中𓅬