

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 偵測和修正 DynamoDB 中的索引鍵違規情況
<a name="GSI.OnlineOps.ViolationDetection"></a>

在建立全域次要索引的回填階段，Amazon DynamoDB 會檢查資料表中的每個項目，判斷是否符合納入索引中的資格。某些項目可能不符合資格，因為這些項目會導致索引鍵違規情況。在這些情況下，項目會保留在資料表中，但索引沒有該項目的對應項目。

出現以下狀況時會發生*索引鍵違規情況*：
+ 屬性值與索引鍵結構描述資料類型之間存在資料類型不相符的問題。例如，假設其中一個項目在 `GameScores` 資料表中有一個類型為 `String` 的值 `TopScore`。如果新增分割區索引鍵為 `TopScore`、類型為 `Number` 的全域次要索引，資料表中的項目會違反索引鍵。
+ 來自資料表的屬性數值超過索引鍵屬性的最大長度。分割區索引鍵的最大長度是 2048 個位元組，而排序索引鍵的最大長度是 1024 個位元組。如果資料表中的任何對應屬性值超過這些限制，資料表中的項目將違反索引鍵。

**注意**  
如果為用作索引鍵的屬性設定了「字串」或「二進制」屬性值，則屬性值的長度必須大於零；否則，資料表中的項目將違反索引鍵。  
這個工具此時不會標記此索引鍵違規情況。

如果發生索引鍵違規情況，回填階段會繼續，而不會中斷。但是，索引中不會包含任何違規項目。回填階段完成後，所有違反新索引鍵結構描述的項目寫入都會遭到拒絕。

若要識別並修正資料表中違反索引鍵的屬性值，請使用 Violation Detector 工具。若要執行 Violation Detector，請建立組態檔案，指定要掃描的資料表名稱、全域次要索引分割區索引鍵及排序索引鍵的名稱和資料類型，以及發現任何索引鍵違規情況時要採取的動作。Violation Detector 可以在以下兩種不同模式之一執行：
+ **偵測模式**：偵測索引鍵違規情況。使用偵測模式報告資料表中會導致全域次要索引中發生索引鍵違規情況的項目。(您可以選擇請求在找到這些違規的資料表項目時立即將其刪除。) 偵測模式的輸出會寫入檔案，可供您用其進行進一步分析。
+ **校正模式**：校正索引鍵違規情況。在校正模式下，Violation Detector 會從偵測模式讀取與輸出檔案格式相同的輸入檔案。校正模式會從輸入檔案讀取紀錄，並且會針對每個紀錄刪除或更新資料表中的對應項目。(請注意，如果您選擇更新項目，則必須編輯輸入檔案並為這些更新設定適當的值。)

## 下載並執行 Violation Detector
<a name="GSI.OnlineOps.ViolationDetection.Running"></a>

Violation Detector 可以作為可執行的 Java 封存檔 (`.jar` 檔案)，並在 Windows、macOS 或 Linux 電腦上執行。Violation Detector 需要 Java 1.7 (或更新版本) 和 Apache Maven。
+ [從 GitHub 下載 Violation Detector](https://github.com/awslabs/dynamodb-online-index-violation-detector)

請遵循 `README.md` 檔案中的說明使用 Maven 下載並安裝 Violation Detector。

若要啟動 Violation Detector，請移至您已建立 `ViolationDetector.java` 的目錄，然後輸入下列命令。

```
java -jar ViolationDetector.jar [options]
```

Violation Detector 命令列接受下列選項：
+ `-h | --help`：列印 Violation Detector 的使用摘要和選項。
+ `-p | --configFilePath` `value`：Violation Detector 組態檔案的完全合格名稱。如需詳細資訊，請參閱 [Violation Detector 組態檔案](#GSI.OnlineOps.ViolationDetection.ConfigFile)。
+ `-t | --detect` `value`：偵測資料表中的索引鍵違規情況，並將其寫入 Violation Detector 輸出檔案。如果此參數的值設定為 `keep`，則不會修改具有索引鍵違規情況的項目。如果值設為 `delete`，則會從資料表中刪除具有索引鍵違規情況的項目。
+ `-c | --correct` `value`：從輸入檔案讀取索引鍵違規情況，並對資料表中的項目採取更正動作。如果此參數的值設定為 `update`，則會使用新的非違規值來更新具有索引鍵違規情況的項目。如果值設為 `delete`，則會從資料表中刪除具有索引鍵違規情況的項目。

## Violation Detector 組態檔案
<a name="GSI.OnlineOps.ViolationDetection.ConfigFile"></a>

在執行時期，Violation Detector 工具需要組態檔案。此檔案中的參數決定 Violation Detector 可以存取哪些 DynamoDB 資源，以及其可以消耗多少佈建的輸送量。下表描述了這些參數。


****  

| 參數名稱 | Description | 是否為必要？ | 
| --- | --- | --- | 
|  `awsCredentialsFile`  |  包含您 AWS 憑證的檔案的完全合格名稱。憑證檔案必須採用下列格式： <pre>accessKey = access_key_id_goes_here<br />secretKey = secret_key_goes_here </pre>  |  是  | 
|  `dynamoDBRegion`  |  資料表所在的 AWS 區域。例如：`us-west-2`。  |  是  | 
|  `tableName`  | 所要掃描 DynamoDB 資料表的名稱。 |  是  | 
|  `gsiHashKeyName`  |  索引分割區索引鍵的名稱。  |  是  | 
|  `gsiHashKeyType`  |  索引分割區索引鍵的資料類型：`String`、`Number` 或 `Binary`： `S \| N \| B`  |  是  | 
|  `gsiRangeKeyName`  |  索引排序索引鍵的名稱。如果索引只有簡易的主索引鍵 (分割區索引鍵)，請勿指定此參數。  |  否  | 
|  `gsiRangeKeyType`  |  索引排序索引鍵的資料類型：`String`、`Number` 或 `Binary`： `S \| N \| B`  如果索引只有簡易的主索引鍵 (分割區索引鍵)，請勿指定此參數。  |  否  | 
|  `recordDetails`  |  是否將索引鍵違規情況的完整詳細資訊寫入輸出檔案。如果設定為 `true` (預設值)，則會報告違規項目的完整資訊。如果設定為 `false`，則只會報告違規情況的數量。  |  否  | 
|  `recordGsiValueInViolationRecord`  |  是否將違反索引鍵的數值寫入輸出檔案。如果設定為 `true` (預設值)，則會報告索引鍵值。如果設定為 `false`，則不會報告索引鍵值。  |  否  | 
|  `detectionOutputPath`  |  Violation Detector 輸出檔案的完整路徑。此參數支援寫入本機目錄或 Amazon Simple Storage Service (Amazon S3)。範例如下： `detectionOutputPath = ``//local/path/filename.csv` `detectionOutputPath = ``s3://bucket/filename.csv` 輸出檔案中的資訊會以逗號分隔值 (CSV) 格式顯示。如果您未設定 `detectionOutputPath`，則輸出檔案會命名為 `violation_detection.csv` 並寫入目前的工作目錄。  |  否  | 
|  `numOfSegments`  | 當 Violation Detector 掃描資料表時，要使用的平行掃描區段數目。預設值為 1，表示會以連續方式掃描資料表。如果數值為 2 或更高，則 Violation Detector 會將資料表分割為許多邏輯區段和相同數量的掃描執行緒。`numOfSegments` 的最高設定為 4096。對於較大的資料表，平行掃描通常比循序掃描更快。此外，如果資料表大小足以跨越多個分割區，則平行掃描會將讀取活動平均分配到多個分割區。如需在 DynamoDB 中執行平行掃描的詳細資訊，請參閱 [平行掃描](Scan.md#Scan.ParallelScan)。 |  否  | 
|  `numOfViolations`  |  索引鍵違規情況寫入輸出檔案的上限。如果設定為 `-1` (預設值)，則會掃描整個資料表。如果設定為正整數，則 Violation Detector 會在偵測到該數量的違規情況後停止。  |  否  | 
|  `numOfRecords`  |  要掃描的資料表中的項目數。如果設定為 -1 (預設值)，則會掃描整個資料表。如果設定為正整數，則 Violation Detector 會在掃描到資料表中該數量的項目後停止。  |  否  | 
|  `readWriteIOPSPercent`  |  規範資料表掃描期間耗用的已佈建讀取容量單位百分比。有效值範圍從 `1` 到 `100`。預設值 (`25`) 表示 Violation Detector 將消耗不超過資料表佈建的讀取輸送量的 25%。  |  否  | 
|  `correctionInputPath`  |  Violation Detector 修正輸入檔案的完整路徑。如果您在校正模式下執行 Violation Detector，則會使用此檔案的內容來修改或刪除資料表中違反全域次要索引的資料項目。 `correctionInputPath` 檔案的格式與 `detectionOutputPath` 檔案的格式相同。這可讓您在校正模式下將偵測模式的輸出作為輸入處理。  |  否  | 
|  `correctionOutputPath`  |  Violation Detector 修正輸出檔案的完整路徑。只有在發生更新錯誤時，才會建立此檔案。 此參數支援寫入本機目錄或 Amazon S3。範例如下： `correctionOutputPath = ``//local/path/filename.csv` `correctionOutputPath = ``s3://bucket/filename.csv` 輸出檔案中的資訊會以 CSV 格式顯示。如果您未設定 `correctionOutputPath`，則輸出檔案會命名為 `violation_update_errors.csv` 並寫入目前的工作目錄。  |  否  | 

## 偵測
<a name="GSI.OnlineOps.ViolationDetection.Detection"></a>

若要偵測索引鍵違規情況，請將 Violation Detector 與 `--detect` 命令列選項搭配使用。若要顯示此選項的運作方式，請考慮 `ProductCatalog` 資料表。以下是資料表中的項目清單。僅顯示主索引鍵 (`Id`) 以及 `Price` 屬性。


****  

| ID (主索引鍵) | Price | 
| --- | --- | 
| 101 |  5  | 
| 102 |  20  | 
| 103 | 200  | 
| 201 |  100  | 
| 202 |  200  | 
| 203 |  300  | 
| 204 |  400  | 
| 205 |  500  | 

所有 `Price` 的數值均為類型 `Number`。不過，因為 DynamoDB 不具結構描述，所以可以新增具有非數字 `Price` 的項目。例如，假設您將另一個項目新增至 `ProductCatalog` 資料表。


****  

| ID (主索引鍵) | Price | 
| --- | --- | 
| 999 | "Hello" | 

資料表現在共有九個項目。

現在，您將新的全域次要索引新增至資料表 `PriceIndex`。此索引的主索引鍵是分割區索引鍵 `Price`，其類型是 `Number`。建置索引後，將會包含八個項目，但 `ProductCatalog` 資料表含有九個項目。造成此差異的原因是數值 `"Hello"` 的類型為 `String`，但 `PriceIndex` 的主索引鍵為類型 `Number`。此 `String` 值違反全域次要索引鍵，因此不會出現在索引中。

若要在此情況中使用 Violation Detector，請先建立如下的組態檔案。

```
# Properties file for violation detection tool configuration.
# Parameters that are not specified will use default values.

awsCredentialsFile = /home/alice/credentials.txt
dynamoDBRegion = us-west-2
tableName = ProductCatalog
gsiHashKeyName = Price
gsiHashKeyType = N
recordDetails = true
recordGsiValueInViolationRecord = true
detectionOutputPath = ./gsi_violation_check.csv
correctionInputPath = ./gsi_violation_check.csv
numOfSegments = 1
readWriteIOPSPercent = 40
```

接著，您可以執行 Violation Detector，如下列範例所示。

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --detect keep

Violation detection started: sequential scan, Table name: ProductCatalog, GSI name: PriceIndex
Progress: Items scanned in total: 9,    Items scanned by this thread: 9,    Violations found by this thread: 1, Violations deleted by this thread: 0
Violation detection finished: Records scanned: 9, Violations found: 1, Violations deleted: 0, see results at: ./gsi_violation_check.csv
```

如果 `recordDetails` 組態參數設為 `true`，Violation Detector 會將每個違規情況的詳細資訊寫入輸出檔案，如下列範例所示。

```
Table Hash Key,GSI Hash Key Value,GSI Hash Key Violation Type,GSI Hash Key Violation Description,GSI Hash Key Update Value(FOR USER),Delete Blank Attributes When Updating?(Y/N) 

999,"{""S"":""Hello""}",Type Violation,Expected: N Found: S,,
```

輸出檔案採用 CSV 格式。檔案中的第一行是標頭，後接每個違反索引鍵的項目的一筆紀錄。這些違規情況紀錄的欄位如下所示：
+ **資料表雜湊索引鍵** - 資料表中項目的分割區索引鍵值。
+ **資料表範圍索引鍵** - 資料表中項目的排序索引鍵值。
+ **GSI 雜湊索引鍵值** - 全域次要索引的分割區索引鍵值。
+ **GSI 雜湊索引鍵違規情況類型** - `Type Violation` 或 `Size Violation`。
+ **GSI 雜湊索引鍵違規情況說明** - 違反的原因。
+ **GSI 雜湊索引鍵更新值 (針對使用者)** - 在校正模式下，屬性的新使用者提供的數值。
+ **GSI 範圍索引鍵值** - 全域次要索引的排序索引鍵值。
+ **GSI 範圍索引鍵違規情況類型** - `Type Violation` 或 `Size Violation`。
+ **GSI 範圍索引鍵違規情況說明** - 違反的原因。
+ **GSI 範圍索引鍵更新值 (針對使用者)** - 在校正模式下，屬性的新使用者提供的數值。
+ **更新時刪除空白屬性 (是/否)** - 在校正模式下，決定要刪除 (是) 或保留 (否) 資料表中的違規情況，但只有在下列其中一個欄位為空白時：
  + `GSI Hash Key Update Value(FOR USER)`
  + `GSI Range Key Update Value(FOR USER)`

  如果這些欄位中的任何一個並非空白，則 `Delete Blank Attribute When Updating(Y/N)` 不起作用。

**注意**  
輸出格式可能會因組態檔案和命令列選項而有所不同。例如，如果資料表有簡單的主索引鍵 (沒有排序索引鍵)，則輸出中不會出現任何排序索引鍵欄位。  
檔案中的違規情況紀錄可能不會以排序順序顯示。

## 更正
<a name="GSI.OnlineOps.ViolationDetection.Correction"></a>

若要校正索引鍵違規情況，請將 Violation Detector 與 `--correct` 命令列選項搭配使用。在校正模式下，Violation Detector 會讀取 `correctionInputPath` 參數指定的輸入檔案。此檔案具有與 `detectionOutputPath` 檔案相同的格式，以便您可以使用來自偵測的輸出作為校正的輸入。

Violation Detector 提供兩種不同的方法來校正索引鍵違規情況：
+ **刪除違規情況**：刪除具有違反屬性值的資料表項目。
+ **更新違規情況**：更新資料表項目，以非違規值取代違規屬性。

在任何一種情況下，您都可以使用偵測模式的輸出檔案作為校正模式的輸入。

繼續進行 `ProductCatalog` 範例，假設您想要從資料表刪除違規情況。若要執行此操作，請使用以下命令列。

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --correct delete
```

此時，系統會要求您確認是否要刪除違規項目。

```
Are you sure to delete all violations on the table?y/n
y
Confirmed, will delete violations on the table...
Violation correction from file started: Reading records from file: ./gsi_violation_check.csv, will delete these records from table.
Violation correction from file finished: Violations delete: 1, Violations Update: 0
```

現在 `ProductCatalog` 和 `PriceIndex` 都具有相同數量的項目。