OpenSearch でいろいろやってみる ～インデックス編～

# インデックス編
OpenSearchを触ってみた個人的メモ代わりです。

1. [OpenSearch でいろいろやってみる ～インストール編～](https://qiita.com/hwatry/items/cf92a44f48f4dbb54d9d)
2. OpenSearch でいろいろやってみる ～インデックス編～ (👈ココ)
3. [OpenSearch でいろいろやってみる ～絞り込み編～](https://qiita.com/hwatry/items/09b577418495f27ac158)
4. OpenSearch でいろいろやってみる ～Aggregation編～

## データを入れてみる

データの投入、ここがキモだと思ってる。主にマッピング。
RDBMS では SQL により、「正規化」されたデータを「取得する」時に如何様にも操作できるが、
検索エンジン等、多くの NoSQL では、データを適宜「非正規化」して「作る」時に、どういう目的でデータを扱うのか、どういう形で取れるかが決まる。
どっちが良いという話ではなく、思想からしてまるっきり違うということなので慎重に。

## マッピングしてみる

今回は、EC サイト等で見かけるレビューのデータを作ってみようと思う。
レビューのタイトル、本文、商品名、1 ～ 5 までの星数...などのフィールドが考えられる。
以下のようにしてみた。

```json:mappings
PUT reviews
{
  "mappings": {
    "properties": {
      "title": {
        "type": "keyword"
      },
      "comment": {
        "type": "text",
        "fielddata": true,
        "analyzer": "kuromoji",
        "fields": {
          "raw": {
            "type": "keyword"
          }
        }
      },
      "user_name": {
        "type": "keyword"
      },
      "star": {
        "type": "integer"
      },
      "product_cd": {
        "type": "keyword"
      },
      "product_name": {
        "type": "keyword"
      },
      "review_date": {
        "type": "date"
      },
      "is_purchased": {
        "type": "boolean"
      },
      "attrs": {
        "type": "nested",
        "properties": {
          "attrs.name": { "type": "keyword" },
          "attrs.answer": { "type": "keyword" }
        }
      }
    }
  }
}
```

例えば商品の下にレビューをArrayでネストさせて。。。
みたいな形も場合によってはあり得そうだが
今回は自由が利きそうなフラットな形で。

ポイントとしては、任意の属性をattrs としてをネストしているところ、
将来的に全文検索に使えそうな一部フィールドに analyze 設定をしているところ。
本格的に集計・分析に使用する場合はまた違ってくるかもしれないが、
検索・絞り込みメインでとりあえず。


## データを投入してみる

下記のような形式で一括投入可能

```json:_bulk
POST _bulk
{ "index": { "_index": "インデックス名", "_id": "一意のID" } }
{ データのjson }
{ "index": { "_index": "インデックス名", "_id": "一意のID" } }
{ データのjson }
...

```

\_id は任意の値で良ければ省略できる。
\_index も予め指定しておけば省略可(`POST {インデックス名}/_bulk`)
成功すれば`"errors" : false`でレスポンスがあるはず。

### 確認
幾つかデータを入れて試しにクエリー投げてみる。

```json:request
GET reviews/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "product_cd": {
              "value": "SAMPLE0001"
            }
          }
        }
      ]
    }
  }
}
```

↓返ってきた！

```json:response
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 0.24116206,
    "hits" : [
      {
        "_index" : "reviews",
        "_type" : "_doc",
        "_id" : "x5XuIn0B1dg6kvEPVSz5",
        "_score" : 0.24116206,
        "_source" : {
          "title" : "1番目のレビュータイトル",
          "comment" : "レビューのコメントです。いい感じです。",
          "user_name" : "ダミーユーザー１",
          "star" : 1,
          "product_cd" : "SAMPLE0001",
          "product_name" : "サンプル商品",
          "review_date" : "2021-11-19T12:00:00",
          "is_purchased" : true,
          "attrs" : [
            {
              "name" : "年代",
              "answer" : "10代"
            },
            {
              "name" : "性別",
              "answer" : "男性"
            },
            {
              "name" : "お住まい",
              "answer" : "北海道"
            }
          ]
        }
      },
      {
        "_index" : "reviews",
        "_type" : "_doc",
        "_id" : "yJXuIn0B1dg6kvEPVSz5",
        "_score" : 0.24116206,
        "_source" : {
～ 省略 ～
```

## エイリアス
現時点では省略するが、aliasも設定した方が良さ気。
alias:indexは1:Nで定義可能で、indexを分散管理した上でalias指定で横断的に引っ張ってきたりできるみたい。

```json:alias
POST _aliases
{
  "actions": [
    {
      "add": {
        "index": "foo_reviews",
        "alias": "all_reviews"
      }
    },
    {
      "add": {
        "index": "bar_reviews",
        "alias": "all_reviews"
      }
    }
  ]
}
```