20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

38
U-NEXTにおけるSolr活用事例 〜インクリメンタルサーチとレコメンドへの挑戦〜 株式会社U-NEXT システム開発部 秋穂

Transcript of 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

Page 1: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

U-NEXTにおけるSolr活用事例〜インクリメンタルサーチとレコメンドへの挑戦〜

株式会社U-NEXTシステム開発部

秋穂 賢

Page 2: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

自己紹介

氏名 秋穂 賢(あきほ すぐる)

所属 株式会社U-NEXT システム開発部

リリース管理や開発用ミドルウェア管理DBFluteを使ったJava8でのAPI実装 など(前職ではChef / Zabbix / JobScheduler 等)

仕事

Page 3: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

まずはじめに

Solr勉強会での登壇という貴重な機会を与えて

頂いた ロンウイット様、リクルートテクノロジーズ

様、誠にありがとうございます。

特にロンウイット様にはコンサルタントとしてSolrを活用する上で様々なアドバイスをいただきまし

た。

Solr歴半年程度の自分が今、ここに立てている

のもロンウイット様のご支援が大きいと感じており

ます。

Page 4: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

そもそもU-NEXT?最新情報はWebで http://video.unext.jp/introduction

10/8に全面リニューアルを実施!

Page 5: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

そもそもU-NEXT?最新情報はWebで http://video.unext.jp/introduction/device

Page 6: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

そもそもU-NEXT?最新情報はWebで http://video.unext.jp/introduction/family

Page 7: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

そもそもU-NEXT?最新情報はWebで http://video.unext.jp/introduction/fee

Page 8: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

U-NEXTでのSolr利用箇所

U-NEXTではSolrを以下のシーンで活用

○ フリーワード検索(インクリメンタルサーチ)

○ ユーザ毎のレコメンドデータ取得

Solrを使ったバックエンドAPIの開発が主な役割

Page 9: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

インクリメンタルサーチでの事例

Page 10: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

インクリメンタルサーチでの事例

○ インクリメンタルサーチ?

□ 検索文字を全て入力してから検索を行うのではなく、

入力するたびに検索結果が返ってくる検索方法のこと

□ Googleも今はインクリメンタルサーチ

○ Why インクリメンタルサーチ?□ すべての文字を打つことなく結果に辿れる

□ 検索中に新しい気づきを得られる可能性

○ デモ

□ http://video.unext.jp

Page 11: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

システム構成(全体)Webクライアント

(Knockout.js)

WebFrontAPI(PHP)

Portal API(PHP)

CMS API(Java)

SolrCloud

WebブラウザのJSクライアントとしてKnockout.jsを利用

Web特有の要件を満たすための専用 APIサーバ

各バックエンド系APIをまとめてクライアントへ返答するための APIサーバ

CMSDB

コンテンツ周りの情報を返却する APIサーバ

Solrは運用面を考慮してSolrCloudを利用

Varnish(Cache) 検索ワード毎にキャッシュを保持

Page 12: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

システム構成(詳細)

CMS API(Java) Solr

CMSDB

CMS API(Java)CMS API

(Java)CMS API(Java)

SolrSolrCloud

LB

JavaのAPIクライアントからSolrCloudへのアクセスはLB経由でHttpSolrClientを利用=> 直前までmaster/slaveかSolrCloudのどちらにするか、決められなかったため

バッチ

Solrインポート用TSV

定期的にCMSDBからデータ抽出&TSVファイル生成SolrへTSVをインポート

Page 13: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

インクリメンタルサーチ実現における課題

○ ユーザ体験として違和感のない応答速度を担

保する必要がある

スキーマ定義を工夫メタデータに作品名のカナがあるので、有効活用

○ 一文字打つたびに検索結果を返す必要がある□ 検索文字は変換前の英字(ローマ字)の可能性も考慮

レスポンスに必要なデータを全てSolrに入れ込みUI上、即時反映が必要な項目は含めないように(詳細は省きますが)本番同様の負荷テストの結果、Solrからのレスポンスは2,30msをマーク!!

Page 14: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

schema定義

○ インクリメンタルサーチを実現するために大きく4つのパターンでanalyzerを定義□ ※ 全てautoGeneratePhraseQueriesはtrueを設定

1. 日本語タイトル向けの設定(単純検索)○ (charFilter)solr.MappingCharFilterFactory

□ 記号などの不要な文字を削除

○ (charFilter)solr.ICUNormalizer2CharFilterFactory

□ 日本語の正規化

○ (tokenizer)solr.JapaneseTokenizerFactory

□ 形態素解析による日本語の文字分割

○ (filter)solr.LowerCaseFilterFactory□ 英字の大文字小文字を区別しない

Page 15: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

2. 日本語タイトル向けの設定(インクリメンタル)

○ トークナイザまでは 1 と同じ

○ (filter)solr.JapaneseReadingFormFilterFactory□ 漢字を読みに変換

○ (filter)solr.ICUTransformFilterFactory(Hiragana-Katakana)

□ ひらがなをカタカナに変換

○ (filter)solr.ICUTransformFilterFactory(Katakana-Latin)

□ カタカナをローマ字に変換

○ (filter)solr.LowerCaseFilterFactory□ 小文字に統一

○ (filter)solr.EdgeNGramFilterFactory□ 形態素解析結果毎に1gram

○ ※ クエリサイドにはEdgeNGramを含まないように設定

□ => 結果的にはインデックスサイドのEdgeNGramにヒットする

schema定義

Page 16: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

3. カナタイトル向けの設定(インクリメンタル)

○ charFilterまでは 1 と同じ

○ (tokenizer)solr.KeywordTokenizerFactory□ カタカナはフィールド全体を1つのトークンとみなす

○ 残りは 2 と同じ

※ クエリサイドは 2 と同じ。ローマ字に直して前方からの部分一致で検索する

例) 「アノヒ」というタイトルの場合、indexは a / an / ano / anoh / anohi が生

「あのh」で検索すると「あのh」で形態素解析されて「anoh」でフレーズクエリとして

検索される

schema定義

4. 1〜3までで検索にかからなかった向けの2gram設定

○ solr.NGramTokenizerFactoryで2gramの設定

Page 17: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

○ 1〜4までをdismaxでの横断検索を実行

○ 横断検索する際には別途、設定してあるシノニムにも同時に検索

を実行□ 例) 「あの日見た花の名前を僕達はまだ知らない」を「あのはな」と略す

○ 日本語タイトル向けの設定(単純検索)□ => このプライオリティを一番高く設定(400)

○ 日本語タイトル向けの設定(インクリメンタル)

○ カナタイトル向けの設定(インクリメンタル)□ => これらプライオリティを2番目に(200)

○ 2gram設定

□ => 最低のプライオリティに(50)○ ※ シノニムについては通常ワードの半分にプライオリティを設定

schema定義

Page 18: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

残課題

○ 検索精度が悪い部分がある□ 作品は存在しているのに検索にひっかからない

□ おそらく、漢字かな変換や形態素解析あたりが原因と

想像

□ こういった対象を地道に潰していく必要がある

○ 同着スコア時の並び順の最適化をしたい(短

い単語で検索された時など)

□ 現状はscore順となるため、検索する人の傾向によっ

て、アニメを優先させたり、ドラマを優先させたりなど、

検索のパーソナライズ化も目指す

Page 19: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

レコメンドでの事例

Page 20: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

○ レコメンド要件として、↓がありました

□ トップ画面で表示される特集をユーザ毎のオススメを表示したい

□ 各ジャンルトップではジャンルに絞り込んだレコメンドを表示した

□ モバイルアプリの場合、最初に好きなジャンルや映画を聞いて、

好きなものを優先して出したい

○ レコメンド自体の計算は別環境で行われていて、計算結果のキャッ

シュを何かしらでもたせたかった

レコメンドでの事例

インクリメンタルサーチでの高速レスポンスの実績+RDBに似た絞り込み検索が行える= Solr※ SolrはRedis等のキャッシュとRDBの間のようなイメージで使える

Page 21: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

システム構成

レコメンド計算サーバ

Solrインポート用TSV

レコメンドSolrCloud

レコメンド計算結果を計算後、レコメンドキャッシュ用SolrCloudにデータインポートを実行

レコメンドSolrCloudレコメンド

SolrCloud

CMS API(Java)CMS API

(Java)CMS API(Java)CMS API

(Java)

LB

CMSDB

最終的にクライアントへ返す・返さないという制御はDBで実施並び順はSolrに格納されたレコメンド計算結果順になる

レコメンド用Solrには計算結果の各ID情報とスコア情報を持つ

Page 22: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

○ シンプルな絞り込み検索だけ(ファセットは使わない)

○ データとしては以下のような形式(一部略)

schema定義

uid ユーザID ジャンルID カテゴリID 特集ID 特集スコア 作品ID

1 user1 anime SF feature1 0.998 s1,s2,s3...

2 user1 houga SF feature10 0.95 s10,s11,s12..

3 user1 anime Drama feature11 0.93 s20,s21,s22..

4 user1 youga Action feature18 0.89 s30,s31,s32..

5 coldstart anime Drama feature4 0.98 s4,s5,s6...

6 coldstart houga SF feature5 0.96 s14,s15,s16..

7 coldstart anime SF feature15 0.94 s24,s25,s26..

8 coldstart youga Action feature22 0.92 s34,s35,s36..

ジャンル単位でのレコメンド表示の際にジャンルで絞り込む

初期のカテゴリ選択のフィルタリングに利用

ユーザ毎のオススメ順にスコアが並んでいる

特集の中の作品の並び順もユーザ毎のオススメ順になっている

Page 23: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

○ user1が好きなカテゴリにDramaとActionを選択した場合

□ => レコメンド結果はフィルタしない

□ => coldstart向けの結果はフィルタする

schema定義

uid ユーザID ジャンルID カテゴリID 特集ID 特集スコア 作品ID

1 user1 anime SF feature1 0.998 s1,s2,s3...

2 user1 houga SF feature10 0.95 s10,s11,s12..

3 user1 anime Drama feature11 0.93 s20,s21,s22..

4 user1 youga Action feature18 0.89 s30,s31,s32..

5 coldstart anime Drama feature4 0.98 s4,s5,s6...

6 coldstart houga SF feature5 0.96 s14,s15,s16..

7 coldstart anime SF feature15 0.94 s24,s25,s26..

8 coldstart youga Action feature22 0.92 s34,s35,s36..

選択していない対象は下においやられる

Page 24: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

レコメンドでの課題

○ やること自体はただのfq(score関係ない)

○ データ件数が膨大

□ アクティブユーザ数 × 特集数 が最大のレコメンド結果のデー

タ数

□○ さすがに多すぎる... & 特集も見る人はそうそういない

□ => 1人あたり最大100特集をレコメンド

□□ ※ フリーワード検索は数十万件程度

Solrからはせいぜい100ms程度で応答して欲しい => 性能検証を実施

mask

mask

mask

Page 25: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

性能検証

○ AWS上に本番相当スペックのSolrCloudを構築してテスト

○ Solrのシャード数:2

□ 2台のSolrに2シャード作ったので、1Solrあたり、1シャード

○ jmeterで実際の疑似クエリを生成し、ランダムにユーザを選択

し、Solrへの検索を行う

○ 10スレッド * 1000リクエストを実行

○ 10万ユーザの中からランダムで1人のユーザを選択してレコメンド

データをリクエスト

○ 事前に1000リクエスト投げてウォームアップを行う

○ 平均、90パーセンタイル値、最小、最大、エラー数を比較

Page 26: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

性能検証結果

件数(万件) 平均(ms) 90%(ms) 最小(ms) 最大(ms) エラー件数

60 22 30 8 503 0

180 20 24 8 598 0

300 23 30 8 513 0

420 24 32 9 755 0

540 25 32 8 509 0

660 25 33 9 497 0

780 24 32 8 499 0

900 27 31 8 715 0

1020 26 35 8 520 0

Page 27: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

性能検証結果

件数(万件) 平均(ms) 90%(ms) 最小(ms) 最大(ms) エラー件数

60 22 30 8 503 0

180 20 24 8 598 0

300 23 30 8 513 0

420 24 32 9 755 0

540 25 32 8 509 0

660 25 33 9 497 0

780 24 32 8 499 0

900 27 31 8 715 0

1020 26 35 8 520 0

件数が60万件〜1020万件までは平均・90パーセンタイル値共に大きな変化はなく、良好な性能

Page 28: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

性能検証結果

件数(万件) 平均(ms) 90%(ms) 最小(ms) 最大(ms) エラー件数

60 22 30 8 503 0

180 20 24 8 598 0

300 23 30 8 513 0

420 24 32 9 755 0

540 25 32 8 509 0

660 25 33 9 497 0

780 24 32 8 499 0

900 27 31 8 715 0

1020 26 35 8 520 0

最小は10ms以下と驚異の性能を発揮最大はいずれも500ms以上のパターンがある=> ハズレを引く人がたまにいる可能性あり

エラー件数はいずれも0となっており発生していない状況

Page 29: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

性能検証結果

○ 1 Solrあたり1シャードで 1 シャードあたり 1020 / 2 = 510万件ま

では性能的にはほとんど問題ない結果

○ 本番では6台のSolrCloudで6シャード2レプリカとした

□ 1Solrあたり2シャード

現状は特に問題がないため、暫くこの構成

mask

Page 30: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

その他の工夫点

Page 31: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

○ 本事例ではSolrのクライアントにJava(solrj)を利用

○ solrjをそのまま使うとタイプセーフではない...

タイプセーフにクエリを実行

try (HttpSolrClient httpSolrClient = new HttpSolrClient(“http://10.105.21.28:8983/solr/general”)) { httpSolrClient.setParser(new XMLResponseParser()); ModifiableSolrParams params = new ModifiableSolrParams(); params.add("q", "あの日"); params.add("defType", "dismax"); params.add("qf", "name kana^10 name_general^20 synonym synonym_general synonym_kana"); QueryResponse response = httpSolrClient.query(params); SolrDocumentList results = response.getResults(); LOG.debug("count={}", results.size()); LOG.debug("list={}", results); } catch (IOException | SolrServerException e) { throw new SystemException("error", e); }

Page 32: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

タイプセーフにクエリを実行

○ ORMにDBFluteを採用

○ DBFluteの自動生成機能を使ってschema.xmlから各種クラス

を自動生成

SolrPagingResultBean<General> list = generalBhv.selectPage(cb -> { cb.query().dismax("あの日", queryField -> { queryField.put(GeneralMeta.Name, null); queryField.put(GeneralMeta.Kana, 10); queryField.put(GeneralMeta.NameGeneral, 20); queryField.put(GeneralMeta.Synonym, null); }); cb.specify().fieldUid(); cb.paging(10, 2); }); LOG.debug("list={}", list);

DBFluteの機能でページング検索が出来る

dismax検索出来る対象のフィールドがタイプセーフに指定可能

specifyでflをタイプセーフに指定可能

Page 33: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

タイプセーフにクエリを実行

○ タイプセーフにすることでミスがあるとコンパイルエラー

○ 単純なミスがなくなる

□ なぜか動かなくて色々とエラー原因を探し回った結果、結

局ただのtypoだった...なんてことを防げる

○ 変更に強くなる

□ スキーマ定義を変えたけど、クエリの指定を変えるのを忘れ

た...なんてことを防げる

タイプセーフにした結果、本当に必要なロジックの実装に集中できる

Page 34: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

まとめ

Page 35: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

○ Solrの機能を有効活用すれば日本語でのイ

ンクリメンタルサーチも実現できる□ ただし、一部精度が悪い部分もあり

○ Solrを使えばレコメンド結果のような大量デー

タを高速に検索可能

□ RedisなどのKVSキャッシュでは出来ない絞り込み検

索が高速に可能

□ 特に単純な検索であれば高速なレスポンスが期待で

きる

○ タイプセーフは大事□ 無駄な時間をかけずに済む

まとめ

Page 36: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

最後に

Page 37: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

U-NEXTでは人材を募集しています

映画やアニメが好きなひとエンターテイメントが好きなひと

配信プラットフォームに興味のあるひと技術的なことが好きなひと

一緒に仕事をしましょう

http://unext.co.jp/recruit/

Page 38: 20151028 第17回 solr勉強会 U-NEXTにおけるSolr活用事例

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