Elasticsearchを使用してレシピ検索アプリ

# Elasticsearchを使用してレシピ検索アプリを作りたかった

冷蔵庫に残っている食材から簡単にレシピを検索できるアプリがあったらいいな🤔
レシピ系のAPIでもいいけど条件たくさんだしElasticsearchを使って見たいな🤔

※イメージ
![Untitled (1).png](https://qiita-image-store.s3.amazonaws.com/0/201114/9c6dc5a1-9c28-e32a-f85e-4a6f2a80da32.png)


1.食材を条件に追加し、検索！
2.条件をElasticsearchで検索！
3.結果を表示！（リンクを押すとレシピのサイトに遷移）

...まずはElasticsearchを使ってみないことには始まらない！


## Elasticsearch とは
Elasticsearch は Elastic 社が開発しているオープンソース全文検索エンジン。
大量のドキュメントから目的の単語を含むドキュメントを高速に抽出することができる。

Elasticsearch はSQL文を使用せず、代わりに RESTful インターフェースを使って操作する。

Elasticsearch は検索をはじめ、各種設定やサーバの状態取得など、ほとんどの操作を API として提供している。
ドキュメントの追加・参照・更新・削除の API も提供しており、その仕様はとてもシンプルで直感的。

ドキュメントをあらわすURLスキーマ

```
/{index}/{type}/{id}
```

基本的には、各種ドキュメントのエンドポイントに対して、`GET` `PUT` `POST` `DELETE` `HEAD`メソッドで追加・更新・削除などの操作が可能。

ElasticsearchではRDBとそれぞれの用語が異なる

| Elasticsearch | RDB |
|:--|:--|
| インデックス | データベース |
| タイプ | テーブル |
| フィールド | カラム |
| ドキュメント | レコード |

とりあえずはローカル環境で動かしてみよう

## ローカル環境構築
* 使用バージョン
    * Elasticsearch 2.4.1
* 任意のディレクトリで以下実施

```
curl -L -O https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.4.1/elasticsearch-2.4.1.tar.gz
```
* elasticsearch-2.4.1.tar.gzを解凍

```
tar -xvf elasticsearch-2.4.1.tar.gz
```

* 解凍されたディレクトリの./bin配下で以下実施で起動

```
./elasticsearch
```

## データの登録
本来であればバッチ等でAPIからレシピのJSONデータを取得して自動でElasticsearchにデータ登録していきたいが、今回はローカルなので勉強も兼ねて手動でデータ登録。

### Index生成（データベース）

```
curl -XPUT 'localhost:9200/refrigerator'
```

### Type作成

```
curl -XPUT 'http://localhost:9200/refrigerator/_mapping/recipe' -d '
{
    "properties" : {
      "recipeId" : {
        "type" : "long"
      },
      "recipeTitle" : {
        "type" : "string"
      },
      "recipeUrl" : {
        "type" : "string"
      },
      "foodImageUrl" : {
        "type" : "string"
      },
      "recipeDescription" : {
        "type" : "string"
      },
      "recipeMaterial" : {
        "type" : "string"
      }
    }
}
```

### レシピレコード登録

楽天レシピAPIから取得したレシピを登録（データはマスクしています）

```
curl -XPUT 'localhost:9200/refrigerator/recipe/1?pretty' -d '
{
  "recipeId": xxxxxxxx,
  "recipeTitle": "ダーリンが気に入った♪我が家のポークケチャップ",
  "recipeUrl": "https://recipe.rakuten.co.jp/recipe/xxxxxxx/",
  "foodImageUrl": "https://image.space.rakuten.co.jp/d/strg/ctrl/xxxxxxx",
  "recipeDescription": "ダーリンが「美味しい」と喜んで食べてくれた、とっても簡単に出来るレシピです",
  "recipeMaterial": [
        "豚肉(こま切れ)",
        "たまねぎ",
        "ケチャップ",
        "三温糖",
        "ウスターソース"
  ]
}
```
"カラム", "データ"といった構成。
※直接構文を書くこともできるが、JSONファイルに内容記載してファイルを指定することも可能。
例）`curl -XPUT 'http://[エンドポイント]/[Index名]/[Type名]/[Id]' -d 'JSONのデータ'`


## 実際に検索してみる

```
curl -XPOST 'localhost:9200/refrigerator/recipe/_search?pretty' -d '
{
  "query": { "match": { "recipeMaterial": "たまねぎ 豚肉" } }
}
```

### 結果

```
{"took":29,"timed_out":false,"_shards":{"total":1,"successful":1,"failed":0},"hits":{"total":1,"max_score":0.84996772,"hits":[{"_index":"refrigerator","_type":"recipe","_score":0.14996772,"_source":
{
  "recipeId": xxxxxxxx,
  "recipeTitle": "ダーリンが気に入った♪我が家のポークケチャップ",
  "recipeUrl": "https://recipe.rakuten.co.jp/recipe/xxxxxxx/",
  "foodImageUrl": "https://image.space.rakuten.co.jp/d/strg/ctrl/xxxxxxx",
  "recipeDescription": "ダーリンが「美味しい」と喜んで食べてくれた、とっても簡単に出来るレシピです",
  "recipeMaterial": [
        "豚肉(こま切れ)",
        "たまねぎ",
        "ケチャップ",
        "三温糖",
        "ウスターソース"
  ]
}
```
Elasticsearchでは検索時のパフォーマンスも同時に表示してくれるよう。
`max_score`では一致率を出してくれるため実際にアプリで使用するときはたくさん取れすぎると困るので、この項目を使用すれば高い検索結果が得られそう。

## 検索できた！
これをアプリ側からの条件を食わせてあげればレシピを検索してくれるはず


# アプリ側の実装
言語はC#
データはElasticsearch



## まずは画面を...


**時間切れ**
せっかくここまで来たので続きの開発の内容は随時更新していく

## 所管
RDBしか触ったことがなかったのでElasticsearchの汎用性の高さに驚いた。
また今回はローカル環境でデータ数も少しだったので実感できなかったがパフォーマンス面でも大量のデータを扱うときは便利そう。
`Amazon Elasticsearch Service`というのもあるらしいのでサーバ側で登録して見たい。
これを生かして冷蔵庫レシピアプリを是非とも開発したい。（料理全くしないんですけどね（小声））


## 参考記事
* https://qiita.com/nskydiving/items/1c2dc4e0b9c98d164329