[調査メモ]Elasticsearchで配列を扱うクエリ

# やりたいこと

`["a","b","c"]`や`[1,2,3]`といった配列を扱うフィールドをインデックスに用意したい


## 話を進める前に公式ドキュメントを読む

配列に関しては[こちらの公式ドキュメント](https://www.elastic.co/guide/en/elasticsearch/reference/master/array.html)に記載がある
まずそちらの内容を確認する

### integerやkeywordで定義されたフィールドには複数の値を含めることができる

Elasticsearchにおいては`array`という特定の型は用意されていないが、integerやkeywordで定義されたフィールドに複数の要素を投入することができる
例えば`["a","b","c"]`という配列はもちろん`[{"id": 1, "name": "Mary"},{"id": 2 "name": "Juan"}]`といったオブジェクトの配列を入れることもできる

ただし以下のような注意点がある

- 配列内のデータ型は一意に定まっていないといけない（例: 数値と文字列を混合した[1,"sample"]みたいな配列の投入は不可）
- オブジェクト配列の場合想定通りの挙動にならないことが多いため、基本的にはnestedの使用が推奨される
- 空の配列はmissing fieldとして扱われる

### なぜintegerやkeywordで定義された型に複数の値を入れることができるのか

同じドキュメントの下部で説明されている[^1]
簡潔に述べると以下の通り

- Luceneが文章中の単語を転置インデックスに登録する都合上、単純なtext fieldであっても複数の値が格納されることをデフォルトでサポートしていた
- 後から他のデータ型を追加する際もその構成が引き継がれた


# ここからやること（これが本題）

投入できることはわかったので、ここからは実際の検索がどうなるかを小さいサンプルを用いて確認していく
①数値型（integer）、②文字列型（keyword）のそれぞれでみていく
オブジェクト型の検証は時間の都合上今回の対象から外している

## integer

integerで定義された型に配列を入れる場合とnestedの子に定義されたフィールドに値を入れる場合の2通りで挙動の違いを調べる
ここで確認したいことは以下の通り
- 配列（およびnested内の配列／以下同じ）にある値以上の要素を含むドキュメントの検索
- 配列内の要素がN個以上であるドキュメントの検索
- 配列が空orNULLであるドキュメントの検索


以下のような二通りのインデックスを作成して調査をする

```json
# 下準備
PUT /integer-index
{
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 1,
    "index.write.wait_for_active_shards": 1
  },
  "mappings": {
    "contents": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "array_field": {
          "type": "integer"
        }
      }
    }
  }
}


PUT /integer-index-nested
{
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 1,
    "index.write.wait_for_active_shards": 1
  },
  "mappings": {
    "contents": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "nested_field": {
          "type": "nested",
          "properties": {
            "array_field": {
              "type": "integer"
            }
          }
        }
      }
    }
  }
}
```

投入するデータは以下の通り

<details>
  <summary>integerの分</summary>

```json
POST /integer-index/_doc
{"id": 1, "array_field": [100,200,300]}
POST /integer-index/_doc
{"id": 2, "array_field": [200,300,400]}
POST /integer-index/_doc
{"id": 3, "array_field": [300,400,500]}
POST /integer-index/_doc
{"id": 4, "array_field": [400,500,600]}
POST /integer-index/_doc
{"id": 5, "array_field": [500,600,700]}
POST /integer-index/_doc
{"id": 6, "array_field": [600,700,800]}
POST /integer-index/_doc
{"id": 7, "array_field": [200,200,400]}
POST /integer-index/_doc
{"id": 8, "array_field": [500,500,600]}
POST /integer-index/_doc
{"id": 9, "array_field": [200,300,400,500]}
POST /integer-index/_doc
{"id": 10, "array_field": [300,300,400,500]}
POST /integer-index/_doc
{"id": 11, "array_field": []}
POST /integer-index/_doc
{"id": 12, "array_field": null}
POST /integer-index/_doc
{"id": 13}
```

</details>

<details>
  <summary>nestedの分</summary>

```json
POST /integer-index-nested/_doc
{"id": 1, "nested_field": [{"array_field": 100},{"array_field": 200},{"array_field": 300}]}
POST /integer-index-nested/_doc
{"id": 2, "nested_field": [{"array_field": 200},{"array_field": 300},{"array_field": 400}]}
POST /integer-index-nested/_doc
{"id": 3, "nested_field": [{"array_field": 300},{"array_field": 400},{"array_field": 500}]}
POST /integer-index-nested/_doc
{"id": 4, "nested_field": [{"array_field": 400},{"array_field": 500},{"array_field": 600}]}
POST /integer-index-nested/_doc
{"id": 5, "nested_field": [{"array_field": 500},{"array_field": 600},{"array_field": 700}]}
POST /integer-index-nested/_doc
{"id": 6, "nested_field": [{"array_field": 600},{"array_field": 700},{"array_field": 800}]}
POST /integer-index-nested/_doc
{"id": 7, "nested_field": [{"array_field": 200},{"array_field": 200},{"array_field": 400}]}
POST /integer-index-nested/_doc
{"id": 8, "nested_field": [{"array_field": 500},{"array_field": 500},{"array_field": 600}]}
POST /integer-index-nested/_doc
{"id": 9, "nested_field": [{"array_field": 200},{"array_field": 300},{"array_field": 400},{"array_field": 500}]}
POST /integer-index-nested/_doc
{"id": 10, "nested_field": [{"array_field": 300},{"array_field": 300},{"array_field": 400},{"array_field": 500}]}
POST /integer-index-nested/_doc
{"id": 11, "nested_field": []}
POST /integer-index-nested/_doc
{"id": 12, "nested_field": [{"array_field": null}]}
POST /integer-index-nested/_doc
{"id": 13}
```

</details>


### ある値以上の要素をもつドキュメントを検索

例えば「配列には購入した商品の価格が入る」「配列にはテストの点数が入る」みたいな使い方をしている場合に「XXXX円以上の商品を購入した履歴を抽出」「XX点未満の得点を持っている受験者を抽出」みたいなことをする場合に使う
「配列内のMin/MaxがXX以上」みたいな検索もこの方法でできそう

integer型の場合
```json
GET /integer-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "array_field": {
              "gte": 600
            }
          }
        }
      ]
    }
  }
}
```

<details>
    <summary>検索結果</summary>

```json
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "CMGrsX8B2mat8b4UZq1t",
        "_score" : 1.0,
        "_source" : {
          "id" : 4,
          "array_field" : [
            400,
            500,
            600
          ]
        }
      },
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "CcGrsX8B2mat8b4UZq2W",
        "_score" : 1.0,
        "_source" : {
          "id" : 5,
          "array_field" : [
            500,
            600,
            700
          ]
        }
      },
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "CsGrsX8B2mat8b4UZq2z",
        "_score" : 1.0,
        "_source" : {
          "id" : 6,
          "array_field" : [
            600,
            700,
            800
          ]
        }
      },
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "DMGrsX8B2mat8b4UZq3Z",
        "_score" : 1.0,
        "_source" : {
          "id" : 8,
          "array_field" : [
            500,
            500,
            600
          ]
        }
      }
    ]
  }
}

```

</details>



nestedの場合

```json
GET /integer-index-nested/_search
{
  "query": {
    "nested": {
      "path": "nested_field",
      "query": {
        "bool": {
          "must": [
            {
              "range": {
                "nested_field.array_field": {
                  "gte": 600
                }
              }
            }
          ]
        }
      }
    }
  }
}
```

<details>
    <summary>検索結果</summary>

```json
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "FcGrsX8B2mat8b4U-q2j",
        "_score" : 1.0,
        "_source" : {
          "id" : 4,
          "nested_field" : [
            {
              "array_field" : 400
            },
            {
              "array_field" : 500
            },
            {
              "array_field" : 600
            }
          ]
        }
      },
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "FsGrsX8B2mat8b4U-q3F",
        "_score" : 1.0,
        "_source" : {
          "id" : 5,
          "nested_field" : [
            {
              "array_field" : 500
            },
            {
              "array_field" : 600
            },
            {
              "array_field" : 700
            }
          ]
        }
      },
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "F8GrsX8B2mat8b4U-q3d",
        "_score" : 1.0,
        "_source" : {
          "id" : 6,
          "nested_field" : [
            {
              "array_field" : 600
            },
            {
              "array_field" : 700
            },
            {
              "array_field" : 800
            }
          ]
        }
      },
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "GcGrsX8B2mat8b4U-60C",
        "_score" : 1.0,
        "_source" : {
          "id" : 8,
          "nested_field" : [
            {
              "array_field" : 500
            },
            {
              "array_field" : 500
            },
            {
              "array_field" : 600
            }
          ]
        }
      }
    ]
  }
}

```


</details>

### 配列内の要素がN個以上であるドキュメントを検索

この検索はstringやobjectの配列であっても同じことができそう
ECにおいて各ユーザが一度に購入した商品のIDを配列に持っていた場合に「N点以上購入したユーザ（購買行動）」を抽出するような場合に使えそう（Elasticsearchでこのような検索をするかはわからないが）


integerの場合

```json
GET /integer-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "filter": {
              "script": {
                "script": "doc['array_field'].length > 3"
              }
            }
          }
        }
      ]
    }
  }
}
```

<details>
    <summary>検索結果</summary>

```json
{
  "took" : 29,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "DcGrsX8B2mat8b4UZq3t",
        "_score" : 0.0,
        "_source" : {
          "id" : 9,
          "array_field" : [
            200,
            300,
            400,
            500
          ]
        }
      },
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "DsGrsX8B2mat8b4UZq3-",
        "_score" : 0.0,
        "_source" : {
          "id" : 10,
          "array_field" : [
            300,
            300,
            400,
            500
          ]
        }
      }
    ]
  }
}
```

nestedの場合→うまい方法が見つからない




### 配列が空orNULLであるドキュメントの検索


Elasticsearchにおいてnullと空の配列は同じ扱いになっている（[参考](https://www.elastic.co/guide/en/elasticsearch/reference/master/null-value.html)）
配列内の要素がゼロの場合とNULLのケース両方で検索する


integerの場合①（配列内の要素が空の場合）

```json
GET /integer-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "filter": {
              "script": {
                "script": "doc['array_field'].length < 1"
              }
            }
          }
        },
        {
          "bool"
        }
      ]
    }
  }
}
```

integerの場合①（フィールドがNULLの場合）

```json
GET /integer-index/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "bool": {
            "filter": {
              "exists": {
                "field": "array_field"
              }
            }
          }
        }
      ]
    }
  }
}
```

</details>

<details>
  <summary>検索結果</summary>

```json
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "D8GrsX8B2mat8b4UZ60O",
        "_score" : 1.0,
        "_source" : {
          "id" : 11,
          "array_field" : [ ]
        }
      },
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "EMGrsX8B2mat8b4UZ60f",
        "_score" : 1.0,
        "_source" : {
          "id" : 12,
          "array_field" : null
        }
      },
      {
        "_index" : "integer-index",
        "_type" : "contents",
        "_id" : "EcGrsX8B2mat8b4UZ60v",
        "_score" : 1.0,
        "_source" : {
          "id" : 13
        }
      }
    ]
  }
}
```

</details>


nestedの場合

lengthを使った検索は先程の項目の通り見つかっていない
nullに対する検索は以下の通り（[こちらの回答を用いた](https://stackoverflow.com/questions/40747360/elasticsearch-check-if-nested-object-array-is-empty)）


```json
GET /integer-index-nested/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "nested": {
            "path": "nested_field",
            "query": {
              "bool": {
                "filter": {
                  "exists": {
                    "field": "nested_field"
                  }
                }
              }
            }
          }
        }
      ]
    }
  }
}
```


<details>
  <summary></summary>

```json
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "KcGvsX8B2mat8b4Ugq26",
        "_score" : 1.0,
        "_source" : {
          "id" : 11,
          "nested_field" : [ ]
        }
      },
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "KsGvsX8B2mat8b4Ugq3K",
        "_score" : 1.0,
        "_source" : {
          "id" : 12,
          "nested_field" : [
            {
              "array_field" : null
            }
          ]
        }
      },
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "K8GvsX8B2mat8b4Ugq3a",
        "_score" : 1.0,
        "_source" : {
          "id" : 13
        }
      }
    ]
  }
}

```

</details>

先程のクエリは`nested`や`must_not`の順番をいれかえると思わぬ結果になる
id=13はnested_field.array_fieldどころかnested_field自体がないので引っかからなそうではあるが（それでも引っかかりそうではあるが）、id=11は引っかかってもおかしくない気がする


```json
GET /integer-index-nested/_search
{
  "query": {
    "nested": {
      "path": "nested_field",
      "query": {
        "bool": {
          "must_not": [
            {
              "exists": {
                "field": "nested_field.array_field"
              }
            }
          ]
        }
      }
    }
  }
}
```


<details>
  <summary>検索結果</summary>

```json
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "integer-index-nested",
        "_type" : "contents",
        "_id" : "KsGvsX8B2mat8b4Ugq3K",
        "_score" : 1.0,
        "_source" : {
          "id" : 12,
          "nested_field" : [
            {
              "array_field" : null
            }
          ]
        }
      }
    ]
  }
}

```

</details>

## 文字列

integerの場合と同様の手順で2通りの場合の検証をする
手間と目的の都合上今回はkeywordのみの検証でnormalize等は特に行っていない

ここで確認したいことは以下の通り
- 配列にある値の要素を含むドキュメントの検索
- 配列内の要素が[A,B,C]であるドキュメントの検索（完全一致の検索）


以下のような二通りのインデックスを作成して調査をする

```json
# 下準備
PUT /keyword-index
{
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 1,
    "index.write.wait_for_active_shards": 1
  },
  "mappings": {
    "contents": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "array_field": {
          "type": "keyword"
        }
      }
    }
  }
}


PUT /keyword-index-nested
{
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 1,
    "index.write.wait_for_active_shards": 1
  },
  "mappings": {
    "contents": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "nested_field": {
          "type": "nested",
          "properties": {
            "array_field": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}
```

投入するデータは以下の通り

<details>
  <summary>keywordの分</summary>

```json
POST /keyword-index/_doc
{"id": 1, "array_field": ["w6o","qbj","Aof"]}
POST /keyword-index/_doc
{"id": 2, "array_field": ["qbj","Aof","SYH"]}
POST /keyword-index/_doc
{"id": 3, "array_field": ["Aof","SYH","srN"]}
POST /keyword-index/_doc
{"id": 4, "array_field": ["SYH","srN","ebA"]}
POST /keyword-index/_doc
{"id": 5, "array_field": ["srN","ebA","hrp"]}
POST /keyword-index/_doc
{"id": 6, "array_field": ["ebA","hrp","PKD"]}
POST /keyword-index/_doc
{"id": 7, "array_field": ["qbj","qbj","SYH"]}
POST /keyword-index/_doc
{"id": 8, "array_field": ["srN","srN","ebA"]}
POST /keyword-index/_doc
{"id": 9, "array_field": ["qbj","Aof","SYH","srN"]}
POST /keyword-index/_doc
{"id": 10, "array_field": ["Aof","Aof","SYH","srN"]}
POST /keyword-index/_doc
{"id": 11, "array_field": []}
POST /keyword-index/_doc
{"id": 12, "array_field": null}
POST /keyword-index/_doc
{"id": 13}
```

</details>

<details>
  <summary>nestedの分</summary>

```json
POST /keyword-index-nested/_doc
{"id": 1, "nested_field": [{"array_field": "w6o"},{"array_field": "qbj"},{"array_field": "Aof"}]}
POST /keyword-index-nested/_doc
{"id": 2, "nested_field": [{"array_field": "qbj"},{"array_field": "Aof"},{"array_field": "SYH"}]}
POST /keyword-index-nested/_doc
{"id": 3, "nested_field": [{"array_field": "Aof"},{"array_field": "SYH"},{"array_field": "srN"}]}
POST /keyword-index-nested/_doc
{"id": 4, "nested_field": [{"array_field": "SYH"},{"array_field": "srN"},{"array_field": "ebA"}]}
POST /keyword-index-nested/_doc
{"id": 5, "nested_field": [{"array_field": "srN"},{"array_field": "ebA"},{"array_field": "hrp"}]}
POST /keyword-index-nested/_doc
{"id": 6, "nested_field": [{"array_field": "ebA"},{"array_field": "hrp"},{"array_field": "PKD"}]}
POST /keyword-index-nested/_doc
{"id": 7, "nested_field": [{"array_field": "qbj"},{"array_field": "qbj"},{"array_field": "SYH"}]}
POST /keyword-index-nested/_doc
{"id": 8, "nested_field": [{"array_field": "srN"},{"array_field": "srN"},{"array_field": "ebA"}]}
POST /keyword-index-nested/_doc
{"id": 9, "nested_field": [{"array_field": "qbj"},{"array_field": "Aof"},{"array_field": "SYH"},{"array_field": "srN"}]}
POST /keyword-index-nested/_doc
{"id": 10, "nested_field": [{"array_field": "Aof"},{"array_field": "Aof"},{"array_field": "SYH"},{"array_field": "srN"}]}
POST /keyword-index-nested/_doc
{"id": 11, "nested_field": []}
POST /keyword-index-nested/_doc
{"id": 12, "nested_field": [{"array_field": null}]}
POST /keyword-index-nested/_doc
{"id": 13}
```

</details>

### 配列（nested内の配列／以下同じ）にある値の要素を含むドキュメントの検索

keywordの場合
文章検索だからあたりまえの結果になる

```json
GET /keyword-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "array_field": {
              "value": "Aof"
            }
          }
        }
      ]
    }
  }
}
```

<details>
  <summary>検索結果</summary>

```json
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 5,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "LMHVsX8B2mat8b4UIK3n",
        "_score" : 0.6931472,
        "_source" : {
          "id" : 1,
          "array_field" : [
            "w6o",
            "qbj",
            "Aof"
          ]
        }
      },
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "LcHVsX8B2mat8b4UIK37",
        "_score" : 0.6931472,
        "_source" : {
          "id" : 2,
          "array_field" : [
            "qbj",
            "Aof",
            "SYH"
          ]
        }
      },
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "LsHVsX8B2mat8b4UIa0M",
        "_score" : 0.6931472,
        "_source" : {
          "id" : 3,
          "array_field" : [
            "Aof",
            "SYH",
            "srN"
          ]
        }
      },
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "NMHVsX8B2mat8b4UIa2M",
        "_score" : 0.6931472,
        "_source" : {
          "id" : 9,
          "array_field" : [
            "qbj",
            "Aof",
            "SYH",
            "srN"
          ]
        }
      },
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "NcHVsX8B2mat8b4UIa2c",
        "_score" : 0.6931472,
        "_source" : {
          "id" : 10,
          "array_field" : [
            "Aof",
            "Aof",
            "SYH",
            "srN"
          ]
        }
      }
    ]
  }
}

```

</details>


nestedの場合

```json
GET /keyword-index-nested/_search
{
  "query": {
    "nested": {
      "path": "nested_field",
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "nested_field.array_field": {
                  "value": "Aof"
                }
              }
            }
          ]
        }
      }
    }
  }
}
```

### 配列内の要素が[A,B,C]であるドキュメントの検索（完全一致の検索）

先程は`Aof`という単語が含まれるドキュメントの検索をしたが、今回は`Aof`,`SYH`,`srN`という3つの単語がその要素となっているドキュメントを検索する[^2]

keywordの場合
もっといいやり方ある気がする（がこれ以上時間がとれないので必要になったらまた調べる）
またこのやり方だとnestedには使えないし、完全一致とは言いながらも重複した要素がある場合は期待通りにいっていない（今回はid=3のみを抽出したかった）

```json
GET /keyword-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "array_field": {
              "value": "Aof"
            }
          }
        },
        {
          "term": {
            "array_field": {
              "value": "SYH"
            }
          }
        },
        {
          "term": {
            "array_field": {
              "value": "srN"
            }
          }
        },
        {
          "script": {
            "script": "doc['array_field'].length == 3"
          }
        }
      ]
    }
  }
}
```


<details>
  <summary>検索結果</summary>

```json
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 2.7453334,
    "hits" : [
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "Y8H2sX8B2mat8b4U0a1g",
        "_score" : 2.7453334,
        "_source" : {
          "id" : 3,
          "array_field" : [
            "Aof",
            "SYH",
            "srN"
          ]
        }
      },
      {
        "_index" : "keyword-index",
        "_type" : "contents",
        "_id" : "asH2sX8B2mat8b4U0a3h",
        "_score" : 2.7453334,
        "_source" : {
          "id" : 10,
          "array_field" : [
            "Aof",
            "Aof",
            "SYH",
            "srN"
          ]
        }
      }
    ]
  }
}

```

</details>

## 時間があったらやりたいこと

- 文字列型の検索関係もう少し調べたい
- オブジェクト型の場合の検証をしたい（特にオブジェクト内の要素にアクセスする場合）

[^1]: 2022/3/17現在この説明はバージョン7.13以前にしか存在していない
[^2]: [A,B,C]がすべて含まれるドキュメント、ならユースケースありそうだが[A,B,C]で（順不同にて）完全一致を検索したいケースがあるかは知らない