【初心者】Amazon OpenSearch Service を使ってみる (基本的なデータ操作)

# 1. はじめに
- 社内にOpenSearchを使ってログ収集・分析をしているシステムがあるが、そもそものOpenSearch(≒ElasticSearch)の仕組みが分からないため、あらためてチュートリアルから実施して、基本的なデータ操作の手順を確認する。

# 2. やったこと
- OpenSearch Service を最小構成で作成する。
- OpenSearch Service のDashboardsを利用し、データの挿入、検索などの基本的な手順を確認する。

# 3. 構成図

![open01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/27c4fad2-4165-d26f-9095-9ce8c91a4233.png)

- 今回は短期的な検証のため、VPC外にOpenSearchドメインを作成し、インターネット経由でアクセスする。(ID/Password認証でのアクセス制限とする)

# 4. 手順

## 4.1 ドメインの作成

- AWS公式ドキュメントの「[Getting Started](https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/gsg.html) 」に従い、最小構成のドメインを作成する。

- ドメインの作成方法：　カスタム作成
- テンプレート：　開発/テスト
- Deployment Options：
    - スタンバイが無効のドメイン
    - アベイラビリティゾーン：　1-AZ
- エンジンオプション：
    - バージョン：　OpenSearch_2.7
- データノード: 
    - インスタンスタイプ: t3.small.search (一番安価なタイプ)
    - ノードの数: 1
    - ノードあたりEBSストレージサイズ:  30 (最小値は10GiB)
- 専用マスターノード：　「専用マスターノードの有効化」のチェックを外す
- ネットワーク：　パブリックアクセス
- きめ細かなアクセスコントロール：　
    - 有効化にチェック
    - マスターユーザの作成：　ユーザ名／パスワードを設定
- アクセスポリシー：　「きめ細かなアクセスコントロールのみを使用」

<details>
  <summary>上記のマネコン設定画面はこちら。(左の▲ボタンを押すと表示)</summary>

  ![open07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/e7385cc7-f0d8-1364-c66e-c50fa03b8557.png)

</details>

## 4.2 データの準備

- 以下のようなデータを入力し、検索できるようにする。※データは[「果物ナビ」](https://www.kudamononavi.com/zukan/strawberry.htm) を参照。

| # | 品種名 | 登録年 | 主な産地 | 説明 |
| --- | --- | --- | --- | --- | 
| 1 | とちおとめ | 1996 | 栃木 | 糖度が高くてほどよい酸味。|
| 2 | あまおう | 2006 | 福岡 | 赤い、丸い、大きい、うまい。|
| 3 | 紅ほっぺ | 2002 | 静岡 | いちご本来の甘っずっぱさを堪能。|
| 4 | さちのか | 2000 | 長崎 | ビタミンC含有量が高い。|

- OpenSearch/ElasticSearch用語として、上記のデータ全体(データベース)が「index」、型の定義(品種名はkeyword、登録年はintegerなど)が「mapping」、1行ごとのレコードが「document」と呼ばれる。

## 4.3 データの入力

- データ操作はcurlやpostmanなどを用いて、OpenSearch Service のエンドポイントにアクセスして行うこともできるが、今回はOpenSearch Serviceに付属してくるDashboards内のDev Toolsを用いる(単純に見やすくて使いやすいため)。
- マネコンに表示される「OpenSearch Dashboards の URL」にアクセスし、ID/Passwordを入力してログインすると以下の画面になるので、Dev toolsを選択する。

![open08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/374bbb13-7047-4e30-1075-89b21016286f.png)

- 左ペインでGET/POSTなどの入力を行うと、結果が右ペインに表示される。
![open09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/2f6762ae-16c5-5f57-f07a-6aca32cf2f13.png)

- index「strawberry」をmappingも含めて作成する。
    - 「品種名」は、検索時に完全一致で検索するため「keyword」とする。
    - 「説明」は、説明文の中の単語で検索できるようにするため、日本語アナライザの「kuromoji」を指定する。

```
PUT /strawberry
{
   "mappings":{
      "properties":{
         "品種名":{
            "type":"keyword"
         },
         "登録年":{
            "type":"integer"
         },
         "主な産地":{
            "type":"text"
         },
         "説明":{
            "type":"text",
            "analyzer": "kuromoji"
         }
      }
   }
}
---
{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "strawberry"
}
```

- indexとmappingが設定されたことを確認する。

```
GET strawberry/_mapping
---
{
  "strawberry": {
    "mappings": {
      "properties": {
        "主な産地": {
          "type": "text"
        },
        "品種名": {
          "type": "keyword"
        },
        "登録年": {
          "type": "integer"
        },
        "説明": {
          "type": "text",
          "analyzer": "kuromoji"
        }
      }
    }
  }
}
```

- 1個目のdocumentを入力する。

```
POST strawberry/_doc/1
{"品種名":"とちおとめ","登録年":1996,"主な産地":"栃木","説明":"糖度が高くてほどよい酸味。"}
---
{
  "_index": "strawberry",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}
```

- 2～4個目のdocumentをバルク(一括)入力する。

```
POST /_bulk
{ "create" : { "_index" : "strawberry", "_id" : "2" } }
{"品種名":"あまおう","登録年":2005,"主な産地":"福岡","説明":"赤い、丸い、大きい、うまい。"}
{ "create" : { "_index" : "strawberry", "_id" : "3" } }
{"品種名":"紅ほっぺ","登録年":2002,"主な産地":"静岡","説明":"いちご本来の甘っずっぱさを堪能。"}
{ "create" : { "_index" : "strawberry", "_id" : "4" } }
{"品種名":"さちのか","登録年":2000,"主な産地":"長崎","説明":"ビタミンC含有量が高い。"}
---
{
  "took": 19,
  "errors": false,
  "items": [
    {
      "create": {
        "_index": "strawberry",
        "_id": "2",
        "_version": 1,
        "result": "created",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "_seq_no": 0,
        "_primary_term": 1,
        "status": 201
      }
    },
    {
      "create": {
        "_index": "strawberry",
        "_id": "3",
        "_version": 1,
        "result": "created",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "_seq_no": 0,
        "_primary_term": 1,
        "status": 201
      }
    },
    {
      "create": {
        "_index": "strawberry",
        "_id": "4",
        "_version": 1,
        "result": "created",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "_seq_no": 0,
        "_primary_term": 1,
        "status": 201
      }
    }
  ]
}
```

## 4.4 データの検索

- 品種名が「あまおう」のdocumentを検索する。

```
GET strawberry/_search
{
  "query" : {
    "term": { "品種名": "あまおう" }
  }
}
---
{
  "took": 114,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "strawberry",
        "_id": "2",
        "_score": 0.2876821,
        "_source": {
          "品種名": "あまおう",
          "登録年": 2005,
          "主な産地": "福岡",
          "説明": "赤い、丸い、大きい、うまい。"
        }
      }
    ]
  }
}
```

- 登録年順にdocumentをソートする。

```
GET strawberry/_search
{
  "sort" : [
      "登録年"
  ]
}
---
{
  "took": 45,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "strawberry",
        "_id": "1",
        "_score": null,
        "_source": {
          "品種名": "とちおとめ",
          "登録年": 1996,
          "主な産地": "栃木",
          "説明": "糖度が高くてほどよい酸味。"
        },
        "sort": [
          1996
        ]
      },
      {
        "_index": "strawberry",
        "_id": "4",
        "_score": null,
        "_source": {
          "品種名": "さちのか",
          "登録年": 2000,
          "主な産地": "長崎",
          "説明": "ビタミンC含有量が高い。"
        },
        "sort": [
          2000
        ]
      },
      {
        "_index": "strawberry",
        "_id": "3",
        "_score": null,
        "_source": {
          "品種名": "紅ほっぺ",
          "登録年": 2002,
          "主な産地": "静岡",
          "説明": "いちご本来の甘っずっぱさを堪能。"
        },
        "sort": [
          2002
        ]
      },
      {
        "_index": "strawberry",
        "_id": "2",
        "_score": null,
        "_source": {
          "品種名": "あまおう",
          "登録年": 2005,
          "主な産地": "福岡",
          "説明": "赤い、丸い、大きい、うまい。"
        },
        "sort": [
          2005
        ]
      }
    ]
  }
}
```

- 説明に「赤い」を含むdocumentを検索する。

```
GET strawberry/_search
{
  "query" : {
    "term": { "説明": "赤い" }
  }
}
---
{
  "took": 21,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "strawberry",
        "_id": "2",
        "_score": 0.2876821,
        "_source": {
          "品種名": "あまおう",
          "登録年": 2005,
          "主な産地": "福岡",
          "説明": "赤い、丸い、大きい、うまい。"
        }
      }
    ]
  }
}
```
- kuromojiの標準設定だと、テキストが以下のように分割されキーワード化される。結果として「赤い」は検索が成功するが、「赤」や「丸」では失敗する。

```
GET strawberry/_analyze
{
  "analyzer": "kuromoji",
  "text" : "赤い、丸い、大きい、うまい。"
}
---
{
  "tokens": [
    {
      "token": "赤い",
      "start_offset": 0,
      "end_offset": 2,
      "type": "word",
      "position": 0
    },
    {
      "token": "丸い",
      "start_offset": 3,
      "end_offset": 5,
      "type": "word",
      "position": 1
    },
    {
      "token": "大きい",
      "start_offset": 6,
      "end_offset": 9,
      "type": "word",
      "position": 2
    },
    {
      "token": "うまい",
      "start_offset": 10,
      "end_offset": 13,
      "type": "word",
      "position": 3
    }
  ]
}
```

# 5. 参考サイト

- [Amazon OpenSearch Service の開始方法](https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/gsg.html)
    - AWS公式ドキュメント。映画のリストを入力して検索する簡単なチュートリアルを実施した。

- [チュートリアル: Amazon OpenSearch Service でドキュメントを作成および検索する](https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/quick-start.html)
    - AWS公式ドキュメント。IDを自動/手動で付与したり、バルク入力したりする練習ができた。

- [AWS Elasticsearch Serviceを使ったElasticsearch超入門 実行編](https://www.granvalley.co.jp/blog/howto_elasticsearch_of_aws_part2)
    - csvをjsonに変えたり、日本語を扱ったりする練習ができた。

- [はじめての Elasticsearch](https://qiita.com/nskydiving/items/1c2dc4e0b9c98d164329)
    - チュートリアル実施中に、CRUD操作や検索操作が分からなくなった時のマニュアルとして。


# 6. 所感
- AWS公式のチュートリアル(映画の題名や出演者の検索)や、その他いくつかのチュートリアル(百人一首の検索)などをやって、「curlでデータ入れたり検索したりできるんだな」レベルの基本的なことができるようになった。
- 実際にシステムで使っているようなログの検索の仕組みも理解を進めていきたい。