

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

# 보조 인덱스 사용
<a name="ddb-en-client-use-secindex"></a>

보조 인덱스는 쿼리 및 스캔 작업에 사용하는 대체 키를 정의하여 데이터 액세스를 향상시킵니다. GSI(글로벌 보조 인덱스)에는 기본 테이블의 파티션 키와 정렬 키가 다를 수 있습니다. 반대로 LSI(로컬 보조 인덱스)는 기본 인덱스의 파티션 키를 사용합니다.

## 보조 인덱스 주석으로 데이터 클래스에 주석 달기
<a name="ddb-en-client-use-secindex-annomodel"></a>

보조 인덱스에 속하는 속성에는 `@DynamoDbSecondaryPartitionKey` 또는 `@DynamoDbSecondarySortKey` 주석이 필요합니다.

다음 클래스는 두 인덱스에 대한 주석을 보여줍니다. *SubjectLastPostedDateIndex*라는 GSI는 파티션 키에 `Subject` 속성을 사용하고 정렬 키에는 `LastPostedDateTime` 속성을 사용합니다. *ForumLastPostedDateIndex라는* 이름의 LSI는 `ForumName`를 파티션 키로, `LastPostedDateTime`를 정렬 키로 사용합니다.

`Subject` 속성은 이중 역할을 한다는 점에 유의하세요. 기본 키의 정렬 키이자 *SubjectLastPostedDateIndex*라는 GSI의 파티션 키입니다.

### `MessageThread` 클래스
<a name="ddb-en-client-use-secindex-class"></a>

이 `MessageThread` 클래스는 *Amazon DynamoDB 개발자 안내서*의 [예제 스레드 테이블](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html)의 데이터 클래스로 사용하기에 적합합니다.

#### 가져오기
<a name="ddb-en-client-use-secindex-classimports"></a>

```
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.List;
```

```
@DynamoDbBean
public class MessageThread {
    private String ForumName;
    private String Subject;
    private String Message;
    private String LastPostedBy;
    private String LastPostedDateTime;
    private Integer Views;
    private Integer Replies;
    private Integer Answered;
    private List<String> Tags;

    @DynamoDbPartitionKey
    public String getForumName() {
        return ForumName;
    }

    public void setForumName(String forumName) {
        ForumName = forumName;
    }

    // Sort key for primary index and partition key for GSI "SubjectLastPostedDateIndex".
    @DynamoDbSortKey
    @DynamoDbSecondaryPartitionKey(indexNames = "SubjectLastPostedDateIndex")
    public String getSubject() {
        return Subject;
    }

    public void setSubject(String subject) {
        Subject = subject;
    }

    // Sort key for GSI "SubjectLastPostedDateIndex" and sort key for LSI "ForumLastPostedDateIndex".
    @DynamoDbSecondarySortKey(indexNames = {"SubjectLastPostedDateIndex", "ForumLastPostedDateIndex"})
    public String getLastPostedDateTime() {
        return LastPostedDateTime;
    }

    public void setLastPostedDateTime(String lastPostedDateTime) {
        LastPostedDateTime = lastPostedDateTime;
    }
    public String getMessage() {
        return Message;
    }

    public void setMessage(String message) {
        Message = message;
    }

    public String getLastPostedBy() {
        return LastPostedBy;
    }

    public void setLastPostedBy(String lastPostedBy) {
        LastPostedBy = lastPostedBy;
    }

    public Integer getViews() {
        return Views;
    }

    public void setViews(Integer views) {
        Views = views;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "ForumRepliesIndex")
    public Integer getReplies() {
        return Replies;
    }

    public void setReplies(Integer replies) {
        Replies = replies;
    }

    public Integer getAnswered() {
        return Answered;
    }

    public void setAnswered(Integer answered) {
        Answered = answered;
    }

    public List<String> getTags() {
        return Tags;
    }

    public void setTags(List<String> tags) {
        Tags = tags;
    }

    public MessageThread() {
        this.Answered = 0;
        this.LastPostedBy = "";
        this.ForumName = "";
        this.Message = "";
        this.LastPostedDateTime = "";
        this.Replies = 0;
        this.Views = 0;
        this.Subject = "";
    }

    @Override
    public String toString() {
        return "MessageThread{" +
                "ForumName='" + ForumName + '\'' +
                ", Subject='" + Subject + '\'' +
                ", Message='" + Message + '\'' +
                ", LastPostedBy='" + LastPostedBy + '\'' +
                ", LastPostedDateTime='" + LastPostedDateTime + '\'' +
                ", Views=" + Views +
                ", Replies=" + Replies +
                ", Answered=" + Answered +
                ", Tags=" + Tags +
                '}';
    }
}
```

## 인덱스 만들기
<a name="ddb-en-client-use-secindex-confindex"></a>

Java용 SDK 버전 2.20.86부터 이 `createTable()` 메서드는 데이터 클래스 주석에서 보조 인덱스를 자동으로 생성합니다. 기본적으로 기본 테이블의 모든 속성이 인덱스에 복사되며 프로비저닝된 처리량 값은 20 읽기 용량 단위 및 20 쓰기 용량 단위입니다.

단, SDK 2.20.86 이전 버전을 사용하는 경우에는 다음 예와 같이 테이블과 함께 인덱스를 빌드해야 합니다. 이 예제에서는 `Thread` 테이블의 인덱스 두 개를 빌드합니다. [빌더](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) 매개 변수에는 주석 줄 1과 2 다음에 표시된 것처럼 두 가지 유형의 인덱스를 모두 구성하는 메서드가 있습니다. 인덱스 빌더의 `indexName()` 메서드를 사용하여 데이터 클래스 주석에 지정된 인덱스 이름을 의도한 인덱스 유형과 연결할 수 있습니다.

이 코드는 모든 테이블 속성이 주석 라인 3과 4 다음에 있는 두 인덱스 모두에 포함되도록 구성합니다. [속성 프로젝션](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections)에 대한 자세한 내용은 *Amazon DynamoDB 개발자 안내서*에서 확인할 수 있습니다.

```
    public static void createMessageThreadTable(DynamoDbTable<MessageThread> messageThreadDynamoDbTable, DynamoDbClient dynamoDbClient) {
        messageThreadDynamoDbTable.createTable(b -> b
                // 1. Generate the GSI.
                .globalSecondaryIndices(gsi -> gsi.indexName("SubjectLastPostedDateIndex")
                        // 3. Populate the GSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
                // 2. Generate the LSI.
                .localSecondaryIndices(lsi -> lsi.indexName("ForumLastPostedDateIndex")
                        // 4. Populate the LSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
        );
```

## 인덱스를 사용하여 쿼리
<a name="ddb-en-client-use-secindex-query"></a>

다음 예시에서는 로컬 보조 인덱스 *ForumLastPostedDateIndex*를 쿼리합니다.

주석 줄 2에 이어 [DynamoDbIndex.query()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)) 메서드를 호출할 때 필요한 [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) 객체를 생성합니다.

인덱스 이름을 전달하여 주석 줄 3 다음에 쿼리하려는 인덱스에 대한 참조를 얻습니다. 주석 줄 4에 이어 `QueryConditional` 객체를 전달하는 인덱스에서 `query()` 메서드를 호출합니다.

또한 주석 줄 5 다음에 표시된 대로 세 가지 속성 값을 반환하도록 쿼리를 구성합니다. `attributesToProject()`가 호출되지 않은 경우 쿼리는 모든 속성 값을 반환합니다. 지정된 속성 이름은 소문자로 시작하는 것을 알 수 있습니다. 이러한 속성 이름은 테이블에 사용된 이름과 일치하지만 반드시 데이터 클래스의 속성 이름과 일치할 필요는 없습니다.

주석 줄 6 다음에 결과를 반복하고 쿼리에서 반환된 각 항목을 기록하고 목록에 저장하여 호출자에게 반환합니다.

```
public class IndexScanExamples {
    private static Logger logger = LoggerFactory.getLogger(IndexScanExamples.class);

    public static List<MessageThread> queryUsingSecondaryIndices(String lastPostedDate,
                                                                 DynamoDbTable<MessageThread> threadTable) {
        // 1. Log the parameter value.
        logger.info("lastPostedDate value: {}", lastPostedDate);

        // 2. Create a QueryConditional whose sort key value must be greater than or equal to the parameter value.
        QueryConditional queryConditional = QueryConditional.sortGreaterThanOrEqualTo(qc ->
                qc.partitionValue("Forum02").sortValue(lastPostedDate));

        // 3. Specify the index name to query.
        final DynamoDbIndex<MessageThread> forumLastPostedDateIndex = threadTable.index("ForumLastPostedDateIndex");

        // 4. Perform the query using the QueryConditional object.
        final SdkIterable<Page<MessageThread>> pagedResult = forumLastPostedDateIndex.query(q -> q
                .queryConditional(queryConditional)
                // 5. Request three attribute in the results.
                .attributesToProject("forumName", "subject", "lastPostedDateTime"));

        List<MessageThread> collectedItems = new ArrayList<>();
        // 6. Iterate through pages response and sort the items.
        pagedResult.stream().forEach(page -> page.items().stream()
                .sorted(Comparator.comparing(MessageThread::getLastPostedDateTime))
                .forEach(mt -> {
                    // 7. Log the returned items and add the collection to return to the caller.
                    logger.info(mt.toString());
                    collectedItems.add(mt);
                }));
        return collectedItems;
    }
```

쿼리가 실행되기 전의 데이터베이스에는 다음과 같은 항목이 있습니다.

```
MessageThread{ForumName='Forum01', Subject='Subject01', Message='Message01', LastPostedBy='', LastPostedDateTime='2023.03.28', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject02', Message='Message02', LastPostedBy='', LastPostedDateTime='2023.03.29', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject04', Message='Message04', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='Message08', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='Message10', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject03', Message='Message03', LastPostedBy='', LastPostedDateTime='2023.03.30', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject06', Message='Message06', LastPostedBy='', LastPostedDateTime='2023.04.02', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject09', Message='Message09', LastPostedBy='', LastPostedDateTime='2023.04.05', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum05', Subject='Subject05', Message='Message05', LastPostedBy='', LastPostedDateTime='2023.04.01', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum07', Subject='Subject07', Message='Message07', LastPostedBy='', LastPostedDateTime='2023.04.03', Views=0, Replies=0, Answered=0, Tags=null}
```

1행과 6행의 로깅 명령문을 실행하면 다음과 같은 콘솔 출력이 나타납니다.

```
lastPostedDate value: 2023.03.31
MessageThread{ForumName='Forum02', Subject='Subject04', Message='', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
```

쿼리가 *Forum02*의 `forumName` 값과 *2023.03.31*보다 크거나 같은 `lastPostedDateTime`을 반환했습니다. 인덱스에 `message` 속성 값이 있더라도 결과에는 빈 문자열이 있는 `message` 값이 표시됩니다. 이는 주석 줄 5 이후에 코드로 메시지 속성이 프로젝션되지 않았기 때문입니다.