

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

# 在 Amazon Neptune Gremlin 中快取查詢結果
<a name="gremlin-results-cache"></a>

Amazon Neptune 支援 Gremlin 查詢的結果快取。

您可以啟用查詢結果快取，然後使用查詢提示來快取 Gremlin 唯讀查詢的結果。

然後，只要快取的結果仍在快取中，重新執行查詢就會擷取這些結果，延遲低且沒有 I/O 成本。這適用於在 HTTP 端點上和使用 Websockets 提交的查詢，無論是做為位元碼或以字串形式。

**注意**  
即使啟用查詢快取，也不會快取傳送至設定檔端點的查詢。

您可以透過數種方式控制 Neptune 查詢結果快取的行為。例如：
+ 您可以透過區塊取得分頁的快取結果。
+ 您可以針對指定的查詢指定存留時間 (TTL)。
+ 您可以清除所指定查詢的快取。
+ 您可以清除整個快取。
+ 您可以設定，若結果超過快取大小，則會收到通知。

快取是使用最近最少使用 (LRU) 政策來維護，這表示，一旦配置給快取的空間已滿，就會移除最近最少使用的結果，以在快取新結果時騰出空間。

**重要**  
`t3.medium` 或 `t4.medium` 執行個體類型上無法使用查詢結果快取。

## 在 Neptune 中啟用查詢結果快取
<a name="gremlin-results-cache-enabling"></a>

 查詢結果快取可以在叢集或每個執行個體中的所有執行個體中啟用。若要在叢集中的所有執行個體上啟用結果快取，請將叢集的 中的 `neptune_result_cache` 參數`cluster-parameter-group`設定為 `1`。若要在特定執行個體上啟用此功能，請將執行個體的 中的 `neptune_result_cache` 參數`instance-parameter-group`設定為 `1`。叢集參數群組設定會覆寫執行個體參數群組值。

 任何受影響的執行個體都需要重新啟動，才能套用結果快取參數設定。雖然您可以透過 啟用叢集中所有執行個體的結果快取`cluster-parameter-group`，但每個執行個體都會維護自己的快取。查詢結果快取功能不是整個叢集的快取。

一旦啟用了結果快取，Neptune 就會留出目前記憶體的一部分來快取查詢結果。您使用的執行個體類型越大且可用的記憶體越多，Neptune 為快取留出的記憶體就越多。

如果結果快取記憶體已滿，Neptune 會自動捨棄最近最少使用 (LRU) 快取的結果，以讓位給新的結果。

您可以使用 [執行個體狀態](access-graph-status.md) 命令檢查結果快取的目前狀態。

## 使用提示快取查詢結果
<a name="gremlin-results-cache-using"></a>

一旦啟用了查詢結果快取，就會使用查詢提示來控制查詢快取。以下所有範例都適用於相同的查詢周遊，即：

```
g.V().has('genre','drama').in('likes')
```

### 使用 `enableResultCache`
<a name="using-enableResultCache"></a>

啟用查詢結果快取後，您可以使用 `enableResultCache` 查詢提示，快取 Grinlin 查詢的結果，如下所示：

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

Neptune 接著會將查詢結果傳回給您，同時也會快取它們。稍後，您可以再次發出完全相同的查詢來存取快取的結果：

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

識別快取結果的快取金鑰是查詢字串本身，即：

```
g.V().has('genre','drama').in('likes')
```

### 使用 `enableResultCacheWithTTL`
<a name="using-enableResultCacheWithTTL"></a>

您可以使用查詢提示，指定應快取 `enableResultCacheWithTTL` 查詢結果多長時間。例如，下列查詢會指定查詢結果應在 120 秒後到期：

```
g.with('Neptune#enableResultCacheWithTTL', 120)
 .V().has('genre','drama').in('likes')
```

同樣地，識別快取結果的快取金鑰是基礎查詢字串：

```
g.V().has('genre','drama').in('likes')
```

您可以再次搭配 `enableResultCache` 查詢提示使用該查詢字串，存取快取的結果：

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

如果自快取結果以來已經過了 120 秒或以上，則該查詢將會傳回新結果並快取它們，沒有任何存留時間。

您也可以使用 `enableResultCacheWithTTL` 查詢提示再次發出相同的查詢來存取快取的結果。例如：

```
g.with('Neptune#enableResultCacheWithTTL', 140)
 .V().has('genre','drama').in('likes')
```

直到過了 120 秒後 (也就是目前有效的 TTL)，這個使用 `enableResultCacheWithTTL` 查詢提示的新查詢就會傳回快取的結果。120 秒後，它將傳回新結果並快取它們，存留時間為 140 秒。

**注意**  
如果查詢金鑰的結果已快取，則具有 `enableResultCacheWithTTL` 的相同查詢金鑰不會產生新結果，也不會影響目前快取結果的存留時間。  
如果之前已使用 `enableResultCache` 快取結果，則必須先清除此快取，然後 `enableResultCacheWithTTL` 才能產生新結果，並快取它們，存留時間為其指定的 TTL。
如果之前已使用 `enableResultCachewithTTL` 快取結果，則先前的 TTL 必須先過期，然後 `enableResultCacheWithTTL` 才能產生新結果，並快取它們，存留時間為其指定的 TTL。

### 使用 `invalidateResultCacheKey`
<a name="using-invalidateResultCacheKey"></a>

您可以使用 `invalidateResultCacheKey` 查詢提示來清除某個特定查詢的快取結果。例如：

```
g.with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

該查詢會清除查詢金鑰 `g.V().has('genre','drama').in('likes')` 的快取，並傳回該查詢的新結果。

您也可以結合 `invalidateResultCacheKey` 與 `enableResultCache` 或 `enableResultCacheWithTTL`。例如，下列查詢會清除目前快取的結果、快取新結果，然後傳回它們：

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

### 使用 `invalidateResultCache`
<a name="using-invalidateResultCache"></a>

您可以使用 `invalidateResultCache` 查詢提示來清除查詢結果快取中的所有快取結果。例如：

```
g.with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

該查詢會清除整個結果快取，並傳回查詢的新結果。

您也可以結合 `invalidateResultCache` 與 `enableResultCache` 或 `enableResultCacheWithTTL`。例如，下列查詢會清除整個結果快取、快取此查詢的新結果，然後傳回它們：

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

## 對快取的查詢結果進行分頁
<a name="gremlin-results-cache-paginating"></a>

假設您已快取大量的結果，如下所示：

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

現在假設您發出以下範圍查詢：

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes').range(0,10)
```

Neptune 首先尋找完整的快取金鑰，即 `g.V().has('genre','drama').in('likes').range(0,10)`。如果該金鑰不存在，Neptune 接下來會查看該查詢字串是否有金鑰沒有範圍 (即 `g.V().has('genre','drama').in('likes')`)。當它找到該金鑰時，Neptune 接著會從其快取中擷取前十個結果，如範圍所指定。

**注意**  
如果您搭配結尾有範圍的查詢使用 `invalidateResultCacheKey` 查詢提示，Neptune 會在找不到與具有範圍的查詢完全相符的項目時，Neptune 會清除沒有範圍的查詢快取。

### 搭配使用 `numResultsCached` 與 `.iterate()`
<a name="gremlin-results-cache-paginating-numResultsCached"></a>

使用 `numResultsCached` 查詢提示，您可以填入結果快取，而不會傳回所有快取的結果，這在您偏好對大量結果進行分頁時很有用。

`numResultsCached` 查詢提示僅會使用結尾為 `iterate()` 的查詢。

例如，如果您想要快取範例查詢的前 50 個結果：

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').iterate()
```

在此情況下，快取中的查詢金鑰是：`g.with("Neptune#numResultsCached", 50).V().has('genre','drama').in('likes')`。您現在可以使用此查詢，擷取前十個快取結果：

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').range(0, 10)
```

您也可以從查詢中擷取接下來的十個結果，如下所示：

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').range(10, 20)
```

請不要忘記包含 `numResultsCached` 提示！它是查詢金鑰的必要部分，因此必須存在才能存取快取的結果。

**使用 `numResultsCached` 時要謹記的一些事項：**
+ **您使用 `numResultsCached` 提供的數目會在查詢結束時套用。**  例如，這表示下列查詢實際上會快取範圍 `(1000, 1500)` 內的結果：

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```
+ **您使用 `numResultsCached` 提供的數目會指定要快取的結果數目上限。**  例如，這表示下列查詢實際上會快取範圍 `(1000, 2000)` 內的結果：

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 100000)
   .V().range(1000, 2000).iterate()
  ```
+ **結尾為 `.range().iterate()` 的查詢所快取的結果具有自己的範圍。**  例如，假設您使用如下的查詢來快取結果：

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```

  若要從快取中擷取前 100 個結果，您將撰寫如下的查詢：

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).range(0, 100)
  ```

  這百個結果將等同於來自範圍 `(1000, 1100)` 中基礎查詢的結果。

## 用來尋找快取結果的查詢快取金鑰
<a name="gremlin-results-cache-query-keys"></a>

在已快取查詢結果之後，具有相同「查詢快取金鑰」**的後續查詢會從快取擷取結果，而不是產生新的結果。查詢的查詢快取金鑰會進行如下的評估：

1. 所有快取相關的查詢提示都會被忽略，但 `numResultsCached` 除外。

1. 最後一個 `iterate()` 步驟會被忽略。

1. 查詢的其餘部分會根據其位元碼表示法進行排序。

產生的字串會與快取中已存在的查詢結果索引進行比對，以判斷查詢是否有快取命中。

例如，採取以下查詢：

```
g.withSideEffect('Neptune#typePromotion', false).with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').iterate()
```

它將儲存為如下的位元碼版本：

```
g.withSideEffect('Neptune#typePromotion', false)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes')
```

## 與結果快取相關的例外狀況
<a name="gremlin-results-cache-exceptions"></a>

如果即使在移除先前快取的所有項目之後，您嘗試快取的查詢結果仍太大而無法容納於快取記憶體中，Neptune 就會引發 `QueryLimitExceededException` 錯誤。系統不會傳回任何結果，且例外狀況會產生下列錯誤訊息：

```
The result size is larger than the allocated cache,
      please refer to results cache best practices for options to rerun the query.
```

您可以使用 `noCacheExceptions` 查詢提示來隱藏此訊息，如下所示：

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#noCacheExceptions', true)
 .V().has('genre','drama').in('likes')
```