pixiv サイバーエージェント共同勉強会 solr導入記

30
pixiv Solr導入記 X

Upload: takahiro-matsumiya

Post on 02-Jul-2015

20.233 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: pixiv サイバーエージェント共同勉強会 solr導入記

pixiv Solr導入記

X

Page 2: pixiv サイバーエージェント共同勉強会 solr導入記

自己紹介 松宮 孝大(mattun)

 プログラムエンジニア

◎pixivでかかわっているサービス  ・pixivモバイル  ・pixiv chat  ・pixivの検索全般

を担当していますJavaが好きなんですがpixivにはJava好きは居ません・・・

Page 3: pixiv サイバーエージェント共同勉強会 solr導入記

目次

Tritonn使用時の検索の問題点

Solrの検証

pixivでのSolrの最適化

まとめ

Page 4: pixiv サイバーエージェント共同勉強会 solr導入記

Solrを導入する目的

Tritonnによる検索に限界があるため検索専用のアプリケーションを模索

検索だけで30台ある台数を減らせればいいなぁ

モバイルで人気順ソートを実装する

Page 5: pixiv サイバーエージェント共同勉強会 solr導入記

Tritonn時代のマシン構成アプリケーション Mysql-Tritton(senna)を使用

マシン構成( 自作機 B28) x 30台 AthlonX2 4850e 2.50GHz (2コア) Mem 8G SSD X25(80GB) or C300(64GB)

Page 6: pixiv サイバーエージェント共同勉強会 solr導入記

でのTritonnの問題点

Page 7: pixiv サイバーエージェント共同勉強会 solr導入記

Mysqlの全文検索には更新時ロックがかかる MyISAMのためReplicationで更新クエリーがくるとそこでロックがかかってしまう

CPUのコア数でスケールできない ロックがかかるためCPUが1コア分くらいしか使い切れていない

R-18など数値のある文字が重い たとえば6を検索したとき⑥や全角半角の6などもOR検索し条件が増える 揺らぎ補正のためNormalizeはOffにできない

MySQLのバージョンをあげることができない Tritonnが組み込まれたバージョンを使用しなければならないため Mysql5.1などにアップグレードできなかった

Page 8: pixiv サイバーエージェント共同勉強会 solr導入記

何かの検索文字 R-18

東方 ( はいてない OR 穿いてない OR はいてません OR 穿いてま せん OR ノーパン)

( 髪 OR かみ)( ほどき OR ほどく OR ほどけ OR ほどい OR ほ どいた OR ほどいて OR ほどこう OR ほどかせ OR ほどかれ

OR 解き OR 解く OR 解け OR 解い OR 解いた 解いて OR 解こう OR 解かせ OR 解かせ OR 解かれ OR おろす OR おろ

し OR おろした OR おろして OR おろそう OR おろさせ OR おろされ OR 下ろす OR 下ろし OR 下ろした OR 下ろして

OR 下ろそう OR 下ろさせ OR 下ろされ)

いろいろ重い検索条件を載せたかったのですがエロワードばかりなので自主規制・・・

Page 9: pixiv サイバーエージェント共同勉強会 solr導入記

これはやばい!

よし!Solrだ!

現在でも捌けないのに人気順ソートをモバイルに実装する必要がでてくる・・・

Page 10: pixiv サイバーエージェント共同勉強会 solr導入記

Solrの特徴

Page 11: pixiv サイバーエージェント共同勉強会 solr導入記

参照・更新ロックがかからない

レプリケーションが単純なファイル転送 Masterが持っているファイルをスレーブにコピーするだけ 内部でrsyncと同じようなことをしているだけ

スレーブの追加が簡単 設定ファイルを書くだけで起動すれば勝手に転送される Masterと同じインデックスファイルをもらうだけ

分散検索ができる

Normalizeや形態素解析やNGramなど目的に合わせたカスタマイズが可能

Page 12: pixiv サイバーエージェント共同勉強会 solr導入記

Commitが重い Solrはドキュメントを追加した後にCommitを行って初めてデータが反映される(トランザクションに近い?)  そのCommitが結構な負荷のため1件ずつリアルタイムで更新せず溜め込んだデータをバッチで一気に処理する

 pixivでは更新されたイラスト情報をMysqlのトリガーでログテーブルに保存しそのログを元にScalaで差分更新処理をしている

Commitのタイミングでキャッシュが消える 頻繁に更新するとクエリーキャッシュの意味を余り成さない

PHPやRubyにシリアライズされた結果を返してくれる 他にもXMLやJSONなどあり

Page 13: pixiv サイバーエージェント共同勉強会 solr導入記

Solr3.2.0を使用Solrの設定tokenizer : NGramTokenizer 指定された文字数で分割するfilter : LowerCaseFilter 大文字英字を小文字に変換charfilter : MappingCharFilterFactory 後ほど説明

データ構造uniqueKey: illust_idその他検索に必要なタグ、タイトル、コメント、作品がR18かどうかなどillust_id以外はインデックスのみでデータを持たない

Page 14: pixiv サイバーエージェント共同勉強会 solr導入記

Solr検証時の問題点

Page 15: pixiv サイバーエージェント共同勉強会 solr導入記

文字が長いと途中から検索できない・・・

NGramTokenizerというSolr標準のTokenizerを使用してたのですが

コードを読んでみると最大値がなぜか1024文字固定になっていたため可変に修正

solr-3.2.0/lucene/contrib/analyzers/common/src/java/org/apache/lucene/analysis/ngram/NGramTokenizer.java

修正前コード

char[] chars = new char[1024]; input.read(chars); inStr = new String(chars).trim();

修正後コード

CharArrayWriter writer = new CharArrayWriter(1024); int c; while((c = input.read()) != -1) {

writer.write(c); } inStr = new String(writer.toCharArray()).trim();

Page 16: pixiv サイバーエージェント共同勉強会 solr導入記

MultiValueを使うと検索結果がおかしい

unigramで2文字以上の検索ワードを投げるとタグがくっついた形ヒットする

例えばタグに[オリジナル] [パン]というタグがあったとして「ルパン」と検索すると・・・[オリジナル ] [パン] という様に分かれているタグが引っかかってしまう対処法が分からなかったため検索ワードの文字数によってunigramとbigramのインデックスを使い分けて対処した

オリジナル 猫の検索例  tag_bigram: オリジナル OR tag_unigram:猫

Page 17: pixiv サイバーエージェント共同勉強会 solr導入記

半角カタカナ文字にヒットしない半角カタカナを全角カタカナでヒットさせるには自前で設定をしなければならない(NGramTokenizerを使用する場合)

その場合MappingCharFilterFactoryというフィルターを使ってNormalizeすることができる設定例

"ガ"=>"ガ""ギ"=>"ギ"

pixivでは「へ」はどちらでもヒットするように設定"へ"=>"ヘ""べ"=>"ベ""ぺ"=>"ペ"

Page 18: pixiv サイバーエージェント共同勉強会 solr導入記

大量の件数がある場合ソートが重い全体で1200万件の内[東方]というタグには100万件以上ありソートだけで1.5秒くらいかかっている

1秒以上かかるものがある時点で検索を捌くことは不可能

データ更新は1分間隔でしていたのでキャッシュの恩威が少ない

ちなみにソートをしなければ一瞬で検索できる

Page 19: pixiv サイバーエージェント共同勉強会 solr導入記

じゃあ高速化しましょう!

Page 20: pixiv サイバーエージェント共同勉強会 solr導入記

高速化1SolrにはDistributedSearchという分散インデックス検索ができるのでインデックスを分散する

4分割(イラストID%4の余りが番号)して各マシンに1つずつインデックスを持てば検索速度が4倍早くなる

この機能は検索時にインデックスを持っているサーバーをパラメータで渡すだけでいいのでクライアント側の修正は簡単である

例q=東方&shareds=localhost:8983/solr/index0,localhost:8983/solr/index1

Page 21: pixiv サイバーエージェント共同勉強会 solr導入記

全体のインデックス

4分割された

イラストのイン

デックス

1つのイラストをイメージ

※補足 左に行くほど新しい

index1

index2

index3

index4

Page 22: pixiv サイバーエージェント共同勉強会 solr導入記

Solr1index1

Solr3index3

Solr2index2

Solr4index4

DistributedSearcher

すべてのインデックスから10件分(4分割なので40件分)の「東方」の結果を受け取る

クライアント

「東方」を検索する

その中で10件分の結果が返る

分散検索のイメージ図

4つのインデックスに投げる

Page 23: pixiv サイバーエージェント共同勉強会 solr導入記

高速化1の結果速度的には4分割するだけでかなりの高速化になった[東方]で1.5秒だったものが0.4秒くらいへ

それでも想定のマシン数では捌ききれない!

Page 24: pixiv サイバーエージェント共同勉強会 solr導入記

高速化2先ほどの4分割されたインデックスを古い日付のインデックスと見なし、新しい日付のイラスト(15万件)だけのインデックスを作り実質5分割にした

新しい日付イラストは1分間隔で差分更新する

古い日付のイラストは1時間隔で差分更新する

キャッシュの量を大量に設定

10万件以降のページングはキャッシュしない  <queryResultMaxDocsCached>100000</queryResultMaxDocsCached>  一度の検索で2万件のキャッシュを保持しておく <queryResultWindowSize>20000</queryResultWindowSize>

Page 25: pixiv サイバーエージェント共同勉強会 solr導入記

全体のインデックス

古い日付の

イラストのイン

デックス

最新の日付のイラスト1分更新

index1

index2

index3

index4

Index_new

Page 26: pixiv サイバーエージェント共同勉強会 solr導入記

高速化2の結果超高速化された!

古い日付のイラストにはSolrにあるクエリーキャッシュで返せる(キャッシュヒット率79%)

新しいイラストは件数が15万件なのでまったく重くない

問題点として古い日付のイラストのインデックスと最新の日付のインデックスに同じデータが被ってしまうと件数に不整合が起こるのでデータが被らないように調整する

Page 27: pixiv サイバーエージェント共同勉強会 solr導入記

全体のインデックス

最新の日付のイラスト

最新の日付のインデックスと古い日付のインデックスが被らないようにする

Index_new

古い日付の

イラストのイン

デックス

index1

index2

index3

index4

Page 28: pixiv サイバーエージェント共同勉強会 solr導入記

最終的にどれだけ高速化されたか?実質常にクエリーキャッシュが効いているため件数の多い[東方]でも1.5 秒 → 0.04~0.1秒などになった

Tritonnでは30台で捌けなかったものが6台で余裕となった

QPS的に言うとSolrのステータスでは200 / qpsと出ている

Page 29: pixiv サイバーエージェント共同勉強会 solr導入記

まとめ普通に使うだけでもTritonnより早い

分散サーチ機能がついているためスケールが簡単にできる。

過去のデータや不変なデータを別のインデックスに持つようにし更新頻度を抑えればキャッシュのヒット率が大幅にあがる

常に大量の更新がある場合はバッチ処理が必須

Page 30: pixiv サイバーエージェント共同勉強会 solr導入記

ご清聴ありがとうございました