

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Amazon OpenSearch Service 자습서
<a name="tutorials"></a>

이 장에는 서비스로 마이그레이션하고 간단한 검색 애플리케이션을 구축하고 OpenSearch Dashboards에서 시각화를 만드는 방법을 비롯하여 Amazon OpenSearch Service 작업을 위한 몇 가지 시작 후 완료 자습서가 포함되어 있습니다.

**Topics**
+ [자습서: Amazon OpenSearch Service에서 문서 생성 및 검색](quick-start.md)
+ [튜토리얼: Amazon OpenSearch Service로 마이그레이션](migration.md)
+ [자습서: Amazon OpenSearch Service를 사용하여 검색 애플리케이션 생성](search-example.md)
+ [자습서: OpenSearch Service 및 OpenSearch Dashboards를 사용하여 고객 지원 통화 시각화](walkthrough.md)

# 자습서: Amazon OpenSearch Service에서 문서 생성 및 검색
<a name="quick-start"></a>

이 자습서에서는 Amazon OpenSearch Service에서 문서를 생성하고 검색하는 방법을 알아봅니다. JSON 문서 형식으로 인덱스에 데이터를 추가합니다. OpenSearch Service는 사용자가 추가하는 첫 번째 문서 주위에 인덱스를 생성합니다.

이 자습서에서는 문서 생성을 위한 HTTP 요청, 문서 ID 자동 생성, 문서에 대한 기본 및 고급 검색 수행 방법을 설명합니다.

**참고**  
이 자습서에서는 개방 액세스가 가능한 도메인을 사용합니다. 최고 수준의 보안을 위해 도메인을 Virtual Private Cloud(VPC) 내부에 두는 것이 좋습니다.

## 사전 조건
<a name="quick-start-prereqs"></a>

이 자습서의 사전 요구 사항은 다음과 같습니다.
+ 가 있어야 합니다 AWS 계정.
+ 활성 OpenSearch Service 도메인이 있어야 합니다.

## 인덱스에 문서 추가
<a name="quick-start-create"></a>

인덱스에 문서를 추가하려면 [Postman](https://www.getpostman.com/), cURL 또는 OpenSearch Dashboards 콘솔과 같은 모든 HTTP 도구를 사용할 수 있습니다. 이 예제에서는 OpenSearch Dashboards에서 개발자 콘솔을 사용하고 있다고 가정합니다. 다른 도구를 사용하는 경우 필요에 따라 전체 URL과 자격 증명을 제공하여 적절히 조정합니다.

**인덱스에 문서 추가**

1. 도메인에 대한 OpenSearch Dashboards URL으로 이동합니다. OpenSearch Service 콘솔의 도메인 대시보드에서 URL을 찾을 수 있습니다. URL은 다음 형식을 따릅니다.

   ```
   domain-endpoint/_dashboards/
   ```

1. 기본 사용자 이름과 암호를 사용하여 로그인합니다.

1. 왼쪽 탐색 패널을 열고 **Dev Tools**(개발 도구)를 선택합니다.

1. 새 리소스를 생성하기 위한 HTTP 동사는 새 문서와 인덱스를 생성하는 데 사용하는 PUT입니다. 콘솔에서 다음 명령을 입력합니다.

   ```
   PUT fruit/_doc/1
   {
     "name":"strawberry",
     "color":"red"
   }
   ```

   `PUT` 요청은 이름이 *fruit*인 인덱스를 생성하고 ID가 1인 단일 문서를 인덱스에 추가합니다. 다음과 같은 응답이 생성됩니다.

   ```
   {
     "_index" : "fruit",
     "_type" : "_doc",
     "_id" : "1",
     "_version" : 1,
     "result" : "created",
     "_shards" : {
       "total" : 2,
       "successful" : 2,
       "failed" : 0
     },
     "_seq_no" : 0,
     "_primary_term" : 1
   }
   ```

## 자동으로 생성되는 ID 만들기
<a name="quick-start-id"></a>

OpenSearch Service는 문서에 대한 ID를 자동으로 생성할 수 있습니다. ID를 생성하는 명령은 PUT 요청 대신 POST 요청을 사용하며 문서 ID가 필요하지 않습니다(이전 요청과 비교).

개발자 콘솔에서 다음 요청을 입력합니다.

```
POST veggies/_doc
{
  "name":"beet",
  "color":"red",
  "classification":"root"
}
```

이 요청은 *veggies*라는 인덱스를 생성하고 인덱스에 문서를 추가합니다. 다음과 같은 응답이 생성됩니다.

```
{
  "_index" : "veggies",
  "_type" : "_doc",
  "_id" : "3WgyS4IB5DLqbRIvLxtF",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}
```

응답에서 ID가 자동으로 생성되었음을 나타내는 추가 `_id` 필드에 유의합니다.

**참고**  
URL에서 `_doc` 다음에 아무 것도 제공하지 않습니다. 대개 이 자리에 ID가 들어갑니다. 생성된 ID로 문서를 만들고 있기 때문에 아직 ID를 제공하지 않습니다. 업데이트용으로 예약되어 있습니다.

## POST 명령으로 문서 업데이트
<a name="quick-start-update"></a>

문서를 업데이트하려면 ID 번호와 함께 HTTP `POST` 명령을 사용합니다.

먼저 ID가 `42`인 문서를 생성합니다.

```
POST fruits/_doc/42
{
  "name":"banana",
  "color":"yellow"
}
```

그런 다음 해당 ID를 사용하여 문서를 업데이트합니다.

```
POST fruits/_doc/42
{
  "name":"banana",
  "color":"yellow",
  "classification":"berries"
}
```

이 명령은 새 필드 `classification`으로 문서를 업데이트합니다. 다음과 같은 응답이 생성됩니다.

```
{
  "_index" : "fruits",
  "_type" : "_doc",
  "_id" : "42",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}
```

**참고**  
존재하지 않는 문서를 업데이트하려고 하면 OpenSearch Service에서 문서를 생성합니다.

## 대량 작업 수행
<a name="quick-start-bulk"></a>

`POST _bulk` API 작업을 사용하여 하나의 요청에서 하나 이상의 인덱스에 대해 여러 작업을 수행할 수 있습니다. 대량 작업 명령의 형식은 다음과 같습니다.

```
POST /_bulk
<action_meta>\n
<action_data>\n
<action_meta>\n
<action_data>\n
```

각 작업에는 두 줄의 JSON이 필요합니다. 먼저 작업 설명 또는 메타데이터를 제공합니다. 다음 줄에서 데이터를 제공합니다. 각 부분은 줄 바꿈(\$1n)으로 구분됩니다. 삽입에 대한 작업 설명은 다음과 같습니다.

```
{ "create" : { "_index" : "veggies", "_type" : "_doc", "_id" : "7" } }
```

데이터가 포함된 다음 줄은 다음과 같습니다.

```
{ "name":"kale", "color":"green", "classification":"leafy-green" }
```

종합하면 메타데이터와 데이터는 대량 작업의 단일 작업을 나타냅니다. 다음과 같이 하나의 요청으로 많은 작업을 수행할 수 있습니다.

```
POST /_bulk
{ "create" : { "_index" : "veggies", "_id" : "35" } }
{ "name":"kale", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "36" } }
{ "name":"spinach", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "37" } }
{ "name":"arugula", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "38" } }
{ "name":"endive", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "39" } }
{ "name":"lettuce", "color":"green", "classification":"leafy-green" }
{ "delete" : { "_index" : "vegetables", "_id" : "1" } }
```

마지막 작업은 `delete`입니다. `delete` 작업 이후의 데이터가 없습니다.

## 문서 검색
<a name="quick-start-search"></a>

이제 데이터가 클러스터에 있으므로 데이터를 검색할 수 있습니다. 예를 들어, 모든 뿌리 채소를 검색하거나, 잎이 많은 채소 수를 모두 구하거나, 시간당 기록된 오류 수를 찾을 수 있습니다.

**기본 검색**

기본 검색은 다음과 같습니다.

```
GET veggies/_search?q=name:l*
```

요청은 lettuce 문서를 포함하는 JSON 응답을 생성합니다.

**고급 검색**

요청 본문에 쿼리 옵션을 JSON으로 제공하여 고급 검색을 수행할 수 있습니다.

```
GET veggies/_search
{
  "query": {
    "term": {
      "name": "lettuce"
    }
  }
}
```

이 예제에서는 lettuce 문서가 포함된 JSON 응답도 생성합니다.

**정렬**

정렬을 사용하여 이러한 유형의 쿼리를 더 많이 수행할 수 있습니다. 먼저 자동 필드 매핑에서 기본적으로 정렬할 수 없는 유형을 선택했기 때문에인덱스를 다시 생성해야 합니다. 다음 요청을 전송하여 인덱스를 삭제했다가 다시 생성합니다.

```
DELETE /veggies

PUT /veggies
{
   "mappings":{
      "properties":{
         "name":{
            "type":"keyword"
         },
         "color":{
            "type":"keyword"
         },
         "classification":{
            "type":"keyword"
         }
      }
   }
}
```

그런 다음 인덱스를 데이터로 다시 채웁니다.

```
POST /_bulk
{ "create" : { "_index" : "veggies", "_id" : "7"  } }
{ "name":"kale", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "8" } }
{ "name":"spinach", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "9" } }
{ "name":"arugula", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "10" } }
{ "name":"endive", "color":"green", "classification":"leafy-green" }
{ "create" : { "_index" : "veggies", "_id" : "11" } }
{ "name":"lettuce", "color":"green", "classification":"leafy-green" }
```

이제 정렬과 함께 검색할 수 있습니다. 다음 요청은 분류별 오름차순 정렬을 추가합니다.

```
GET veggies/_search
{
  "query" : {
    "term": { "color": "green" }
  },
  "sort" : [
      "classification"
  ]
}
```

## 관련 리소스
<a name="quick-start-resources"></a>

자세한 정보는 다음 자료를 참조하세요.
+ [Amazon OpenSearch Service 시작하기](gsg.md)
+ [Amazon OpenSearch Service의 데이터 인덱싱](indexing.md)
+ [Amazon OpenSearch Service의 데이터 검색](searching.md)

# 튜토리얼: Amazon OpenSearch Service로 마이그레이션
<a name="migration"></a>

인덱스 스냅샷은 자체 관리형 OpenSearch 또는 레거시 Elasticsearch 클러스터에서 Amazon OpenSearch Service로 마이그레이션하는 데 널리 사용되는 방법입니다. 대체로 프로세스는 다음 단계로 구성됩니다.

1. 기존 클러스터의 스냅샷을 만들고 스냅샷을 Amazon S3 버킷에 업로드합니다.

1. OpenSearch Service 도메인 생성

1. 버킷에 액세스할 수 있는 권한을 OpenSearch Service에 부여하고 자신에게 스냅샷으로 작업할 수 있는 권한이 있는지 확인합니다.

1. OpenSearch Service 도메인에서 스냅샷을 복원합니다.

이 연습에서는 자세한 단계와 대체 옵션(해당되는 경우)을 다룹니다.

## 스냅샷 생성 및 업로드
<a name="migration-take-snapshot"></a>

[리포지토리-s3](https://docs.opensearch.org/latest/opensearch/snapshot-restore/#amazon-s3) 플러그인을 사용하여 S3에 직접 스냅샷을 생성할 수 있지만 모든 노드에 플러그인을 설치하고, 조정하고`opensearch.yml`(또는 Elasticsearch 클러스터를 사용하는 `elasticsearch.yml` 경우), 각 노드를 다시 시작하고, AWS 자격 증명을 추가하고, 마지막으로 스냅샷을 생성해야 합니다. 플러그인은 지속해서 사용하거나 더 큰 클러스터를 마이그레이션하기 위한 좋은 옵션입니다.

작은 클러스터의 경우 일회성 접근 방식은 [공유 파일 시스템 스냅샷](https://docs.opensearch.org/latest/opensearch/snapshot-restore/#shared-file-system)을 생성한 다음를 사용하여 S3 AWS CLI 에 업로드하는 것입니다. 이미 스냅샷이 있는 경우 4단계로 건너뜁니다.

****스냅샷을 생성하여 Amazon S3에 업로드****

1. 모든 노드에서 `opensearch.yml`(또는 `Elasticsearch.yml`)에 `path.repo` 설정을 추가한 다음 각 노드를 다시 시작합니다.

   ```
   path.repo: ["/my/shared/directory/snapshots"]
   ```

1. 스냅샷을 찍기 전에 필요한 [스냅샷 리포지토리](https://opensearch.org/docs/latest/opensearch/snapshot-restore/#register-repository)를 등록합니다. 리포지토리는 공유 파일 시스템, Amazon S3, Hadoop 분산 파일 시스템(HDFS) 등, 단순한 스토리지 위치입니다. 이 경우 공유 파일 시스템(“fs”)을 사용합니다.

   ```
   PUT _snapshot/my-snapshot-repo-name
   {
     "type": "fs",
     "settings": {
       "location": "/my/shared/directory/snapshots"
     }
   }
   ```

1. 스냅샷 생성:

   ```
   PUT _snapshot/my-snapshot-repo-name/my-snapshot-name
   {
     "indices": "migration-index1,migration-index2,other-indices-*",
     "include_global_state": false
   }
   ```

1. [AWS CLI](https://aws.amazon.com/cli/)를 설치하고 `aws configure`을 실행하여 자격 증명을 추가합니다.

1. 스냅샷 디렉터리로 이동합니다. 다음 명령을 실행하여 새 S3 버킷을 생성하고 스냅샷 디렉터리의 콘텐츠를 해당 버킷에 업로드합니다.

   ```
   aws s3 mb s3://amzn-s3-demo-bucket --region us-west-2
   aws s3 sync . s3://amzn-s3-demo-bucket --sse AES256
   ```

   스냅샷의 크기와 인터넷 연결 속도에 따라 이 작업을 실행할 때 시간이 걸릴 수 있습니다.

## 도메인 생성
<a name="migration-create-domain"></a>

콘솔이 도메인을 생성하는 가장 쉬운 방법이지만이 경우 이미 터미널이 열려 있고가 AWS CLI 설치되어 있습니다. 다음 명령을 수정하여 필요에 맞게 도메인을 만듭니다.

```
aws opensearch create-domain \
  --domain-name migration-domain \
  --engine-version OpenSearch_1.0 \
  --cluster-config InstanceType=c5.large.search,InstanceCount=2 \
  --ebs-options EBSEnabled=true,VolumeType=gp2,VolumeSize=100 \
  --node-to-node-encryption-options Enabled=true \
  --encryption-at-rest-options Enabled=true \
  --domain-endpoint-options EnforceHTTPS=true,TLSSecurityPolicy=Policy-Min-TLS-1-2-2019-07 \
  --advanced-security-options Enabled=true,InternalUserDatabaseEnabled=true,MasterUserOptions='{MasterUserName=master-user,MasterUserPassword=master-user-password}' \
  --access-policies '{"Version": "2012-10-17",		 	 	 "Statement":[{"Effect":"Allow","Principal": {"AWS": "arn:aws:iam::aws-region:user/UserName"},"Action":["es:ESHttp*"],"Resource":"arn:aws:es:aws-region:111122223333:domain/migration-domain/*"}]}' \
  --region aws-region
```

마찬가지로 이 명령은 각각 100GiB의 스토리지가 있는 두 개의 데이터 노드를 갖춘 인터넷 액세스 가능 도메인을 만듭니다. 또한 HTTP 기본 인증 및 모든 암호화 설정으로 [세분화된 액세스 제어](fgac.md)가 가능합니다. VPC와 같은 고급 보안 구성이 필요한 경우, OpenSearch Service 콘솔을 사용합니다.

명령을 실행하기 전에 도메인 이름, 마스터 사용자 자격 증명 및 계정 번호를 변경합니다. 스냅샷과 호환되는 S3 버킷 및 OpenSearch/Elasticsearch 버전에 사용한 AWS 리전 것과 동일하게 지정합니다.

**중요**  
스냅샷은 하나의 주 버전에서만 호환됩니다. 예를 들어, Elasticsearch 7.*x* 클러스터에서는 OpenSearch 1.*x* 클러스터의 스냅샷을 복원할 수 없습니다. OpenSearch 1.*x* 또는 2.*x* 클러스터만 가능합니다. 마이너 버전도 중요합니다. 5.3.2 OpenSearch Service 도메인의 자체 관리형 5.3.3 클러스터에서는 스냅샷을 복원할 수 없습니다. 스냅샷에서 지원하는 OpenSearch 또는 Elasticsearch의 최신 버전을 선택하는 것이 좋습니다. 호환 가능한 버전 테이블은 [스냅샷을 사용하여 데이터 마이그레이션](snapshot-based-migration.md) 섹션을 참조하세요.

## S3 버킷에 권한 부여
<a name="migration-permissions"></a>

 AWS Identity and Access Management (IAM) 콘솔에서 다음과 같은 권한과 [신뢰 관계를](https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-managingrole_edit-trust-policy) 가진 [역할을 생성합니다](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html). 역할을 생성할 때 **AWS 서비스**로 **S3**를 선택합니다. 쉽게 찾을 수 있도록 `OpenSearchSnapshotRole` 역할 이름을 지정합니다.

**권한**

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [{
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::amzn-s3-demo-bucket"
      ]
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::amzn-s3-demo-bucket/*"
      ]
    }
  ]
}
```

------

**신뢰 관계**

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [{
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

------

그런 다음 개인 IAM 역할에 `OpenSearchSnapshotRole`을 수임할 수 있는 권한을 부여합니다. 다음 정책을 만들어 자격 증명에 [연결합니다](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html).

**권한**

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [{
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
    }
  ]
}
```

------

### 세분화된 액세스 제어를 사용하는 경우 OpenSearch Dashboards에서 스냅샷 역할을 매핑할 수 있습니다.
<a name="migration-snapshot-role"></a>

[세분화된 액세스 제어](fgac.md#fgac-mapping)를 활성화한 경우 다른 모든 용도로 HTTP 기본 인증을 사용하더라도 `manage_snapshots` 역할을 IAM 역할에 할당하여 스냅샷으로 작업할 수 있도록 해야 합니다.

**스냅샷으로 작업할 수 있는 자격 증명 권한을 부여하려면**

1. OpenSearch Service 도메인을 생성할 때 지정한 마스터 사용자 자격 증명을 사용하여 Dashboards에 로그인합니다. Dashboards URL은 OpenSearch Service 콘솔에서 찾을 수 있습니다. `https://domain-endpoint/_dashboards/` 형식을 사용합니다.

1. 주 메뉴에서 **보안(Security)**, **역할(Roles)**을 선택하고 **manage\$1snapshots** 역할을 선택합니다.

1. **매핑된 사용자(Mapped users)**, **매핑 관리(Manage mapping)**를 차례로 선택합니다.

1. 그런 다음 해당 필드에 개인 IAM 역할의 도메인 ARN을 추가합니다. ARN은 다음 형식 중 하나여야 합니다.

   ```
   arn:aws:iam::123456789123:user/user-name
   ```

   ```
   arn:aws:iam::123456789123:role/role-name
   ```

1. **Map**(맵)을 선택하고 **Mapped users**(매핑된 사용자)에 역할이 나타나는지 확인합니다.

## 스냅샷을 복원합니다.
<a name="migration-restore"></a>

이 시점에서 OpenSearch Service 도메인에 액세스하는 두 가지 방법, 즉 마스터 사용자 자격 증명을 사용한 HTTP 기본 인증 또는 IAM 자격 증명을 사용한 AWS 인증이 있습니다. 스냅샷에서는 마스터 사용자에 대한 개념이 없는 Amazon S3를 사용하므로, IAM 자격 증명을 사용하여 OpenSearch Service 도메인에 스냅샷 리포지토리를 등록해야 합니다.

대부분의 프로그래밍 언어에는 서명 요청에 도움이 되는 라이브러리가 있지만, 더 간단한 방법은 [Postman](https://www.postman.com/downloads/)과 같은 도구를 사용하여 IAM 보안 인증 정보를 **권한 부여** 섹션에 넣는 것입니다.

![\[Postman interface showing Authorization settings for AWS API request with Signature type.\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/migration2.png)


**스냅샷을 복원하려면**

1. 요청에 서명하는 방법과 관계없이 첫 번째 단계는 리포지토리를 등록하는 것입니다.

   ```
   PUT _snapshot/my-snapshot-repo-name
   {
     "type": "s3",
     "settings": {
       "bucket": "amzn-s3-demo-bucket",
       "region": "us-west-2",
       "role_arn": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
     }
   }
   ```

1. 그런 다음 리포지토리에 있는 스냅샷을 나열하고 복원할 스냅샷을 찾습니다. 이 시점에서 Postman을 계속 사용하거나 [curl](https://curl.haxx.se/)과 같은 도구로 전환할 수 있습니다.

   **간편**

   ```
   GET _snapshot/my-snapshot-repo-name/_all
   ```

   **curl**

   ```
   curl -XGET -u 'master-user:master-user-password' https://domain-endpoint/_snapshot/my-snapshot-repo-name/_all
   ```

1. 스냅샷을 복원합니다.

   **간편**

   ```
   POST _snapshot/my-snapshot-repo-name/my-snapshot-name/_restore
   {
     "indices": "migration-index1,migration-index2,other-indices-*",
     "include_global_state": false
   }
   ```

   **curl**

   ```
   curl -XPOST -u 'master-user:master-user-password' https://domain-endpoint/_snapshot/my-snapshot-repo-name/my-snapshot-name/_restore \
     -H 'Content-Type: application/json' \
     -d '{"indices":"migration-index1,migration-index2,other-indices-*","include_global_state":false}'
   ```

1. 마지막으로 인덱스가 예상대로 복원되었는지 확인합니다.

   **간편**

   ```
   GET _cat/indices?v
   ```

   **curl**

   ```
   curl -XGET -u 'master-user:master-user-password' https://domain-endpoint/_cat/indices?v
   ```

이 시점에서 마이그레이션이 완료됩니다. 새 OpenSearch 엔드포인트를 사용하도록 클라이언트를 구성하거나, 워크로드에 맞게 [도메인 크기를 조정하거나](sizing-domains.md), 인덱스의 샤드 수를 확인하거나, [IAM 마스터 사용자](fgac.md#fgac-concepts)로 전환하거나, OpenSearch Dashboards에서 시각화를 구축할 수 있습니다.

# 자습서: Amazon OpenSearch Service를 사용하여 검색 애플리케이션 생성
<a name="search-example"></a>

Amazon OpenSearch Service로 검색 애플리케이션을 생성하는 일반적인 방법은 웹 양식을 사용해 사용자 쿼리를 서버로 전송하는 것입니다. 그런 다음 서버가 OpenSearch API를 직접 호출하여 OpenSearch Service로 요청을 전송할 수 있도록 권한을 부여하면 됩니다. 하지만 서버에 의존하지 않는 클라이언트 측 코드를 작성하려면 보안 및 성능 위험을 상쇄해야 합니다. OpenSearch API에 대한 무서명 공개 액세스를 허용하는 것은 권장하지 않습니다. 사용자가 보호되지 않은 엔드포인트에 액세스하거나 너무 광범위한 쿼리(또는 너무 많은 쿼리)로 클러스터 성능에 악영향을 미칠 수 있습니다.

이 장에서는 Amazon API Gateway를 사용하여 사용자를 OpenSearch APIs의 하위 집합으로 제한하고 API Gateway에서 OpenSearch Service AWS Lambda 로의 요청에 서명하는 솔루션을 제공합니다.

![\[검색 애플리케이션 흐름도.\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/search-application-diagram.png)


**참고**  
표준 API Gateway 및 Lambda 요금 정책이 적용되지만, 이 자습서에서는 사용량이 제한적이므로 비용은 무시할만한 수준입니다.

## 사전 조건
<a name="search-example-prereq"></a>

이 자습서의 사전 조건은 OpenSearch Service 도메인입니다. 아직 도메인이 없는 경우 [OpenSearch Service 도메인 생성](gsgcreate-domain.md) 단계에 따라 도메인을 생성합니다.

## 1단계: 샘플 데이터 인덱싱
<a name="search-example-index"></a>

[sample-movies.zip](samples/sample-movies.zip)을 다운로드하여 압축을 해제한 다음 [\$1bulk](https://opensearch.org/docs/latest/api-reference/document-apis/bulk/) API 작업을 사용하여 5,000개 문서를 `movies` 인덱스에 추가합니다.

```
POST https://search-my-domain.us-west-1.es.amazonaws.com/_bulk
{ "index": { "_index": "movies", "_id": "tt1979320" } }
{"directors":["Ron Howard"],"release_date":"2013-09-02T00:00:00Z","rating":8.3,"genres":["Action","Biography","Drama","Sport"],"image_url":"http://ia.media-imdb.com/images/M/MV5BMTQyMDE0MTY0OV5BMl5BanBnXkFtZTcwMjI2OTI0OQ@@._V1_SX400_.jpg","plot":"A re-creation of the merciless 1970s rivalry between Formula One rivals James Hunt and Niki Lauda.","title":"Rush","rank":2,"running_time_secs":7380,"actors":["Daniel Brühl","Chris Hemsworth","Olivia Wilde"],"year":2013,"id":"tt1979320","type":"add"}
{ "index": { "_index": "movies", "_id": "tt1951264" } }
{"directors":["Francis Lawrence"],"release_date":"2013-11-11T00:00:00Z","genres":["Action","Adventure","Sci-Fi","Thriller"],"image_url":"http://ia.media-imdb.com/images/M/MV5BMTAyMjQ3OTAxMzNeQTJeQWpwZ15BbWU4MDU0NzA1MzAx._V1_SX400_.jpg","plot":"Katniss Everdeen and Peeta Mellark become targets of the Capitol after their victory in the 74th Hunger Games sparks a rebellion in the Districts of Panem.","title":"The Hunger Games: Catching Fire","rank":4,"running_time_secs":8760,"actors":["Jennifer Lawrence","Josh Hutcherson","Liam Hemsworth"],"year":2013,"id":"tt1951264","type":"add"}
...
```

위는 사용 가능한 데이터의 하위 세트를 포함하는 예제 명령입니다. `_bulk` 작업을 수행하려면 `sample-movies` 파일의 전체 내용을 복사하여 붙여 넣어야 합니다. 자세한 지침은 [옵션 2: 여러 문서 업로드](gsgupload-data.md#gsgmultiple-document)을(를) 참조하세요.

또한 다음 curl 명령을 사용하여 동일한 결과를 얻을 수도 있습니다.

```
curl -XPOST -u 'master-user:master-user-password' 'domain-endpoint/_bulk' --data-binary @bulk_movies.json -H 'Content-Type: application/json'
```

## 2단계: Lambda 함수 생성 및 배포
<a name="search-example-lambda"></a>

API Gateway에서 API를 생성하기 전에 요청을 전달하는 Lambda 함수를 만듭니다.

### Lambda 함수 생성
<a name="sample-lamdba-python"></a>

이 솔루션에서는 API Gateway가 요청을 다음 Lambda 함수로 전달합니다. 그러면 이 함수가 OpenSearch Service를 쿼리하고 결과를 반환합니다. 이 샘플 함수는 외부 라이브러리를 사용하므로 배포 패키지를 생성하고 Lambda에 업로드해야 합니다.

**배포 패키지를 만드는 방법**

1. 명령 프롬프트를 열고 `my-opensearch-function` 프로젝트 디렉터리를 만듭니다. 예를 들어, macOS에서는 다음을 수행합니다.

   ```
   mkdir my-opensearch-function
   ```

1. `my-sourcecode-function` 프로젝트 디렉터리로 이동합니다.

   ```
   cd my-opensearch-function
   ```

1. 다음과 같은 샘플 Python 코드의 콘텐츠를 복사하고 이름이 `opensearch-lambda.py`인 새 파일에 저장합니다. 리전 및 호스트 엔드포인트를 파일에 추가합니다.

   ```
   import boto3
   import json
   import requests
   from requests_aws4auth import AWS4Auth
   
   region = '' # For example, us-west-1
   service = 'es'
   credentials = boto3.Session().get_credentials()
   awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token)
   
   host = '' # The OpenSearch domain endpoint with https:// and without a trailing slash
   index = 'movies'
   url = host + '/' + index + '/_search'
   
   # Lambda execution starts here
   def lambda_handler(event, context):
   
       # Put the user query into the query DSL for more accurate search results.
       # Note that certain fields are boosted (^).
       query = {
           "size": 25,
           "query": {
               "multi_match": {
                   "query": event['queryStringParameters']['q'],
                   "fields": ["title^4", "plot^2", "actors", "directors"]
               }
           }
       }
   
       # Elasticsearch 6.x requires an explicit Content-Type header
       headers = { "Content-Type": "application/json" }
   
       # Make the signed HTTP request
       r = requests.get(url, auth=awsauth, headers=headers, data=json.dumps(query))
   
       # Create the response and add some extra content to support CORS
       response = {
           "statusCode": 200,
           "headers": {
               "Access-Control-Allow-Origin": '*'
           },
           "isBase64Encoded": False
       }
   
       # Add the search results to the response
       response['body'] = r.text
       return response
   ```

1. 외부 라이브러리를 새 `package` 디렉터리에 설치합니다.

   ```
   pip3 install --target ./package boto3
   pip3 install --target ./package requests
   pip3 install --target ./package requests_aws4auth
   ```

1. 루트에서 설치된 라이브러리를 포함하는 배포 패키지를 만듭니다. 다음 명령을 실행하면 프로젝트 디렉터리에 `my-deployment-package.zip` 파일이 생성됩니다.

   ```
   cd package
   zip -r ../my-deployment-package.zip .
   ```

1. zip 파일의 루트에 `opensearch-lambda.py` 파일을 추가합니다.

   ```
   cd ..
   zip my-deployment-package.zip opensearch-lambda.py
   ```

Lambda 함수 및 배포 패키지를 만드는 방법에 대한 자세한 내용은 *AWS Lambda 개발자 안내서*의 [zip 파일 아카이브를 사용하여 Python Lambda 함수 배포](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html) 및 본 가이드의 [Lambda 배포 패키지 생성](integrations-s3-lambda.md#integrations-s3-lambda-deployment-package)를 참조하세요.

Lambda 콘솔을 사용하여 함수를 만들려면

1. [https://console.aws.amazon.com/lambda/home](https://console.aws.amazon.com/lambda/home )에서 Lambda 콘솔로 이동합니다. 왼쪽 탐색 창에서 **함수**를 선택합니다.

1. **함수 생성**을 선택합니다.

1. 다음 필드를 구성합니다.
   + 함수 이름: opensearch-function
   + 런타임 – Python 3.9
   + 아키텍처: x86\$164

   다른 모든 기본 옵션은 그대로 두고 **함수 생성**을 선택합니다.

1. 함수 요약 페이지의 **코드 소스** 섹션에서 드롭다운에서 **업로드**를 선택하고 **.zip 파일**을 선택합니다. 생성한 `my-deployment-package.zip` 파일을 찾아 **저장**을 선택합니다.

1. *핸들러*는 이벤트를 처리하는 함수 코드의 메서드입니다. **런타임 설정**에서 **편집**을 선택하고 Lambda 함수가 있는 배포 패키지의 파일 이름에 따라 핸들러 이름을 변경합니다. 파일 이름이 `opensearch-lambda.py`이므로 핸들러 이름을 `opensearch-lambda.lambda_handler`로 변경합니다. 자세한 내용은 [Python의 Lambda 함수 핸들러](https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html)를 참조하세요.

## 3단계: API Gateway에서 API 생성
<a name="search-example-api"></a>

API Gateway를 사용하면 보다 제한된 API를 생성하고 OpenSearch `_search` API와의 상호 작용을 간소화할 수 있습니다. API Gateway를 사용하면 Amazon Cognito 인증 및 요청 조절 같은 보안 기능을 활성화할 수도 있습니다. API를 생성하고 배포하려면 다음 단계를 수행합니다.

### API 생성 및 구성
<a name="create-api"></a>

API Gateway 콘솔을 사용하여 API를 생성하려면

1. [https://console.aws.amazon.com/apigateway/home](https://console.aws.amazon.com/apigateway/home )에서 API Gateway 콘솔로 이동합니다. 왼쪽 탐색 창에서 **API**를 선택합니다.

1. **REST API**(비공개 아님)를 찾고 **빌드(Build)**를 선택합니다.

1. 다음 페이지에서 **새 API 생성** 섹션을 찾아 **새 API**가 선택되어 있는지 확인합니다.

1. 다음 필드를 구성합니다.
   + API 이름: **OpenSearch-api**
   + 설명: **Amazon OpenSearch Service 도메인을 검색하기 위한 퍼블릭 API**
   + 엔드포인트 유형: **리전별**

1. **API 생성**을 선택합니다.

1. **작업(Actions)** 및 **메서드 생성(Create Method)**을 선택합니다.

1. 드롭다운에서 **GET**을 선택하고 확인 표시를 클릭하여 확인합니다.

1. 다음 설정을 구성한 다음 **저장(Save)**을 선택합니다.


| 설정 | 값 | 
| --- | --- | 
| 통합 유형 | Lambda 함수 | 
| Lambda 프록시 통합 사용 | 예 | 
| Lambda 리전 | us-west-1 | 
| Lambda 함수 | opensearch-lambda | 
| 기본 제한 시간 사용 | 예 | 

### 메서드 요청 구성
<a name="method-request"></a>

**메서드 요청(Method Request)**을 선택하고 다음 설정을 구성합니다.


| 설정 | 값 | 
| --- | --- | 
| 권한 부여 | NONE | 
| 요청 검사기 |  쿼리 문자열 파라미터 및 헤더 검사   | 
| 필수 API 키 | false | 

**URL 쿼리 문자열 파라미터**에서 **쿼리 문자열 추가**를 선택하고 다음 파라미터를 구성합니다.


| 설정 | 값 | 
| --- | --- | 
| 이름 | q | 
| 필수 |  예  | 

### API 배포 및 단계 구성
<a name="deploy-api"></a>

 API Gateway 콘솔에서 배포를 생성하고 새 단계 또는 기존 단계에 연결하여 API를 배포할 수 있습니다.

1. **작업(Actions)** 및 **API 배포(Deploy API)**를 선택합니다.

1. **배포 단계(Deployment stage)**에서 **새 단계(New Stage)**를 클릭하고 단계 이름을 `opensearch-api-test`로 지정합니다.

1. **배포(Deploy)**를 선택합니다.

1. 단계 편집기에서 다음 설정을 구성한 다음 **변경 내용 저장(Save Changes)**을 선택합니다.


| 설정 | 값 | 
| --- | --- | 
| 조절 활성화 | 예 | 
| 속도 |  1000  | 
| 버스트 | 500 | 

이러한 설정은 엔드포인트 루트에 대한 `GET` 요청(`https://some-id.execute-api.us-west-1.amazonaws.com/search-es-api-test`) 메서드 하나뿐인 API를 구성합니다. 이 요청에는 파라미터 하나(`q`), 즉 검색할 쿼리 문자열이 필요합니다. 메서드를 호출하면 요청이 Lambda로 전송되어 `opensearch-lambda` 함수가 실행됩니다. 자세한 내용은 [Amazon API Gateway에서 API 생성](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-create-api.html) 및 [Amazon API Gateway에서 REST API 배포](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-deploy-api.html)를 참조하세요.

## 4단계: (선택 사항) 도메인 액세스 정책 수정
<a name="search-example-perms"></a>

OpenSearch Service 도메인에서 Lambda 함수가 `movies` 인덱스에 `GET` 요청을 수행할 수 있도록 허용해야 합니다. 도메인에 세분화된 액세스 제어가 활성화된 오픈 액세스 정책이 있는 경우 그대로 둘 수 있습니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:us-west-1:123456789012:domain/domain-name/*"
    }
  ]
}
```

------

또는 도메인 액세스 정책을 보다 세분화하도록 선택할 수 있습니다. 예를 들어 다음 최소 정책은 `opensearch-lambda-role`(Lambda를 통해 생성됨)에 `movies` 인덱스에 대한 읽기 액세스를 제공합니다. Lambda가 자동으로 생성하는 역할의 정확한 이름을 가져오려면 AWS Identity and Access Management (IAM) 콘솔로 이동하여 **역할을** 선택하고 "lambda"를 검색합니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/service-role/opensearch-lambda-role-1abcdefg"
      },
      "Action": "es:ESHttpGet",
      "Resource": "arn:aws:es:us-west-1:123456789012:domain/domain-name/movies/_search"
    }
  ]
}
```

------

**중요**  
도메인에 대해 세분화된 액세스 제어를 활성화한 경우 OpenSearch 대시보드에서 [역할을 사용자에게 매핑](fgac.md#fgac-mapping)해야 합니다. 그러지 않으면 권한 오류가 표시됩니다.

### Lambda 실행 역할 권한 구성
<a name="search-example-lambda-iam"></a>

도메인 액세스 정책을 구성하는 것 외에, OpenSearch Service 도메인에 액세스하는 데 필요한 IAM 권한이 Lambda 실행 역할에 있는지도 확인해야 합니다. Lambda 함수에는 관리형 도메인을 사용하는지 아니면 OpenSearch Service Serverless 컬렉션을 사용하는지에 따라 특정 권한이 필요합니다.

**관리형 OpenSearch Service 도메인의 경우:**

다음 IAM 정책을 Lambda 실행 역할에 연결하여 OpenSearch Service 도메인에 요청을 보낼 수 있게 합니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "es:ESHttpGet",
        "es:ESHttpPost"
      ],
      "Resource": "arn:aws:es:us-west-1:123456789012:domain/domain-name/*"
    }
  ]
}
```

------

**OpenSearch Service Serverless 컬렉션의 경우:**

OpenSearch Service Serverless를 사용하는 경우 Lambda 실행 역할에 다음 IAM 정책을 연결합니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "aoss:*",
      "Resource": "arn:aws:aoss:us-west-1:123456789012:collection/collection-id"
    }
  ]
}
```

------

Lambda 실행 역할에 이러한 정책을 연결하려면:

1. [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)에서 IAM 콘솔로 이동합니다.

1. **역할**을 선택하고 Lambda 실행 역할(일반적으로 이름이 `opensearch-lambda-role-xxxxxxxx`)을 검색합니다.

1. **권한 추가**를 선택한 후 **인라인 정책 생성**을 선택합니다.

1. **JSON** 탭을 선택하고 위에서 적절한 정책을 붙여 넣고 자리 표시자 값을 실제 리소스 ARN으로 바꿉니다.

1. **정책 검토**를 선택하고 `OpenSearchAccess`와 같은 이름을 입력한 다음 **정책 생성**을 선택합니다.

**참고**  
이러한 IAM 권한이 없으면 도메인 액세스 정책이 요청을 허용하더라도 OpenSearch Service 도메인 쿼리를 시도할 때 Lambda 함수에 '액세스 거부됨' 오류가 발생합니다.

액세스 정책에 대한 자세한 내용은 [액세스 정책 구성](createupdatedomains.md#createdomain-configure-access-policies) 섹션을 참조하세요.

## Lambda 역할 매핑(세분화된 액세스 제어를 사용하는 경우)
<a name="search-example-perms-fgac"></a>

세분화된 액세스 제어를 사용하면 애플리케이션을 테스트하기 전에 추가 단계가 안내됩니다. 다른 모든 목적으로 HTTP 기본 인증을 사용하더라도 Lambda 역할을 사용자에게 매핑해야 합니다. 그러지 않으면 권한 오류가 표시됩니다.

1. 도메인에 대한 OpenSearch 대시보드 URL로 이동합니다.

1. 기본 메뉴에서 **보안**, **역할**을 선택한 후 Lambda 역할을 매핑해야 할 역할인 `all_access`에 대한 링크를 선택합니다.

1. **매핑된 사용자(Mapped users)**, **매핑 관리(Manage mapping)**를 차례로 선택합니다.

1. **Backend roles**(백엔드 역할)에서 Lambda 역할의 Amazon 리소스 이름(ARN)을 추가합니다. ARN은 `arn:aws:iam::123456789123:role/service-role/opensearch-lambda-role-1abcdefg` 형식을 취해야 합니다.

1. **Map**(맵)을 선택하고 **Mapped users**(매핑된 사용자)에 사용자 또는 역할이 나타나는지 확인합니다.

## 5단계: 웹 애플리케이션 테스트
<a name="search-example-webpage"></a>

**웹 애플리케이션을 테스트하려면**

1. [sample-site.zip](samples/sample-site.zip)을 다운로드하고 압축을 해제하여 자주 사용하는 텍스트 편집기에서 `scripts/search.js`를 엽니다.

1. `apigatewayendpoint` 변수를 업데이트하여 API Gateway 엔드포인트를 가리키도록 하고 지정된 경로의 끝에 백슬래시를 추가합니다. **단계(Stages)**를 선택하고 API의 이름을 선택하여 API Gateway에서 엔드포인트를 빠르게 찾을 수 있습니다. `apigatewayendpoint` 변수는 `https://some-id.execute-api.us-west-1.amazonaws.com/opensearch-api-test`/의 형식을 취해야 합니다.

1. `index.html`을 열고 *thor*, *house* 등 몇 가지 단어를 검색해 봅니다.  
![\[thor에 대한 샘플 검색입니다.\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/search-ui.png)

### CORS 오류 문제 해결
<a name="search-example-cors"></a>

Lambda 함수가 CORS를 지원하기 위해 응답에 콘텐츠를 포함하더라도 다음과 같은 오류가 계속 표시될 수 있습니다.

```
Access to XMLHttpRequest at '<api-gateway-endpoint>' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present in the requested resource.
```

이러한 상황이 발생하면 다음 작업을 시도합니다.

1. GET 리소스에서 [CORS를 활성화](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html)합니다. **고급(Advanced)**에서 **Access-Control-Allow-Credentials**를 `'true'`로 설정합니다.

1. API Gateway에서 API를 재배포합니다(**작업(Actions)**, **API 배포(Deploy API)**).

1. Lambda 함수 트리거를 삭제하고 다시 추가합니다. 다시 추가하려면 **트리거 추가**를 선택하고 함수를 호출하는 HTTP 엔드포인트를 생성합니다. 트리거 구성은 다음과 같아야 합니다.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/search-example.html)

## 다음 단계
<a name="search-example-next"></a>

이 장은 개념을 설명하기 위한 출발점에 불과합니다. 다음과 같은 수정을 고려할 수 있습니다.
+ OpenSearch Service 도메인에 사용자의 데이터를 추가합니다.
+ 사용자의 API에 메서드를 추가합니다.
+ Lambda 함수에서 검색 쿼리를 수정하거나 다른 필드를 부스트합니다.
+ 결과 스타일을 다르게 지정하거나 `search.js`를 수정하여 사용자에게 다른 필드를 표시합니다.

# 자습서: OpenSearch Service 및 OpenSearch Dashboards를 사용하여 고객 지원 통화 시각화
<a name="walkthrough"></a>

이 장에서는 몇 차례의 고객 지원 문의 전화를 받은 기업에서 이를 분석하려는 상황에 대해 자세히 알아봅니다. 각 통화의 주제는 무엇입니까? 긍정적인 내용은 몇 통이었습니까? 부정적인 내용은 몇 통이었습니까? 관리자가 이러한 통화의 녹취록을 검색하거나 검토하려면 어떻게 해야 합니까?

수작업 워크플로우에서는 직원들이 녹음된 내용을 듣고, 각 통화의 주제를 기록하고, 고객 상담 내용이 긍정적이었는지를 판단합니다.

따라서 이러한 프로세스는 대단히 노동 집약적입니다. 평균 통화 시간이 10분이라고 가정하면 직원 한 명이 하루에 48건의 통화밖에 들을 수 없습니다. 인간의 편견이 작용하지 않는다면 이들은 매우 정확한 데이터를 생산해 내겠지만, 그 데이터의 *양*은 최소한에 불과하여 통화의 주제와 고객이 만족했는지 여부에 대한 부울 값 정도를 얻을 수 있을 것입니다. 전체 녹취록 등 그 이상의 결과물이 필요한 경우에는 막대한 시간이 소요됩니다.

[Amazon S3](https://aws.amazon.com/s3/), [Amazon Transcribe](https://aws.amazon.com/transcribe/), [Amazon Comprehend](https://aws.amazon.com/comprehend/) 및 Amazon OpenSearch Service를 사용하면 비슷한 프로세스를 굉장히 적은 코드로 자동화하여 훨씬 더 많은 데이터를 얻을 수 있습니다. 예를 들면 전체 통화 녹취록, 녹취록의 키워드, 그리고 통화의 전반적인 "감정"(긍정적, 부정적, 중립적, 혼합)을 파악할 수 있습니다. 그런 다음 OpenSearch 및 OpenSearch Dashboards를 사용하여 데이터를 검색하고 시각화할 수 있습니다.

이 연습 단계를 그대로 사용해도 되지만, JSON 문서를 OpenSearch Service에 인덱싱하기 전에 문서를 보강하는 방법에 관한 아이디어를 얻는 것이 이 과정의 목표입니다.

**추정 비용**

일반적으로, 이 연습 단계를 수행하는 데 드는 비용은 2달러 미만입니다. 이 연습 단계에서는 다음 리소스를 사용합니다.
+ 전송 및 저장량이 100MB 미만인 S3 버킷

  자세한 내용은 [Amazon S3 요금](https://aws.amazon.com/s3/pricing/)을 참조하세요.
+ 몇 시간 동안의 10GiB EBS 스토리지와 `t2.medium` 인스턴스 한 개가 있는 OpenSearch Service 도메인

  자세한 내용은 [Amazon OpenSearch Service 요금](https://aws.amazon.com/elasticsearch-service/pricing/)을 참조하세요.
+ Amazon Transcribe에 대한 호출 여러 개

  자세한 내용은 [Amazon Transcribe 요금](https://aws.amazon.com/transcribe/pricing/)을 참조하세요.
+ Amazon Comprehend에 대한 자연어 처리 호출 여러 개

  자세한 내용은 [Amazon Comprehend 요금](https://aws.amazon.com/comprehend/pricing/)을 참조하세요.

**Topics**
+ [1단계: 사전 조건 구성](#walkthrough-prereq)
+ [2단계: 샘플 코드 복사](#walkthrough-script)
+ [(선택 사항) 3단계: 샘플 데이터 인덱싱](#walkthrough-sample-data)
+ [4단계: 데이터 분석 및 시각화](#walkthrough-analysis)
+ [5단계: 리소스 정리 및 다음 단계](#walkthrough-next-steps)

## 1단계: 사전 조건 구성
<a name="walkthrough-prereq"></a>

계속하려면 먼저 다음 리소스를 확보해야 합니다.


****  

| 사전 조건 | 설명 | 
| --- | --- | 
| Amazon S3 버킷 | 자세한 내용은 Amazon Simple Storage Service 사용 설명서에서 [버킷 생성](https://docs.aws.amazon.com/AmazonS3/latest/userguide/CreatingABucket.html)을 참조하세요. | 
| OpenSearch Service 도메인 | 데이터의 대상 주소입니다. 자세한 내용은 [OpenSearch Service 도메인 생성](createupdatedomains.md#createdomains)을 참조하세요. | 

이러한 리소스가 아직 없는 경우 다음 AWS CLI 명령을 사용하여 만들 수 있습니다.

```
aws s3 mb s3://my-transcribe-test --region us-west-2
```

```
aws opensearch create-domain --domain-name my-transcribe-test --engine-version OpenSearch_1.0 --cluster-config  InstanceType=t2.medium.search,InstanceCount=1 --ebs-options EBSEnabled=true,VolumeType=standard,VolumeSize=10 --access-policies '{"Version": "2012-10-17",		 	 	 "Statement":[{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:root"},"Action":"es:*","Resource":"arn:aws:es:us-west-2:123456789012:domain/my-transcribe-test/*"}]}' --region us-west-2
```

**참고**  
이 명령은 `us-west-2` 리전을 사용하지만, Amazon Comprehend가 지원하는 아무 리전이나 사용할 수 있습니다. 자세한 내용은 [AWS 일반 참조](https://docs.aws.amazon.com/general/latest/gr/rande.html#comprehend_region) 섹션을 참조하십시오.

## 2단계: 샘플 코드 복사
<a name="walkthrough-script"></a>

1. 다음 Python 3 샘플 코드를 복사하여 `call-center.py`라는 새 파일에 붙여넣습니다.

   ```
   import boto3
   import datetime
   import json
   import requests
   from requests_aws4auth import AWS4Auth
   import time
   import urllib.request
   
   # Variables to update
   audio_file_name = '' # For example, 000001.mp3
   bucket_name = '' # For example, my-transcribe-test
   domain = '' # For example, https://search-my-transcribe-test-12345.us-west-2.es.amazonaws.com
   index = 'support-calls'
   type = '_doc'
   region = 'us-west-2'
   
   # Upload audio file to S3.
   s3_client = boto3.client('s3')
   
   audio_file = open(audio_file_name, 'rb')
   
   print('Uploading ' + audio_file_name + '...')
   response = s3_client.put_object(
       Body=audio_file,
       Bucket=bucket_name,
       Key=audio_file_name
   )
   
   # # Build the URL to the audio file on S3.
   # # Only for the us-east-1 region.
   # mp3_uri = 'https://' + bucket_name + '.s3.amazonaws.com/' + audio_file_name
   
   # Get the necessary details and build the URL to the audio file on S3.
   # For all other regions.
   response = s3_client.get_bucket_location(
       Bucket=bucket_name
   )
   bucket_region = response['LocationConstraint']
   mp3_uri = 'https://' + bucket_name + '.s3-' + bucket_region + '.amazonaws.com/' + audio_file_name
   
   # Start transcription job.
   transcribe_client = boto3.client('transcribe')
   
   print('Starting transcription job...')
   response = transcribe_client.start_transcription_job(
       TranscriptionJobName=audio_file_name,
       LanguageCode='en-US',
       MediaFormat='mp3',
       Media={
           'MediaFileUri': mp3_uri
       },
       Settings={
           'ShowSpeakerLabels': True,
           'MaxSpeakerLabels': 2 # assumes two people on a phone call
       }
   )
   
   # Wait for the transcription job to finish.
   print('Waiting for job to complete...')
   while True:
       response = transcribe_client.get_transcription_job(TranscriptionJobName=audio_file_name)
       if response['TranscriptionJob']['TranscriptionJobStatus'] in ['COMPLETED', 'FAILED']:
           break
       else:
           print('Still waiting...')
       time.sleep(10)
   
   transcript_uri = response['TranscriptionJob']['Transcript']['TranscriptFileUri']
   
   # Open the JSON file, read it, and get the transcript.
   response = urllib.request.urlopen(transcript_uri)
   raw_json = response.read()
   loaded_json = json.loads(raw_json)
   transcript = loaded_json['results']['transcripts'][0]['transcript']
   
   # Send transcript to Comprehend for key phrases and sentiment.
   comprehend_client = boto3.client('comprehend')
   
   # If necessary, trim the transcript.
   # If the transcript is more than 5 KB, the Comprehend calls fail.
   if len(transcript) > 5000:
       trimmed_transcript = transcript[:5000]
   else:
       trimmed_transcript = transcript
   
   print('Detecting key phrases...')
   response = comprehend_client.detect_key_phrases(
       Text=trimmed_transcript,
       LanguageCode='en'
   )
   
   keywords = []
   for keyword in response['KeyPhrases']:
       keywords.append(keyword['Text'])
   
   print('Detecting sentiment...')
   response = comprehend_client.detect_sentiment(
       Text=trimmed_transcript,
       LanguageCode='en'
   )
   
   sentiment = response['Sentiment']
   
   # Build the Amazon OpenSearch Service URL.
   id = audio_file_name.strip('.mp3')
   url = domain + '/' + index + '/' + type + '/' + id
   
   # Create the JSON document.
   json_document = {'transcript': transcript, 'keywords': keywords, 'sentiment': sentiment, 'timestamp': datetime.datetime.now().isoformat()}
   
   # Provide all details necessary to sign the indexing request.
   credentials = boto3.Session().get_credentials()
   awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, 'opensearchservice', session_token=credentials.token)
   
   # Index the document.
   print('Indexing document...')
   response = requests.put(url, auth=awsauth, json=json_document, headers=headers)
   
   print(response)
   print(response.json())
   ```

1. 처음 여섯 개의 변수를 업데이트합니다.

1. 다음 명령을 사용하여 필요한 패키지를 설치합니다.

   ```
   pip install boto3
   pip install requests
   pip install requests_aws4auth
   ```

1. MP3를 `call-center.py`와 동일한 디렉터리에 넣고 스크립트를 실행합니다. 샘플 출력은 다음과 같습니다.

   ```
   $ python call-center.py
   Uploading 000001.mp3...
   Starting transcription job...
   Waiting for job to complete...
   Still waiting...
   Still waiting...
   Still waiting...
   Still waiting...
   Still waiting...
   Still waiting...
   Still waiting...
   Detecting key phrases...
   Detecting sentiment...
   Indexing document...
   <Response [201]>
   {u'_type': u'call', u'_seq_no': 0, u'_shards': {u'successful': 1, u'failed': 0, u'total': 2}, u'_index': u'support-calls4', u'_version': 1, u'_primary_term': 1, u'result': u'created', u'_id': u'000001'}
   ```

`call-center.py`는 다음 몇 가지 작업을 수행합니다.

1. 이 스크립트는 S3 버킷에 오디오 파일(이 경우에는 MP3지만, Amazon Transcribe는 다른 형식도 지원함)을 업로드합니다.

1. 오디오 파일의 URL을 Amazon Transcribe로 보낸 다음 녹취 작업이 완료되기를 기다립니다.

   녹취 작업의 완료 시간은 오디오 파일의 길이에 따라 달라집니다. 몇 초가 아니라 몇 분이 걸립니다.
**작은 정보**  
녹취 품질을 높이기 위해 Amazon Transcribe에 대한 [사용자 지정 어휘](https://docs.aws.amazon.com/transcribe/latest/dg/API_CreateVocabulary.html)를 구성할 수 있습니다.

1. 녹취 작업이 완료되면 스크립트가 녹취록을 추출하고, 5,000자로 정리한 다음 키워드 및 감정 분석을 위해 Amazon Comprehend로 보냅니다.

1. 마지막으로 이 스크립트는 전체 녹취록, 키워드, 감정 분석, 현재 타임스탬프 등을 JSON 문서에 추가하고 OpenSearch Service에서 이를 인덱싱합니다.

**작은 정보**  
[LibriVox](https://librivox.org/)의 퍼블릭 도메인 오디오북을 테스트에 이용할 수 있습니다.

## (선택 사항) 3단계: 샘플 데이터 인덱싱
<a name="walkthrough-sample-data"></a>

다수의 통화 레코딩을 바로 사용할 수 없는 경우 `call-center.py`에서 생성하는 것에 해당하는 샘플 문서를 [sample-calls.zip](samples/sample-calls.zip)으로 [인덱스](indexing.md)할 수 있습니다.

1. `bulk-helper.py`라는 이름의 파일을 만듭니다.

   ```
   import boto3
   from opensearchpy import OpenSearch, RequestsHttpConnection
   import json
   from requests_aws4auth import AWS4Auth
   
   host = '' # For example, my-test-domain.us-west-2.es.amazonaws.com
   region = '' # For example, us-west-2
   service = 'es'
   
   bulk_file = open('sample-calls.bulk', 'r').read()
   
   credentials = boto3.Session().get_credentials()
   awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token)
   
   search = OpenSearch(
       hosts = [{'host': host, 'port': 443}],
       http_auth = awsauth,
       use_ssl = True,
       verify_certs = True,
       connection_class = RequestsHttpConnection
   )
   
   response = search.bulk(bulk_file)
   print(json.dumps(response, indent=2, sort_keys=True))
   ```

1. `host` 및 `region`의 처음 두 변수를 업데이트합니다.

1. 다음 명령을 사용하여 필요한 패키지를 설치합니다.

   ```
   pip install opensearch-py
   ```

1. [sample-calls.zip](samples/sample-calls.zip)을 다운로드하여 압축을 풉니다.

1. `sample-calls.bulk`를 `bulk-helper.py`와 동일한 디렉터리에 넣고 도움말을 실행합니다. 샘플 출력은 다음과 같습니다.

   ```
   $ python bulk-helper.py
   {
     "errors": false,
     "items": [
       {
         "index": {
           "_id": "1",
           "_index": "support-calls",
           "_primary_term": 1,
           "_seq_no": 42,
           "_shards": {
             "failed": 0,
             "successful": 1,
             "total": 2
           },
           "_type": "_doc",
           "_version": 9,
           "result": "updated",
           "status": 200
         }
       },
       ...
     ],
     "took": 27
   }
   ```

## 4단계: 데이터 분석 및 시각화
<a name="walkthrough-analysis"></a>

OpenSearch Service에 데이터가 있으므로 OpenSearch Dashboards를 사용하여 시각화할 수 있습니다.

1. `https://search-domain.region.es.amazonaws.com/_dashboards`로 이동합니다.

1. OpenSearch Dashboards를 사용하려면 먼저 인덱스 패턴이 있어야 합니다. Dashboards는 인덱스 패턴을 사용하여 분석 범위를 하나 이상의 인덱스로 좁혀 줍니다. `call-center.py`에서 생성된 `support-calls` 인덱스를 일치시키려면 **스택 관리(Stack Management)**, **인덱스 패턴(Index Patterns)**으로 이동하여 `support*`의 인덱스 패턴을 정의한 다음, **다음 단계(Next step)**를 선택합니다.

1. **시간 필터 필드 이름(Time Filter field name)**에서 **타임스탬프(timestamp)**를 선택합니다.

1. 이제 시각화를 생성할 수 있습니다. **시각화(Visualize)**를 선택한 다음, 새 시각화를 추가합니다.

1. 파이 차트와 `support*` 인덱스 패턴을 선택합니다.

1. 시각화의 기본값은 기본이므로 **조각 분할(Split Slices)**을 선택하여 보다 흥미로운 시각화를 만듭니다.

   **집계(Aggregation)**에서 **조건(Terms)**을 선택합니다. **필드(Field)**에서 **sentiment.keyword**를 선택합니다. 그런 다음 **변경 사항 적용(Apply changes)** 및 **저장(Save)**을 선택합니다.  
![\[Dashboards 파이 차트의 샘플 구성.\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/sentiment-pie-chart.png)

1. **시각화(Visualize)** 페이지로 돌아가서 다른 시각화를 추가합니다. 이번에는 가로 막대 차트를 선택합니다.

1. **계열 분할(Split Series)**을 선택합니다.

   **집계(Aggregation)**에서 **조건(Terms)**을 선택합니다. **필드**에서 **keywords.keyword**를 선택하고 **크기(Size)**를 20으로 변경합니다. 그런 다음 **변경 사항 적용(Apply Changes)** 및 **저장(Save)**을 선택합니다.  
![\[Dashboards 가로 막대 차트의 샘플 구성\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/keyword-bar-chart.png)

1. **시각화(Visualize)** 페이지로 돌아가서 마지막 시각화인 세로 막대 차트를 추가합니다.

1. **계열 분할(Split Series)**을 선택합니다. **집계(Aggregation)**에서 **날짜 히스토그램(Date Histogram)**을 선택합니다. **필드(Field)**에서 **타임스탬프(timestamp)**를 선택하고 **간격(Interval)**을 **매일(Daily)**로 변경합니다.

1. **지표 및 축(Metrics & Axes)**을 선택하고 **모드(Mode)**를 **정상(normal)**으로 변경합니다.

1. **변경 사항 적용(Apply Changes)** 및 **저장(Save)**을 선택합니다.  
![\[Dashboards 세로 막대 차트의 샘플 구성.\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/timestamp-bar-chart-2.png)

1. 이제 시각화 세 개를 Dashboards 대시보드에 추가할 수 있습니다. **대시보드(Dashboard)**를 선택하고, 대시보드를 만들고, 시각화를 추가합니다.  
![\[샘플 Dashboard 시각화.\]](http://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/images/dashboard-2.png)

## 5단계: 리소스 정리 및 다음 단계
<a name="walkthrough-next-steps"></a>

불필요한 요금 부과를 피하려면 S3 버킷과 OpenSearch Service 도메인을 삭제하세요. 자세한 내용은 *Amazon Simple Storage Service 사용 설명서*의 [버킷 삭제](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-or-empty-bucket.html#delete-bucket) 및 이 가이드의 [OpenSearch Service 도메인 삭제](gsgdeleting.md) 섹션을 참조하세요.

녹취록은 MP3 파일보다 필요한 디스크 공간이 훨씬 적습니다. MP3 보존 기간을 단축하고(예: 통화 레코딩 3개월에서 1개월로 단축) 스토리지 비용을 절감할 수 있습니다.

또한 AWS Step Functions 및 Lambda를 사용하여 트랜스크립션 프로세스를 자동화하거나, 인덱싱 전에 메타데이터를 추가하거나, 정확한 사용 사례에 맞게 더 복잡한 시각화를 만들 수 있습니다.