SlideShare una empresa de Scribd logo
1 de 29
Descargar para leer sin conexión
Python を使って
カメリオを高速化
した話
白ヤギ勉強会 #13 2015.03.25
Nozomu Kaneko
アジェンダ
カメリオについて
以前のアーキテクチャ
記事とテーマの事前紐づけ(タグ付け)
なぜ Python か
カメリオ
● 気になるテーマで最新情報が追える
● 2014年 AppStore ベストアプリ
● iPhone / Android / Web
カメリオのシステム全体構成
小さなサーバーで大きなサービスをつくる
http://aial.shiroyagi.co.jp/2014/11/simple-server-and-huge-service/
以前の状況 (2014年後半〜)
● テーマに関連する記事の選択は、内部的に
検索で実現
o テーマ毎に異なる検索クエリが存在する
● ユーザが増えるに従い表示の遅さが目立って
きた
解決1: 検索サーバを増やす (2014/8〜)
APP 1
記事イン
デックス
記事検索
サーバ1
記事検索
サーバ2
記事検索
サーバ3
ELB ELB
APP 2
APP 3
NFSマウント
検索サーバを増やすようにした結果
● ひとまずスケールするようになった
o 金のチカラで解決…
● アクセスの急増に対応しきれない
● DAU と比例して徐々にサーバ台数が増加
o c3.xlarge × 6台 (MAX: 20台)
検索の限界
● キャッシュとの相性
o あまり長くすると新しい情報が入ってこなくなる
o 1人しかフォローしていないテーマが大半
● CPU heavy
o サーバ1台で同時にさばけるリクエスト数が少ない
● 無駄が多い
o 記事とテーマの関連性を毎回計算している
解決2: 記事とテーマを事前に紐づける
● ユーザがアプリを開く前に、すべての記事に
ついてすべてのテーマとの関連度を計算して
おく
● 表示するときは SQL で取ってくるだけ
目標とするパフォーマンス
テーマ数: 約300万
新着記事数: 1日約2万記事
→処理速度: 1記事あたり5秒以内
最終目標: ファーストビュー1.5秒以内
設計方針
● 記事精度を担保するため、既存のクエリを
使って関連度スコアを計算する
o 普通にやると遅すぎて話にならないので、各種の工
夫をして現実的な時間で終わるようにする
● 将来的にタグ付けのアルゴリズムを拡張可能
にする
o ソースとテーマの関連付けなど
タグ付け処理の概要
...
クローラー データベース
タグ付けアルゴリズム
テーマ テーマ テーマ
テーマ
RabbitMQ
オープンソースのメッセージングミドルウェア
● 高い安定性
● メッセージの永続化
● 非同期タスクや PubSub
など、様々な構成に対応
● 公式のチュートリアルが
充実している
タグ付けパイプライン (1)
X
X
P
C
C
C
記事内容に基づくテーマタグ付け
ソースに基づくテーマタグ付け*
topic_tagger topic_tagger_main
topic_tagger_source
topic_tagger_main_queue
X
topic_tagger_source_queue
クローラー→タグ付け
*今回は未実装
タグ付けパイプライン (2)
P
P
P
X C
DB
topic_collector
topic_collector_queue
タグ付け→タグ保存
関連度スコア計算
Q = "#weight(3.0 #syn(カメリオ kamelio) 1.0 白ヤギ)"
score(Q|D) = (3.0 * log P(カメリオ or kamelio|D) +
1.0 * log P(白ヤギ|D)) / 4.0
表現rの文書D中の出現頻度
文書Dの総単語数
表現rのコーパス中の出現確率
μ=200〜2500 (スムージングパラメータ)
文書Dにおける表現
(≒単語)rの確率
スコア計算を高速化する工夫 (1)
クエリの絞り込み
● クエリに含まれる単語が文書に1回も出てこなければ、
そのクエリは決してマッチしない
● 転置インデックスを使って、評価すべきクエリを絞り
込む
● フォロー中のテーマ数 約4万 → 2,000〜10,000テーマ
クエリの絞り込み
カメリオは白ヤギコーポ
レーションが開発した
ニュースアプリです。
カメリオ
カメルーン
カメレオン
カメラ
クエリに「カメリオ」を含むテーマの
リスト
テーマ1
テーマ124
テーマ3357
…
転置インデックス
#weight( 1.0 Python 0.5 PyPI 0.1 Guido )
決してマッチしない
スコア計算を高速化する工夫 (2)
事前計算
● クエリの Python コードへの変換
o それまで使っていた検索エンジンと同等の処理
(クエリのパース、スコア計算式)を Python で
再実装
● クエリ評価に必要な統計値(各単語のコーパス中の
出現頻度)の事前取得
● この部分の処理は全部で30分くらい。1日1回更新
ast
● Python の抽象構文木を扱うためのモジュール
● compile() 関数を使って Python コードに変換できる
>>> print ast.dump(ast.parse("1 + 2 * x"))
Module(body=[
Expr(value=BinOp(op=Add(),
left=Num(n=1),
right=BinOp(op=Mult(),
left=Num(n=2),
right=Name(id='x', ctx=Load()))))
])
字句解析と構文解析
BNF の例 (数式のみ)
<expression> ::= <term> ('+' <term>)* | <term> ('-' <term>)*
<term> ::= <factor> ('*' <factor>)* | <factor> ('/' <factor>)*
<factor> ::= '(' <expression> ')' | '+' <expression> | '-'
<expression> | <number>
<number> ::= <integer>('.'<digit>*)+
<integer> ::= <nonzerodigit><digit>* | '0'
<nonzerodigit> ::= '1'...'9'
<digit> ::= '0'...'9'
クエリから Python コードへの変換
#weight(3.0 #syn(カメリオ kamelio) 1.0 白ヤギ)
#weight
3.0 1.0 白ヤギ
カメリオ
def func(log_p, p):
return 0.75 * log(p("カメリオ", "kamelio")) + 0.25 * log_p["白ヤギ"]
+
* *
0.75 0.25log() []
p()
カメリ
オ
kamelio
白ヤギlog_p
クエリのパース
ast の生成
コンパイル
kamelio
#syn
スコア計算を高速化する工夫 (3)
データ構造
● 事前計算したデータはシリアライズしてファイルに
保存する。実行時には SQL にアクセスしない。
● 単純に pickle すると読み込みに時間がかかるので、
trie と配列を使って読み込みを高速化。
● 300MB -> 100MB (zip 圧縮して 70MB)
ここまでの工夫で、1記事あたり3〜5秒程度でタグ付けが
完了する
結果
● 表示速度は改善
o 最初の5テーマの表示に2秒かからない
o アプリ側でも読み込みタイミングの調整を行った
● バックエンドのサーバ台数は削減
o before: c3.xlarge 7台〜 (アクセスによって変動)
o after: c3.xlarge 3台 + c3.2xlarge 1台
● 新着記事が出るまでの時間が短縮
o 以前は平均して30分程度の遅延があった
ほぼリアルタイムに記事を処理できている
通常時
tagger 10プロセス
collector 2 プロセス
必要に応じてスポットインスタンスを立ち上げることでスケール可能
結果 (続き)
hourly crawled contents
hourly extracted contents
hourly filtered contents
hourly queued contents
hourly tagged contents
苦労したところ
● 精度の評価
o スコア計算のバグやパイプライン処理中の欠落など
様々な原因で、表示される記事が一致しない
 ランダムに選んだテーマで結果を比較
 アクセスの多いテーマで誤差の原因を解析
苦労したところ
● RabbitMQ ワーカーが安定しない
o ライブラリ (pika) とマルチスレッドの相性が悪い
o heartbeat が途切れるとサーバが勝手に接続を切る
o 最終的には詰まっていることを検知して自動再起動
するようにした(運用でカバー)
なぜ Python か
● 高速化したいなら C++ や Go の方が Python
より 100 倍高速では?
● Python を使った理由
o 構文解析のような複雑な処理を、なるべくバグを出
さずにかつ素早く書けること
o コードオブジェクトのシリアライズができること
o pypy は使っているライブラリが対応していなかった
おまけ

Más contenido relacionado

La actualidad más candente

RubyWorld Conference 2017 虎の穴ランチセッション
RubyWorld Conference 2017 虎の穴ランチセッションRubyWorld Conference 2017 虎の穴ランチセッション
RubyWorld Conference 2017 虎の穴ランチセッション虎の穴 開発室
 
事例紹介「なうまぴおん」
事例紹介「なうまぴおん」事例紹介「なうまぴおん」
事例紹介「なうまぴおん」Eiji Iwazawa
 
若手Webエンジニア勉強会公開用
若手Webエンジニア勉強会公開用若手Webエンジニア勉強会公開用
若手Webエンジニア勉強会公開用Hiroki Nigorinuma
 
Apache ArrowのRubyバインディングをGObject Introspectionで
Apache ArrowのRubyバインディングをGObject IntrospectionでApache ArrowのRubyバインディングをGObject Introspectionで
Apache ArrowのRubyバインディングをGObject IntrospectionでKouhei Sutou
 

La actualidad más candente (6)

RubyWorld Conference 2017 虎の穴ランチセッション
RubyWorld Conference 2017 虎の穴ランチセッションRubyWorld Conference 2017 虎の穴ランチセッション
RubyWorld Conference 2017 虎の穴ランチセッション
 
事例紹介「なうまぴおん」
事例紹介「なうまぴおん」事例紹介「なうまぴおん」
事例紹介「なうまぴおん」
 
若手Webエンジニア勉強会公開用
若手Webエンジニア勉強会公開用若手Webエンジニア勉強会公開用
若手Webエンジニア勉強会公開用
 
Apache ArrowのRubyバインディングをGObject Introspectionで
Apache ArrowのRubyバインディングをGObject IntrospectionでApache ArrowのRubyバインディングをGObject Introspectionで
Apache ArrowのRubyバインディングをGObject Introspectionで
 
【Unityの集い in大阪】Unity最新情報
【Unityの集い in大阪】Unity最新情報【Unityの集い in大阪】Unity最新情報
【Unityの集い in大阪】Unity最新情報
 
Python yield
Python yieldPython yield
Python yield
 

Similar a Python を使ってカメリオを高速化した話

【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へ【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へDevelopers Summit
 
XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由Ransui Iso
 
はじめてのPython
はじめてのPythonはじめてのPython
はじめてのPythonKatsumi Honda
 
XPagesDay 2015 RESTの総復習
XPagesDay 2015 RESTの総復習XPagesDay 2015 RESTの総復習
XPagesDay 2015 RESTの総復習Masahiko Miyo
 
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12Takanori Suzuki
 
Using PyFoam as library(第25回オープンCAE勉強会@関西)
Using PyFoam as library(第25回オープンCAE勉強会@関西)Using PyFoam as library(第25回オープンCAE勉強会@関西)
Using PyFoam as library(第25回オープンCAE勉強会@関西)TatsuyaKatayama
 
Parquetはカラムナなのか?
Parquetはカラムナなのか?Parquetはカラムナなのか?
Parquetはカラムナなのか?Yohei Azekatsu
 
インメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギインメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギMasaki Yamakawa
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„和弘 井之上
 
Pelicanによる www.python.jpの構築
Pelicanによる www.python.jpの構築Pelicanによる www.python.jpの構築
Pelicanによる www.python.jpの構築Atsuo Ishimoto
 
AWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターンAWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターンseiichi arai
 
アドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニングアドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニングYosuke Mizutani
 
Gura プログラミング言語の紹介
Gura プログラミング言語の紹介Gura プログラミング言語の紹介
Gura プログラミング言語の紹介Yutaka Saito
 
「深層学習」勉強会LT資料 "Chainer使ってみた"
「深層学習」勉強会LT資料 "Chainer使ってみた"「深層学習」勉強会LT資料 "Chainer使ってみた"
「深層学習」勉強会LT資料 "Chainer使ってみた"Ken'ichi Matsui
 
初めてのPadrino
初めてのPadrino初めてのPadrino
初めてのPadrinoTakeshi Yabe
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Yoshifumi Kawai
 
Introduction to Chainer (LL Ring Recursive)
Introduction to Chainer (LL Ring Recursive)Introduction to Chainer (LL Ring Recursive)
Introduction to Chainer (LL Ring Recursive)Kenta Oono
 

Similar a Python を使ってカメリオを高速化した話 (20)

【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へ【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へ
 
XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由
 
はじめてのPython
はじめてのPythonはじめてのPython
はじめてのPython
 
XPagesDay 2015 RESTの総復習
XPagesDay 2015 RESTの総復習XPagesDay 2015 RESTの総復習
XPagesDay 2015 RESTの総復習
 
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
 
Using PyFoam as library(第25回オープンCAE勉強会@関西)
Using PyFoam as library(第25回オープンCAE勉強会@関西)Using PyFoam as library(第25回オープンCAE勉強会@関西)
Using PyFoam as library(第25回オープンCAE勉強会@関西)
 
Parquetはカラムナなのか?
Parquetはカラムナなのか?Parquetはカラムナなのか?
Parquetはカラムナなのか?
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
インメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギインメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギ
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
 
Pelicanによる www.python.jpの構築
Pelicanによる www.python.jpの構築Pelicanによる www.python.jpの構築
Pelicanによる www.python.jpの構築
 
AWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターンAWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターン
 
アドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニングアドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニング
 
Gura プログラミング言語の紹介
Gura プログラミング言語の紹介Gura プログラミング言語の紹介
Gura プログラミング言語の紹介
 
「深層学習」勉強会LT資料 "Chainer使ってみた"
「深層学習」勉強会LT資料 "Chainer使ってみた"「深層学習」勉強会LT資料 "Chainer使ってみた"
「深層学習」勉強会LT資料 "Chainer使ってみた"
 
RとWeb API
RとWeb APIRとWeb API
RとWeb API
 
初めてのPadrino
初めてのPadrino初めてのPadrino
初めてのPadrino
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
 
秀スクリプトの話
秀スクリプトの話秀スクリプトの話
秀スクリプトの話
 
Introduction to Chainer (LL Ring Recursive)
Introduction to Chainer (LL Ring Recursive)Introduction to Chainer (LL Ring Recursive)
Introduction to Chainer (LL Ring Recursive)
 

Python を使ってカメリオを高速化した話