Cookpadのレシピ検索とレシピコミュニティ

兼山元太氏:よろしくお願いします。クックパッドの兼山と申します。私からは「クックパッドのレシピ検索とレシピコミュニティ」という話をしたいと思います。

まず、なぜこのミートアップをやりたいと思ったかというと、みなさんここに来るぐらいだからこの記事を見たんじゃないかと思うんですけど、今日登壇してくださる森山さんの「メルカリの検索結果になぜ売れた商品を表示するのか?」という発表があって。

僕はクックパッドで検索に関する機能を担当しているのですが「この記事おもしろいよ」って何人も僕にDMで送ってきて、「いや、こういう話したほうがいいよ」みたいな感じで言われて、「確かにこういう話したいな」と思いました。

こういう話題が話せる場があまりないかもしれないなと思ったので、今日はそういう話がいっぱいできたり、みなさんから質問をいただければなと思います。

では、始めさせていただきます。

私は兼山と申します。所属はクックパッドの会員事業部で、プレミアムサービスの利用者を増やしたり、そのためのプロダクトとして検索を作ったりしています。

今日お話ししたいことなんですが、クックパッドの中でユーザーが体験するコアな体験を増やしたいという話と、そのためにどんな工夫しているか。ランキングの工夫やそれを支える検索基盤だったり、どういうログを分析しているのかといったこと。それから「まだできてないけど、こういうことをやってみたいですね」という話をさせていただきたいと思っています。

クックパッドとコアの体験

まずクックパッドの概要ですが、現在レシピ数は約310万。月間の利用者数はだいたい5,400万人ほどです。

今日は検索とマッチングの話なんですが、クックパッドのレシピ検索は年間12億セッションくらいのボリューム感です。

検索されるフリーワードは数が多く、主だったものだけでも30万通りほどあり、数回しか試されないものも合わせると倍くらいある状態です。

クックパッドのレシピにはどういった特徴があるかといいますと、普通の人が作った料理の工夫が入っていて、食卓の定番になれるような簡単なレシピや、おいしそうなレシピが見つかります。さらに、CGMなのですが目視で運営がレビューしていて、そのとおりにやれば作れるか、ほかの人が不快にならない内容かといったことを全部チェックしています。

コアとなる体験として、投稿されてなんぼというか、コンテンツあっての検索なんですが、投稿すると予想外の報酬が得られるようになっています。載せる人は、レシピを載せると、それを見つけてもらって、実際に作ってもらえる。探す人は、生活が変わるアイデアがレシピを通じて見つかって、それを実際に料理してみる。それをつくれぽというなかたちでネットに紹介することができて、載せる人と探す人がお互いに楽しい体験を増やせるようになっています。

レシピ作者さんにインタビューもやったりするのですが、「私のレシピにつくれぽが来るなんて思わなくて、素直に驚いた」とか「来るのがうれしくてレシピ投稿を続けた」といったことをおっしゃっていただけます。

例えばつくれぽがあるかというと、単純に作ってみて「上手にできました。おいしかったです」という投稿は多くあります。

ですが、その他にも、シンプルなパウンドケーキのレシピがあったりすると、ユーザーによってかなりアレンジされたものが返ってきたりして、「そんな材料で作れるんだ?」みたいなことが起きたりして、作者の方が驚かれることもあります。

例えば、クックパッド全体だと、50パーセントぐらいの料理は「アレンジしました」と報告されていて、残り50パーセントは「そのままきっちりきレシピどおりやりました」と言っています。

メニューごとに見てみると、あるカレーのレシピは95パーセントぐらいアレンジされています。調味料を調節したり、いろいろな作られ方をしているので、作者からすると驚きがあります。

お菓子のレシピの例では、「食紅がなかったので赤ワインでやったら色がこうなりました」とか、いろいろな報告がされています。

それが投稿者のコアとなる体験の1つです。もう1つは検索側のコアの体験です。

弊社はプレミアムサービスとして有料サービスを提供しているのですが、「一番期待することは何ですか?」と聞くと、機能として「殿堂入りや人気順で検索できるようなレシピ検索が使いたかったです」という話が1つ。

2位・3位を見ると、「献立を決めるのが楽になると思って買いました」とか「レパートリーを増やしたくて買いました」とおっしゃってくれる方がけっこういます。ですのでそこに向けてどんな取り組みをしているのかをお話します。

ランキングにおける工夫

1つはランキングなんですが、コミュニティのため、投稿者のための新着順という側面がありまして、ここではレシピを投稿したらなるべく早くつくれぽが来る。1つのレシピに何千も来るのももちろんいいのですが、できるだけ1on1というか、いろいろなレシピにまんべんなくつくれぽが来るようなマッチを起こしたいと思っています。

そのために、レシピ検索は主に新着順と人気順で提供していまして、検索からのクリックを直近1ヶ月で集計してみますと、310万のレシピがあるうち、260万ぐらいは1ヶ月以内に誰かが検索から参照しています。

今年公開されたレシピに限ってみると、青い部分がフリーユーザーのクリックで、黄色い部分が有料ユーザーのクリックです。2019年に公開されたレシピを見ている人はおおむねフリーユーザーで、オレンジの有料ユーザーは古いレシピも含めてまんべんなく人気順から見ています。

新しいレシピにつくれぽが早く来て驚く体験、予想外の報酬をつくつためには、新着順をきちんと機能させる必要があります。

関連性を高めるためにリランクを実施

もう1つの側面としては、今日の献立が決まるということで、良い献立が「見つかりそう」という印象を作ることも大事だと思っています。そのために、関連検索を利用して先回りして検索する「リランク」を行っています。

これはどういうことかといいますと、例えば「ローストビーフ」と検索するとたくさんのレシピがあるので、単純に新しい順に表示すると、ローストビーフ丼だったり、「ローストビーフが余ったらこうしてみませんか」とか「ローストビーフのタレってこうやって作りましょう」とか、いろんな種類のレシピが出てきてしまいます。「ローストビーフ」というクエリから考えると、実は一番関連性が高いのはど真ん中の「ローストビーフの作り方」なので、それを実現するためにリランクを使っています。

これはちょっとわかりづらいですが、関連検索といってローストビーフを探した人が次に何を検索するかが集計されています。次に検索するものをリランクでなるべく上の方に出して、しかもダブらないかたちで出すようにしています。

新着順のランキングについては、ちょっとしたジレンマがあります。

今のような工夫を行って関連性を高めると、どれが押されるかは結局上の方に表示されているかにすごく影響を受けるので、見られるレシピが偏って、多くのレシピを見てもらう機会がなくなり、もともとコミュニティのために成立していた新着順としての機能が損なわれてしまいます。

その結果、多くのレシピを見てもらう機会が減ってしまうため、関連性を高めるトライもしている一方で、全員が違う結果をランダムで見るというA/Bテストもやったりしています。

もう1つは、これはカレーの人気順の例なのですが、実際に人気でおいしそうだと思えるレシピが上に出てくることが大切です。ですが、「カレー」と検索すると、カレーうどんやカレーピラフなど本当にいろいろなカレーが出てきてしまいます。

一方で、ここは関連検索でリランクするかというと、人気度も維持したいので、前日のクリック情報で訂正を行っています。

なので、カレーうどんが人気度的に1位だったとしても、「カレー」というクエリからはあまり押されていないというような情報があったとしたら訂正を行っています。例えば「1位に表示するんだったら何回ぐらいクリックしてほしい」という期待値が計算できるのですが、それに満たない場合は1ランクずつ下がっていって、逆に「3位にあるはずなんだけれども、このクエリからはすごく押される」というものがあると、1個ずつ上に上がっていくような仕組みになっています。

対象はトップ10の中だけにするなど、もともと人気があるところの中でのリランクを行っています。

今回は2つのリランクを紹介しましたが、いくつかの検索に対する要件を、トレードオフをわかりやすく、作っている人たちがデバッグしやすく、仕様としても理解しやすくするために、リランクはすごく便利な道具だと思っています。

もう1つは、最初にコアの体験の1つとして「献立が決まる」ということを紹介しましたが、実は30万通り毎日検索クエリがある一方で、1人ずつ見ていくと、材料を1個だけ検索するというクエリもすごく多いです。いつも食材を検索して「どんな食べ方があるかな?」というものを見つけるのも大きなユースケースの1つです。

そんななかで、例えば「さつも芋」を検索したら「こんなメニューがありますよ」というようにカルーセルで表示したり、関連キーワードとしていろいろなメニューが提案されるようにして、「そう言えば、そんな食べ方あったな」という新しい発見を増やせるようなナビゲーションも工夫しています。

これが、コアの体験と、そこに至るためにどんな工夫が考えられるか、どんなことをやってますよという話でした。

クックパッドの検索エンジン

もう1つが検索基盤なんですけれども、クックパッドはApache Solrという検索エンジンを使っています。

ここでは多様な検索オプションや先ほど紹介したようなランキング、リランキングを持つサブサービスとして、マイクロサービスが切り出されています。その詳細はすごく長くなってしまうので割愛させていただきます。

今日ご紹介したいのは、実はフィールド数がすごくいっぱいあって、社内ではいろいろな検索のランキングや絞り込み用の情報を定義しています。有料サービスや検索のベーシックな機能も含めて、それらは全部DWHからSQLで定義が表現されています。

例えば、調理時間のテーブルがDWHに同期されているのですが、そこからレシピごとに、最頻値や「このレシピだったら15分で作っている人が一番多いですね」みたいなことをSQLで表現して、それをSolrのフィールドとして定義するというDSLが書けるようになっています。

もう1つは、検索の仕組みを作ったらどうしても出てきてしまうというのが辞書の問題です。クックパッドでも辞書は存在していて、Rubyのgemとして切り出されてデータベースと、GDBMというすごい枯れたKVSがあるのですが、そのKVS上にデータを表現するかたちで辞書を整理しています。

ここには世の中にある検索フレーズを全部まとめたいと思っていて、検索ログを見て、1週間に何十回以上レシピが見つかったら、自動的に辞書に取り込む仕組みになっています。

そういった検索キーワードのリストとしての機能以外には、MeCabという分かち書きのサブシステムに対してユーザー辞書を渡しているのですが、そのフラグの管理も行っています。

GDBMで表現しているのには理由があって、バッチやRailsのリクエストの中で辞書を参照して、「これと同意語なのは何でしたっけ?」とか同義語の解決だったり、あとは「この単語ってメニューなんでしたっけ? 食材名なんでしたっけ?」といった属性の参照をアドホックにやることがけっこうあるのですが、そのためにネットワーク通信をしているとけっこう遅いので、GDBMでAppサーバに配布できるようにして、それを高速に参照するという工夫を行っています。

鰹と鰹節問題

先ほどMeCabを使ってますよと言いましたが、正直、分かち書きを神経質にやらなくても成立すると言えば成立するんですね。

クックパッドだと例えば「鰹と鰹節問題」というものが存在しています。人気順で「鰹」で検索すると鰹節ばかりが検索結果に表示されてしまうという問題がありました。それは鰹節のレシピのほうが圧倒的に多いからですが、そういう解析誤りがすごく起きやすいキーワードで、しかも無視できないキーワードが時々あるので、どうしても分かち書きが必要になっています。

例えばこの例ですごく大変だったのは、鰹節という1単語で分かち書きしてほしいのですが、ひらがなだったりカタカナだったりシノニムの表現がすごくいっぱいあって、主だったものだけでも鰹節って60通りぐらいあって、それを全部MeCabに登録してちゃんと解析がされるようにしました。

結果としては、当時4,900あった「鰹」の検索結果を3,400まで減らすことができました。要するに1,000以上は「鰹節」のノイズだったということですが、CTRも0.27から0.52まで上げることができました。「鰹」で検索したのに、人気順のTOP3が全部「鰹節」だったのですがそれがなくなって、TOP30まで見てもエラーがなくなりました。そういった分かち書きの管理も検索の辞書の中で表現しています。

ログの分析について

もう1つはログの分析です。ここまで、ランキングだったら例えば前日のフィードバックだったり、調理時間のフィールドを追加したいとなったらDWHからSQL書いたりしてきましたが、なんにせよ、ログやプロダクトのデータがすべて1箇所に集まっているDWHをRedshiftで社内に準備してあって、そこからすべてのものを作っています。

なので、関連検索やオートコンプリート、辞書のデータ、アクセスログ、プロダクトのログはDWHから見たり、作ったりしています。

これは非常に重要だと思っていて、ログだけのDBがあっても使いづらいし、プロダクトのマスターデータだけのDBも使いにくいです。両方が1つの場所に入っていて、1回のSQLで両方参照してジョインできるということが、プロダクトのライフサイクルというか開発サイクルを早めるために便利でした。

今後取り組みたいこと

ここからは今後やりたいことです。まだできていませんが、おそらく会社のいろいろなプロダクトに共通する側面としてあるのは、結局、何のために何を最適化するのか。

検索を改善したいとしたとき、どんなKPIをセットして、それを最適化していくのか。例えばクックパッドだとつくれぽを増やしたいというのがあるのですが、すごく難しいのは、検索でレシピを見つけて、4時間待つと、送られてくるつくれぽは全体の半分しか来ていなくて、さらに48時間とか待つとやっと8割つくれぽが送られてくるという状況です。

なので、レシピを見つけたらすぐ調理したとしても、1時間かかる料理ももちろんありますし、「あとで送ろうかな」と思ってしまったりしてコンバージョンの確認がけっこう遠くにあるので、どの原因に対してどの結果が生じたのかを掴むのが、時間が空くほどあやふやになっていきます。ですので、それをどうやって検索に取り入れるのかという問題があります。

あとは、より多くのレシピ作者に再び投稿してもらうことはビジネス上の大きな課題の1つなのですが、先ほども言ったように、つくれぽが来るとうれしいというのはあるものの、いかにちゃんとマッチングさせるかはまだ工夫の余地があると思っています。新着順と人気順だけではなく、もっと違ったUI/UXのアプローチもあるかもしれません。

もう1つは、クックパッドを使っている人の属性やシーンの多様さに対応したいと思っています。これはどういうことかというと、クックパッドは来る人の8割ぐらいの人が週5以上で料理する人で、料理をする頻度の高い人がオーディエンスの大半を占めてるんですけれども、そういう意味では似た人が来ていると考えられます。

しかし、この1個1個の調理の機会を見ていくと、「自分1人のためだけに作りました」という機会が10パーセント。例えば「自分とパートナー、夫だったり妻だったりのために作ります」と言っているのが全体の調理の13パーセント。プラス、「子ども、幼児の、3人のために作ってますよ」というのが10パーセントという感じで、その時々でいろいろな用途のためにレシピを探していたりするので、それにきちんと対応できるようにすることで、もっと楽に「献立が決まる」というコアの体験を増やせるのではないかと思います。

ほかにも、好き嫌いや時間帯・曜日といった、パーソナライズというよりは、コンテキストに合わせた検索をやることがまだできるのではないかと思います。

以上となります。ご清聴ありがとうございました。

(会場拍手)