REQLY開発ブログ

プロの料理レシピ専門検索エンジンREQLY(レクリー)の開発ブログです。

REQLY料理日記 〜親子丼編〜

背景

冷蔵庫に卵がある。

卵といえば親子丼だろう。

REQLYで「親子丼」と入力して検索したら、色々な種類の親子丼が出てくる。逆にこれだけ親子丼が登場してしまうと、どれにすればいいか決めるのは難しい。

f:id:reqly-tokyo:20180618173826p:plain

こう言う時に、REQLYの出番だ。左側に検索フィルタというものがあるのに気づかれた方はいらっしゃるだろうか。

f:id:reqly-tokyo:20180618174231p:plain

フィルタしたい要素をクリックして選択すると、色が変わるので選んでいることがわかる。そして、「この条件で検索する」ボタンをクリックする。スマホユーザーの方は「適用」ボタンをタップすればよい。今回は敢えて、「難しい」メニューを選択してみた。

f:id:reqly-tokyo:20180618140927p:plain

なぜこれが「難しい」に分類されているのだろうか。その謎を探るべく、実際に作ってみることにした。

reqly.tokyo

手法

鶏もも肉: 160円 卵: 50円弱 → 約200円となり、予測された金額とだいたい合致していた。

調理していて気づいたことがあるが、白ごはん.comはかなりおおざっぱなレシピである。これはおそらく、ある程度料理のできるユーザがこのレシピをみて、おおざっぱにコツをつかむのにはかなり適している。しかし初心者にとっては、何分ぐらい火に掛ければいいかというのが分からないこともあるだろう。そういう意味では、このレシピは上級者向きであり、「難しい」と分類されてもおかしくないだろう。

このように、レシピサービスごとの違いをもとに、自分にあったレシピサービスを探すことができるのもREQLYを使うメリットである。検索フィルタの下ではレシピサイトをフィルタリングできるので、自分好みのレシピサービスで検索してもらいたい。

f:id:reqly-tokyo:20180618173635j:plain

親子丼向けの鶏もも肉を煮込み、最後に卵を割って混ぜる。

結果

f:id:reqly-tokyo:20180618143145j:plain

うに丼みたいな見た目になった*1

見た目という点で、三つ葉を導入することが重要であるということがわかった。

*1:これはレシピ側の問題ではなく、あくまで作る側の問題であったことを、念のため断っておく

REQLY料理日記 〜じゃがいもの油揚げ包み編〜

背景

REQLYで、じゃがいもを利用した料理を探してみた。

今回はレシピ重視で、これは作ってみたい!と思うレシピがでるまでひたすらザッピングするという方法を選択した。

https://reqly.tokyo/?cost=0&food=0&procedure=0&search=%E3%81%98%E3%82%83%E3%81%8C%E3%81%84%E3%82%82&time=0

f:id:reqly-tokyo:20180617183031p:plain

7ページ目で、ついに出会った。

f:id:reqly-tokyo:20180617183059p:plain

これにしよう。

手法

予測された所要時間は30分とあったが、実際は20分ぐらいで作ることができた。これはクラシルでの工程の説明が多いので、料理に時間がかかるように推定されてしまったのだろう。これは今後の修正課題である。

コストについていえば300円と予測されていたが、チーズ: 50円弱、油揚げ: 50円弱、 じゃがいも: 前回の残り ということで、余った分をうまく使い切ることができるならば、十分リーズナブルだろう。

調理風景。

まずはじゃがいもの皮をむき、じゃがいもを電子レンジで加熱する。

f:id:reqly-tokyo:20180617185129j:plain

できたじゃがいもは、フォークで潰して、チーズと混ぜられて油揚げ送りにする。そして、油揚げごと焼く。

f:id:reqly-tokyo:20180617185154j:plain

最後に味を調え、できあがり。

結果

f:id:reqly-tokyo:20180617185219j:plain

溶けたチーズとじゃがいもが、甘辛い油揚げに包まれていて、その調和が絶妙にじゃがいも本来の食材の味を引き立てており、非常に美味であった。

f:id:reqly-tokyo:20180617185231j:plain

ちゃんと美味なものを作ることができるようになってきた。だが、美味しい料理を作ることと、見た目が美味しい料理を作ることには、また別の次元の難しさがあるということを認識した。

しょう油は焦げがちである。

REQLY料理日記 〜ベーコン肉じゃが編〜

はじめに

REQLYは料理を作る皆さんのための、レシピ検索を便利にするための検索エンジンです。REQLYを使って、複数のプロのレシピサイトから自分が作りたい料理を選ぶことができます。

では、どうやってREQLYを使ってレシピを選ぶんだろう?と思われる方もいらっしゃるでしょう。ここでは、開発者が自らREQLYを使って自分が見つけたいと思っていたレシピに簡単にたどり着いた実例を紹介するとともに、そのレシピをもとに作った料理を紹介したいと思います!

レシピを見つけよう

reqly.tokyo

まずはREQLYにアクセスしてみましょう。使い方は簡単です! このトップページの検索バーに、食材や作りたい料理名を入力して、検索ボタンをクリックするだけです。

試しに、何か検索してみましょう。冷蔵庫をみてみると、ちょうどベーコンがありました。これは前もって購入していたものですが、塊で買ってしまうとなかなか使い切るのに悩みます。そこで、今回はベーコンを利用するレシピを探してみたいと思います。

f:id:reqly-tokyo:20180617141938j:plain

検索される結果は、検索ワードとの類似性や人気など、複数の基準をもとに、より上に並んでいるレシピほど、その検索条件のなかでオススメしているレシピになります。中央に縦に並んでいるのがレシピカードですが、このカードにマウスカーソルを合わせると、そのレシピに必要な材料や、REQLYがそのレシピをもとに付与した分類が、タグという形で右側に表示されるようになっています。

f:id:reqly-tokyo:20180617142552p:plain

レシピの画像、所要時間や材料といった複数の情報を見比べながら、作りたい料理を選びましょう*1

また、気に入った料理は無料会員していただくことで、お気に入り登録することができます。レシピの右上のハートボタンをクリックすることでお気に入り登録できます。お気に入り登録すると、自分の気に入った料理を集めた自分だけのレシピ集を作ることができるというイメージです。なので、作った料理をリストにまとめておきたいとか、次に作りたい料理をまとめておくといった使い道があります。

作ってみよう

https://reqly.tokyo/?cost=0&favorite=false&food=0&procedure=0&search=%E3%83%99%E3%83%BC%E3%82%B3%E3%83%B3&time=0

f:id:reqly-tokyo:20180617143341p:plain

今回は、上の検索結果でフォーカスしている「ベーコン肉じゃが」を作ってみました。このレシピを選んだのは、検索結果の上の方にでてきたというのが大きな理由ですが、それ以外にも、実際に材料を確認してちょうど手元にあるものが揃っているというのも、大きな選択理由になりました。このように材料カードをうまく利用することで、それぞれのレシピをいちいち確認しなくても、材料をもとに作れそうか判断することができるようになります。

まずはお買い物です。このレシピカードには400円とかいてありますが、これはREQLYが材料をもとに予測したコストとなります。私が購入した時にはじゃがいも100円、ベーコン100円弱、玉ネギ50円程度でした。これに調味料や、季節毎に変動するコストが入るので、それほど大きく外した値ではないと思います。

調理風景

f:id:reqly-tokyo:20180617184038j:plain

こちらは実際に料理を作っている風景になります。

じゃがいもの皮むきが大変でした。ちょうど値段が安かったので小粒なじゃがいもを購入したのですが、大粒のじゃがいもに比べて体積あたりの表面積が大きくなってしまうため、皮むきの手間が増えてしまうことは誤算でした。

調理時間は、レシピカードには30分とありました。煮込む時間自体はほとんどそれだけですが、じゃがいもの皮むきやその他の準備などにもたつくことがあるので、料理になれない初心者だともう少し多めに時間を見積もっておいたほうがよいでしょう。私も実際にはもう少し時間がかかりましたが、慣れて効率よくそれぞれの作業を行えるようになると、その時間は短縮できると思いました!

できあがり

十分に火が通り、味が通ったことを確認して器に取り分けました。

f:id:reqly-tokyo:20180617184118j:plain

f:id:reqly-tokyo:20180617184215j:plain

拡大してみました。

肉じゃがといえば、日本の東西で豚肉を使うか牛肉を使うか議論になるように、作り方に地域差や家庭毎の差が出る料理です。肉じゃがといえば豚肉の地域で育ちましたが、ベーコン肉じゃがを食べたことはありませんでした。そういった意味ではベーコンを使った肉じゃがは若干変則的ではありますが、厚切りベーコンを噛むとしっかり味が染み出してきて、ジャガイモや玉ネギの風味も相まってとてもおいしい夕飯になりました。

f:id:reqly-tokyo:20180617184324j:plain

また、たくさん作って冷蔵庫に作り置きしておくことも可能なので、平日忙しい方にもオススメの一品です。今回は二人前作ったので、残りは冷蔵して後日のおかずになりました。

このように、REQLYを使えば、料理を作りたいと思った瞬間にレシピを探し始めることができます。REQLYはレシピ選択で悩む皆さんをお助けするのもそうですが、そもそも料理をしないという皆さんも、ぜひREQLYを料理を始めるきっかけにしてみてください!

*1:この検索結果は2018/06/17現在の情報なので、いまアクセスすると当時とは異なる検索結果が出力される可能性があります。予めご承知下さい。

material-uiによる検索モード搭載のAppBarの実装

はじめに

REQLYではGoogleの提唱するマテリアルデザインに基づいた実装が行われています。material-uiは、マテリアルデザインを構成するUIパーツのReactライブラリであり、REQLYではスマホ版のAppBarなどの実装に取り入れられています。material-uiの1つ1つのコンポーネントの使い方は、公式のDemoページにサンプルコードと共に丁寧に書かれていますが、どのようにして複数のコンポーネントを組み合わせて実用的なデザインを組み上げていくのか、という実践的な内容についての情報は多くありません。今回は、REQLYのAppBarを例にmaterial-uiの実践的な使い方をしっかり説明していきたいと思います。


完成品

Dockerによって再現可能なコードをGitHub - ReqlyTokyo/appbarにて公開しています。

 

f:id:reqly-tokyo:20180616201005g:plain



実装詳細

1. DockerによるReact開発環境の作成

まずは、Dockerを用いて逐次実行可能なポータブルなReact環境を作成するところから始めよう。facebookが公開しているcreate-react-appというコマンドを使えば、開発のベースとなるReactアプリケーションを簡単に作成することができる。create-react-appコマンドのインストール方法は公式ページを参照されたい。

create-react-app myapp
cd myapp
npm start

これによりhttp://localhost:3000/にデフォルトページが立ち上がるはずだ。

次にこのアプリケーションをDockerfileとdocker-compose.ymlを使ってコンテナ化しよう。

Dockerfile
FROM node:9
WORKDIR /myapp

COPY ./myapp/package.json .
RUN npm install
CMD ["npm", "start"]

./myapp/package.jsonはReactプロジェクトに必要なライブラリの依存関係等が記述されたファイルで、npm installをRUN命令で実行することで、必要なライブラリがインストールされたDockerイメージを作成できる。

docker-compose.yml
myapp:
    build: .
    ports:
     - "3000:3000"
    volumes:
     - ./myapp/src:/myapp/src
     - ./myapp/public:/myapp/public

3000番ポートの公開のほか、volumes命令によって./myapp/src./myapp/publicをそれぞれマウントしている。これにより、Dockerコンテナを立ち上げた状態でホスト側で./myapp/src./myapp/public以下のファイルを編集したときに、リアルタイムで更新が走るようにできる。



2. material-uiによる必要なUIコンポーネントの実装

material-uiの導入

./myapp/package.jsonに新たに@material-ui/core - npm@material-ui/icons - npmへの依存関係を定義する。coreだけでなくiconsも使えば、マテリアルデザイン公式アイコン集を簡単に実装に組み込むことが可能になる。

"dependencies": {
    "@material-ui/core": "^1.2.0",
    "@material-ui/icons": "^1.1.0",
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-scripts": "1.1.4"
}

上の2行をdependenciesに追記した状態でdocker-compose buildを実行すれば、無事に必要なライブラリが揃ったDockerイメージが作られる。

次に通常モードと検索モードを表現するクラスをそれぞれ独立に実装していこう。

通常モードの実装(appbar/DefaultBar.js at master · ReqlyTokyo/appbar · GitHub

イメージに非常に近いものがDemoページの3番目に既に実装されている。MenuIconを廃止し、SearchIconを新たに導入すれば、ほとんどイメージに近いものが得られる。この段階ではSearchIconにonClickが定義されていないので遷移自体は起こらないが、マテリアルデザインに基づいたクリック時のエフェクトなどが既に自動的に付与されていることが分かるだろう。

検索モードの実装(appbar/SearchBar.js at master · ReqlyTokyo/appbar · GitHub

検索ウィンドウ自体はmaterial-uiに実装されていないが、material-uiを用いて実装された検索ウィンドウがMITライセンスで公開されている。これについても、一番左にBackIconを追加するだけで、ほぼイメージ通りの検索バーを実装することができる。



3. AppBarの出し分けの実装

Default.jsとSearchBar.jsが定義されたので、あとはこの2つを出し分ける親クラス(ReqlyAppBar.js)を実装すれば目的は達成できる。

親クラスの実装(appbar/ReqlyAppBar.js at master · ReqlyTokyo/appbar · GitHub

class ReqlyAppBar extends React.Component{
  state = {
    search: false,
  };

  handleChange = event => {
    console.log("handleChange called!");
    this.setState({ ['search']: !this.state.search });
  };

  render () {
    if (this.state.search) {
      return (
        <SearchBar
          onChange={() => console.log('onChange')}
          onRequestSearch={() => console.log('onRequestSearch')}
          onHandleChange={this.handleChange}
        />
        );
    } else {
      return (
        <DefaultBar
          onHandleChange={this.handleChange}
        />
      );
    }
  }
}

export default ReqlyAppBar;

ReqlyAppBarは、searchというbooleanのstateを持ち、それがTrueだった場合は検索モード、Falseだった場合は通常モードを描画するクラスだ。searchを反転させる関数であるhandleChangeをコールバック関数としてSearchBar, DefaultBarの呼び出し時に渡していることが分かるだろう。あとは、検索アイコンまたは戻るボタンがクリックされた場合に、このコールバック関数を発火するようにすれば、ReqlyAppBarクラスのstateが変更されてReqlyAppBarが再描画され、2つのモードが切り替わることとなる。クリック時の発火はそれぞれのIconButtonのonClickパラメタにて登録できる。

SearchBar.js

<IconButton
  onClick={this.props.onHandleChange}
>
  <BackIcon />
</IconButton>

DefaultBar.js

<IconButton
  onClick={this.props.onHandleChange}
>
  <Search />
</IconButton>

以上により、サーチモードに切り替え可能なAppBarが無事実装できた。



おわりに

REQLYではAppBarの他にもレシピカードなどにmaterial-uiが使用されています。是非使ってみてください! reqly.tokyo

クックパッドから紐解く食材・調味料の入手困難度

はじめに

 こんにちは!エンジニアのkenboです。

 第1回目のブログとなりますので、簡単にREQLY(レクリー)について説明させていただきます。REQLYは、ウェブ上に公開されたプロの料理家によるレシピの中から希望のレシピを効率的に見つけ出す検索プラットフォームを提供しています。ぜひ、一度使ってみてください!

 

食材・調味料のレア度について

 第一回目の内容は、料理で使われている食材・調味料のレア度についてです。普段レシピ検索サイトを使っていて、せっかく作りたい料理を見つけたのに詳細を見てみると食材・調味料が足りなくて作れないということがありますよね。こんな時に、料理を選んでいる段階で珍しい食材が何か教えてくれたら便利ではないでしょうか。REQLYでは、レシピカードにカーソルをホバーした時に画面右側に材料カードと呼ばれるものが表示されます(図1)。

 

f:id:reqly-tokyo:20180615154222p:plain

図1 webページ版トップ画面の説明

 

この材料カードには、料理に必要な食材が表記されているだけでなく一般の家庭になさそうな食材の左側には?マークが表示されるようになっています(図2)。これらのハテナ食材をもとに、料理の詳細を見るのか、買い物に行くスーパーをどこにするのかなどを考えてもらえればと思います。

 

f:id:reqly-tokyo:20180615145136p:plain

図2 材料カードの例

 

ハテナ食材の推定について

 では、実際にどのようにしてハテナ食材を推定しているのか説明します。REQLYでは、一般的な家庭にあまりない食材・調味料は、レシピサイトにおいて出現回数が少ないという仮定のもとハテナ食材を推定しています。一般的な家庭にあるかという点を判断基準とするため、ユーザー投稿型で290万件以上のレシピが掲載されているクックパッドのデータを用いることにしました。

 まず、レシピによって食材名の表記にばらつきがあるため、解析、検索の精度向上のためにはオントロジーを定義する必要があります。例えば、調味料の味覇では10個ほどの表現方法があります。これらを全て同一の食材と認識するため、オントロジーテーブルを作成しました。

 

           f:id:reqly-tokyo:20180615145210p:plain

図3 食材オントロジーの概念図

 

 その後、食材を6種類のカテゴリ (主食、魚類、肉類、野菜、調味料、その他)に分けました。このブログでは、調味料について見ていきます。調味料はオントロジーテーブルを用いて約70種類に分類されます。それらについて、出現頻度を見ると次のような結果が得られました (図4)。結果を見ると大きく3つの領域に分けられそうです。赤色と黄色の領域の境界線の決め方は少し難しいですが、全体的に一般家庭の調味料の在庫状況を反映できていると思います。

f:id:reqly-tokyo:20180615145222p:plain

図4   クックパッドでの調味料の出現頻度

 今回は調味料を例に見ましたが、他のカテゴリについても出現頻度から一般家庭の食材事情が見えそうです。REQLYではこれらの出現頻度をもとに各食材・調味料に対して入手困難度をスコア化しています。このスコアをもとに、前述の材料カード上でハテナ食材を表示したり、検索フィルターとしてシンプルな食材のみで作れるレシピだけに絞り込むということを実現しています。

 

 

おわりに

 第一回目のブログでは、材料カードに記載された?マークの意味とその導出方法について説明させていただきました。次回のブログでは、検索フィルタで用いられている各フィルタの推定器について説明していきたいと思います。