PythonとOpenSearch®を使って検索クエリを書き、おいしいレシピを見つけよう

<font color="Grey">*[Write search queries with Python and OpenSearch® to find delicious recipes](https://aiven.io/blog/opensearch-dinner-party)の翻訳です。*</font>

OpenSearch®を使用して、半構造化レシピデータに対して簡単な検索と高度な検索の両方を実行し、そこから完璧なメニューを作成する方法については、こちらをお読みください。

# PythonとOpenSearch®を使って検索クエリを書き、おいしいレシピを見つけよう

検索デベロッパーセンター

## PythonとOpenSearch®で完璧なディナーパーティーをしよう


### はじめに


ディナーパーティーを計画するとき、私はゲストに素晴らしい体験をしてもらいたい。食材、ゲストの食事制限、好みをチェックする必要がある。もしあなたも、特別なディナーを計画するのは難しいと感じているなら、ぜひ試してみてください。


このブログでは、Pythonicな方法で美味しいレシピを見つける方法を紹介します。データ、Python、そしてOpenSearch®の力があれば、完璧なディナーパーティーを計画することができます！


この学習の旅のサポート教材は便利な[CLIアプリケーション](https://github.com/Aiven-Labs/demo-opensearch-python)で、OpenSearchの一般的なクエリの種類を調べたり、自分で実行することもできます。


### はじめに


検索結果は、データセットと同じくらい良いものでなければならないという意見があるかもしれない。[Epicurious](https://www.kaggle.com/datasets/hugodarwood/epirecipes?select=full_format_recipes.json)の高品質なデータセットを使用します。このデータセットには20,000以上のレシピ、評価、栄養情報が含まれています。


AivenのフルマネージドOpenSearchサービスを使ってクラスタを立ち上げ、稼働させるつもりです。[demo](https://github.com/Aiven-Labs/demo-opensearch-python)を用意しました。接続、データ送信、検索クエリを実行するすべてのコードが含まれています。


プロジェクトの[README.rst](https://github.com/Aiven-Labs/demo-opensearch-python/blob/main/README.rst)に全て説明されているので、クエリを理解することだけに集中できます。


### OpenSearch クラスタにデータを取り込む


最初のステップは、OpenSearch クラスタにデータをロードして、クエリを開始することです。データをクラスタにロードする方法は、[Python クライアントを使う](https://developer.aiven.io/docs/products/opensearch/howto/sample-dataset.html#load-the-data-with-python) を参照してください。


さて、データを使って遊び始めましょう！


### レシピの検索


祖父が来るという噂があるので、ナトリウムを控えたレシピをひとつくらいは用意しなければと思っている。低ナトリウムの食事は血圧を下げるために推奨されているが、一般的に、これは誰にとっても良い健康的な選択肢である。


range`関数を使うと、フィールドの値（この場合は`ナトリウム`）が一定の範囲内にある文書を見つけることができる。


1食あたりのナトリウム量が140ミリグラム以下のレシピは低ナトリウム食とみなされます。そこで、100 - 140 mg前後のレシピを探し、このクエリを次のように構築してみましょう：



```
{
   "query":{
      "range":{
         "sodium":{
            "gte":100,
            "lte":140
         }
      }
   }
}
```

デモプログラムを使って、`range`クエリの動作を確認することができる：



```
python search.py "sodium" 100 140
```

この条件でどのようなレシピが得られるか興味がある：



```
['Salsa Verde ',
 'Green Bean and Red Onion Salad with Warm Cider Vinaigrette ',
 'Toasted-Pecan Pie ',
 'Provençal Chicken and Tomato Roast ',
 'Sauteed Cod Provençale ',
 'Roasted Potatoes and Asparagus with Parmesan ',
 'Sweet-and-Sour Baby Carrots ',
 'Ricotta Puddings with Glazed Rhubarb ',
 'Butternut Squash and White Bean Soup ',
 'Turkish Zucchini Pancakes ']
```

トルコ風ズッキーニのパンケーキ」はおいしそうなレシピなので、これを選びます。


あと、この日のために美味しいサラダのレシピを見つけなきゃ🥗。大根の季節だし、この野菜は夏のサラダによく合うから、`match_phrase`を使って「大根のサラダ」を含む「タイトル」を探してみよう。



```
{
   "query":{
      "match_phrase":{
         "title":{
            "query":"Salad with radish"
         }
      }
   }
}
```

デモプログラムを使ってこのクエリーを実行することができる：



```
python search.py match-phrase "title" "Salad with Radish"
```

検索結果がこちらです：



```
['Green Bean and Red Onion Salad with Radish Dressing ']
```

マッチしたのは1つだけで、大根はドレッシングの一部だけのようだ。その理由は、`match_phrase`を使うときに単語の順番が重要だからです。この場合、`Salad with Radish`というフレーズは一度しか出てこないので、結果は一回だけである。


検索に柔軟性を持たせることで、この問題を解決することができる。match_phrase`には強力な機能があり、検索語同士の距離を定義することができる。このパラメータは `slop` (default=0) と呼ばれる。では、`slop`パラメータを3にしてもう一度試してみよう。



```
{
   "query":{
      "match_phrase":{
         "title":{
            "query":"Salad with radish",
            "slop":3
         }
      }
   }
}
```

デモプログラムを使ってこのクエリーを実行することができる：



```
python search.py match-phrase "title" "Salad with Radish" --slop 3
```

驚くことではないが、今回はより多くの検索結果が得られた：



```
['Green Bean and Red Onion Salad with Radish Dressing ',
 'Winter Salad with Black Radish, Apple, and Escarole ',
 'Avocado Radish Salad with Lime Dressing ',
 'Chickpea Salad Sandwich With Creamy Carrot-Radish Slaw ',
 'Mâche, Frisée, and Radish Salad with Mustard Vinaigrette ',
 'Frisée and Radish Salad with Goat Cheese Croutons ',
 'Endive, Mâche, and Radish Salad with Champagne Vinaigrette ',
 'Butter Lettuce and Radish Salad with Fresh Spring Herbs ',
 'Butter Lettuce and Radish Salad with Lemon-Garlic Vinaigrette ',
 'Shaved Carrot and Radish Salad With Herbs and Pumpkin Seeds ']
 ```

これで、"Radish Salad with"、"Salad with `<something else>` Radish "といった具合に結果が一致する。  

どれかひとつを選んで、デザートを探しに進むことができる。


それでは、`match`関数がどのように機能するのか、"title "に "Chocolate Carrot Cake "を検索するクエリーを作ってみよう。



```
{
   "query":{
      "match":{
         "title":{
            "query":"Chocolate Carrot Cake",
            "operator": "and"
         }
      }
   }
}
```

match`パラメータは、"Chocolate Carrot Cake" ᥕに近い順に結果を表示します。デフォルトでは、`match`は "OR "演算子を使用し、"Chocolate "か "Carrot "か "Cake "の結果を返します。しかし、検索時にこれらの用語をすべて「タイトル」に含めたい。そのためには「AND」演算子を使えばよい：



```
['Chocolate-Orange Carrot Cake ',
 'Milk Chocolate Semifreddo with Star Anise Carrot Cake ']
```

ケーキの検索結果です。



```
['Chocolate-Orange Carrot Cake ',
 'Milk Chocolate Semifreddo with Star Anise Carrot Cake ']
```

どれもおいしそうで、パーティーの準備は万端です🥳！夕食は何？自分で検索クエリを書いて遊んで、自分の完璧なディナーを見つけることができます。


それでは皆さん、ごちそうさまでした！


## 例とその他のリソース


* [GitHubリポジトリでコードサンプルを探す](https://github.com/Aiven-Labs/demo-opensearch-python)
* [チュートリアルを続けて、[データクエリの方法を学ぶ](https://docs.aiven.io/docs/products/opensearch/howto/opensearch-search-and-python)
* [Aiven for OpenSearchのドキュメントリソースを探す](https://docs.aiven.io/docs/products/opensearch)


[Aiven for OpenSearch](https://aiven.io/opensearch)を使い始めるには、無料トライアルにサインアップしてください。