

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

# openCypher `explain` 功能
<a name="access-graph-opencypher-explain"></a>

openCypher `explain` 功能是 Amazon Neptune 中的自助式工具，可協助您了解 Neptune 引擎採取的執行方法。若要調用 Explain，您可以使用 `explain={{mode}}` 將參數傳遞至 OpenCypher [HTTPS](access-graph-opencypher-queries.md) 請求，其中 `mode` 值可以是下列其中一個：

****
+ **`static`** – 在 `static` 模式中，`explain` 只會列印查詢計畫的靜態結構。它實際上並不會執行查詢。
+ **`dynamic`** – 在 `dynamic` 模式中，`explain` 也會執行查詢，並包含查詢計畫的動態層面。這些層面可能包含經由運算子流動的中繼繫結數和傳入繫結與傳出繫結的比率，以及每個運算子所花費的時間。
+ **`details`** – 在 `details` 模式中，`explain` 會列印動態模式中顯示的資訊及其他詳細資訊，例如，實際 openCypher 查詢字串，以及構成聯結運算子基礎之模式的預估範圍計數。

  

例如，使用 `POST`搭配 `dynamic` 模式：

------
#### [ AWS CLI ]

```
aws neptunedata execute-open-cypher-explain-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "MATCH (n) RETURN n LIMIT 1" \
  --explain-mode dynamic
```

如需詳細資訊，請參閱《 AWS CLI 命令參考》中的 [execute-open-cypher-explain-query](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/execute-open-cypher-explain-query.html)。

------
#### [ SDK ]

```
import boto3
from botocore.config import Config

client = boto3.client(
    'neptunedata',
    endpoint_url='https://{{your-neptune-endpoint}}:{{port}}',
    config=Config(read_timeout=None, retries={'total_max_attempts': 1})
)

response = client.execute_open_cypher_explain_query(
    openCypherQuery='MATCH (n) RETURN n LIMIT 1',
    explainMode='dynamic'
)

print(response['results'].read().decode('utf-8'))
```

如需其他語言的 AWS SDK 範例，請參閱 [AWS 開發套件](access-graph-opencypher-sdk.md)。

------
#### [ awscurl ]

```
awscurl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  --region {{us-east-1}} \
  --service neptune-db \
  -X POST \
  -d "query=MATCH (n) RETURN n LIMIT 1" \
  -d "explain=dynamic"
```

**注意**  
此範例假設您的 AWS 登入資料已在您的環境中設定。將 {{us-east-1}} 取代為 Neptune 叢集的區域。

------
#### [ curl ]

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=MATCH (n) RETURN n LIMIT 1" \
  -d "explain=dynamic"
```

------

## Neptune 中 openCypher `explain` 的限制
<a name="access-graph-opencypher-explain-limitations"></a>

OpenCypher Explain 的目前版本具有下列限制：
+ Explain 計畫目前僅適用於執行唯讀操作的查詢。不支援執行任何類型變動的查詢，例如 `CREATE`、`DELETE`、`MERGE`、`SET` 等等。
+ 特定計畫的運算子和輸出可能會在未來版本中變更。

## openCypher `explain` 輸出中的 DFE 運算子
<a name="access-graph-opencypher-dfe-operators"></a>

若要使用 OpenCypher `explain` 功能提供的資訊，您必須了解一些有關 [DFE 查詢引擎](neptune-dfe-engine.md)運作方式的詳細資料 (DFE 是 Neptune 用來處理 OpenCypher 查詢的引擎)。

DEF 引擎會將每個查詢轉換為運算子的管道。從第一個運算子開始，中繼解決方案會透過此運算子管道從一個運算子流至下一個運算子。Explain 資料表中的每一列都代表評估時間點之前的結果。

可以出現在 DFE 查詢計畫中的運算子如下：

**DFEApply**   –   針對儲存在指定變數中的值，執行引數區段中指定的函數

**DFEBindRelation** – 將具有指定名稱的變數繫結在一起

**DFEChunkLocalSubQuery** – 這是一種非封鎖操作，其會做為包裝正在執行之子查詢的包裝函式。

**DFEDistinctColumn** – 根據指定的變數傳回輸入值的不同子集。

**DFEDistinctRelation** – 根據指定的變數傳回輸入解決方案的不同子集。

**DFEDrain** – 出現在子查詢結尾處，做為該子查詢的終止步驟。解決方案的數目會記錄為 `Units In`。`Units Out` 一律為零。

**DFEForwardValue** — 將所有輸入區塊直接複製為輸出區塊，以傳遞給其下游運算子。

**DFEGroupByHashIndex** — 根據先前計算出的雜湊索引 (使用 `DFEHashIndexBuild` 作業)，針對輸入解決方案執行依據分組作業。作為輸出，指定的輸入會從包含每個輸入解決方案的群組索引鍵的資料欄延伸。

**DFEHashIndexBuild** - 藉由一組變數組建一個雜湊索引作為副作用。此雜湊索引通常會在稍後的作業中重複使用。請參閱 `DFEHashIndexJoin` 或 `DFEGroupByHashIndex` 以了解可能使用此雜湊索引的位置。

**DFEHashIndexJoin** — 針對先前建置的雜湊索引，針對傳入的解決方案執行聯結。請參閱 `DFEHashIndexBuild` 以了解此雜湊索引的建置位置。

**DFEJoinExists** — 採用左右側輸入關係，並保留左側關係的值，這些關係在右側關係中具有對應值 (如指定聯結變數所定義)。

****   –   這是一種非封鎖操作，其會做為子查詢的包裝函數，允許它重複執行以在迴圈中使用。

**DFEMergeChunks**   –   這是一個封鎖操作，其將來自上游運算子的區塊合併為單一解決方案區塊，以傳遞給下游運算子 (`DFESplitChunks` 的反向)。

**DFEMinus** — 採用左右側輸入關係，並保留左側關係的值，這些關係在右側關係中不具對應值 (如指定聯結變數所定義)。如果跨兩個關係的變數沒有重疊，那麼這個運算子只會傳回左側輸入關係。

**DFENotExists** — 採用左右側輸入關係，並保留左側關係的值，這些關係在右側關係中不具對應值 (如指定聯結變數所定義)。如果跨兩個關係的變數沒有重疊，那麼這個運算子會傳回空的關係。

**DFEOptionalJoin** — 執行左側外部聯結 (也稱為 OPTIONAL 聯結)：左側至少有一個聯結夥伴在右側的解決方案會加入，而左側沒有聯結夥伴的解決方案會依原樣轉送。這是一項封鎖操作。

**DFEPipelineJoin** – 針對 `pattern` 引數定義的元組模式聯結輸入。

**DFEPipelineRangeCount** — 計算與指定模式相符的解決方案的數量，並傳回包含計數值的單一解決方案。

**DFEPipelineScan** – 掃描資料庫找出給定的 `pattern` 引數，其中在資料行上具有或沒有給定的篩選條件。

**DFEProject** – 採取多個輸入資料行並只投影所需的資料行。

**DFEReduce** – 對指定的變數執行指定的彙總函數。

**DFERelationalJoin** – 使用合併聯結，根據指定的模式索引鍵，聯結上一個運算子的輸入。這是一項封鎖操作。

**DFERouteChunks** — 從其單一傳入邊緣獲取輸入區塊，並沿著其多個傳出邊緣路由傳送這些區塊。

**DFESelectRows** — 此運算子選擇性地從左側輸入關係解決方案中取得資料列，以轉送至其下游運算子。根據運算子右側輸入關係中提供的資料列識別碼選取的資料列。

**DFESerialize** — 將查詢的最終結果序列化為 JSON 字串序列，將每個輸入解決方案映射到適當的變數名稱。對於節點和邊緣結果，這些結果會序列化為實體屬性和中繼資料的映射。

**DFESort** — 取得輸入關係，並根據提供的排序索引鍵產生排序關係。

**DFESplitByGroup** — 將每個單一輸入區塊從一個傳入邊緣分割為較小的輸出區塊，對應於由另一個傳入邊緣的對應輸入區塊的資料列 ID 識別的資料列群組。

**DFESplitChunks** — 將每個單一輸入區塊分割成較小的輸出區塊 (`DFEMergeChunks` 的反向)。

**DFEStreamingHashIndexBuild**   – `DFEHashIndexBuild` 的串流版本。

**DFEStreamingGroupByHashIndex** — `DFEGroupByHashIndex` 的串流版本。

**DFESubquery** – 此運算子會出現在所有計畫的開頭處，並封裝 [DFE 引擎](neptune-dfe-engine.md)上執行的計畫部分，即 OpenCypher 的整個計畫。

**DFESymmetricHashJoin** – 使用合併聯結，根據指定的模式索引鍵，聯結上一個運算子的輸入。這是一項非封鎖操作。

**DFESync** — 此運算子是支援非封鎖計劃的同步處理運算子。該運算子從兩個傳入邊緣取得解決方案，並將這些解決方案轉送至適當的下游邊緣。為達同步處理之目的，沿著這些邊緣之一的輸入可以在內部緩衝。

**DFETee** – 這是一個分支運算子，其會將相同的一組解決方案傳送至多個運算子。

**DFETermResolution** — 對其輸入執行本地化或全域化作業，分別產生本土化或全域化識別碼的資料欄。

**** — 將輸入資料欄中的值清單展開至輸出資料欄，作為個別元素。

**DFEUnion** — 接受兩個或多個輸入關係，並使用所需的輸出結構描述產生這些關係的聯集。

**SolutionInjection** – 出現在 Explain 輸出中的所有其他項目之前，其在 Units Out 資料欄中具有 1 值。不過，它提供為無操作，而且實際上並沒有將任何解決方案注入至 DFE 引擎。

**TermResolution** – 出現在計畫結束時，並將物件從 Neptune 引擎轉換為 OpenCypher 物件。

## openCypher `explain` 輸出中的資料行
<a name="access-graph-opencypher-explain-columns"></a>

Neptune 產生以做為 OpenCypher Explain 輸出的查詢計畫資訊包含每列都有一個運算子的資料表。資料表包含以下資料行：

**ID** – 此運算子在計畫中的數字 ID。

**Out \#1** (和 **Out \#2**) – 來自此運算子的下游運算子的 ID。最多可有兩個下游運算子。

**Name** – 此運算子的名稱。

**Arguments** – 運算子的任何相關詳細資訊。這包括輸入結構描述、輸出結構描述、模式 (適用於 `PipelineScan` 和 `PipelineJoin`) 等項目。

**Mode** – 描述基本運算子行為的標籤。此資料行大多為空白 (`-`)。例外是 `TermResolution`，其中模式可以是 `id2value_opencypher`，表示從 ID 解析為 OpenCypher 值。

**Units In** – 以輸入形式傳遞至這個運算子的解決方案數目。沒有上游運算子的運算子 (例如 `DFEPipelineScan`、`SolutionInjections`，以及未插入靜態值的 `DFESubquery`) 將具有零值。

**Units Out** – 產生為此運算子之輸出的解決方案數目。`DFEDrain` 是一種特殊情況，其中要被排除的解決方案數目記錄在 `Units In` 中，並且 `Units Out` 始終為零。

**Ratio** – `Units Out` 與 `Units In` 的比率。

**Time (ms)** – 此運算子取用的 CPU 時間，以毫秒為單位。

## openCypher Explain 輸出的基本範例
<a name="access-graph-opencypher-explain-basic-example"></a>

以下是 openCypher `explain` 輸出的基本範例。查詢是空中路由節點資料集的單一節點查詢，其中包含以預設 ASCII 輸出格式`explain`使用 `details` 模式`ATL`呼叫的機場代碼。

若要叫`explain`用此查詢：

------
#### [ AWS CLI ]

```
aws neptunedata execute-open-cypher-explain-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "MATCH (n {code: 'ATL'}) RETURN n" \
  --explain-mode details
```

如需詳細資訊，請參閱《 AWS CLI 命令參考》中的 [execute-open-cypher-explain-query](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/execute-open-cypher-explain-query.html)。

------
#### [ SDK ]

```
import boto3
from botocore.config import Config

client = boto3.client(
    'neptunedata',
    endpoint_url='https://{{your-neptune-endpoint}}:{{port}}',
    config=Config(read_timeout=None, retries={'total_max_attempts': 1})
)

response = client.execute_open_cypher_explain_query(
    openCypherQuery="MATCH (n {code: 'ATL'}) RETURN n",
    explainMode='details'
)

print(response['results'].read().decode('utf-8'))
```

如需其他語言的 AWS SDK 範例，請參閱 [AWS 開發套件](access-graph-opencypher-sdk.md)。

------
#### [ awscurl ]

```
awscurl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  --region {{us-east-1}} \
  --service neptune-db \
  -X POST \
  -d "query=MATCH (n {code: 'ATL'}) RETURN n" \
  -d "explain=details"
```

**注意**  
此範例假設您的 AWS 登入資料已在您的環境中設定。將 {{us-east-1}} 取代為 Neptune 叢集的區域。

------
#### [ curl ]

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=MATCH (n {code: 'ATL'}) RETURN n" \
  -d "explain=details"
```

------

`explain` 輸出：

```
Query:
MATCH (n {code: 'ATL'}) RETURN n

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 1         │ 0.00  │ 4.00      ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?n]          │ id2value_opencypher │ 1        │ 1         │ 1.00  │ 2.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?n) with property 'code' as ?n_code2 and label 'ALL'                                            │ -    │ 0        │ 1         │ 0.00  │ 0.21      ║
║    │        │        │                       │ inlineFilters=[(?n_code2 IN ["ATL"^^xsd:string])]                                                            │      │          │           │       │           ║
║    │        │        │                       │ patternEstimate=1                                                                                            │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEProject            │ columns=[?n]                                                                                                 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 1        │ 0         │ 0.00  │ 0.03      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?n, ?n_code2]                                   │ -    │ 0        │ 1         │ 0.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -    │ 1        │ 2         │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?n                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.20      ║
║    │        │        │                      │ ordered=false                                              │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?n]                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Node(?n) with property 'ALL' and label '?n_label1' │ -    │ 1        │ 1         │ 1.00  │ 0.25      ║
║    │        │        │                      │ patternEstimate=3506                                       │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ 7      │ DFESync              │ -                                                          │ -    │ 2        │ 2         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                                          │ -    │ 2        │ 1         │ 0.50  │ 0.35      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ -      │ -      │ DFEDrain             │ -                                                          │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

在頂層，`SolutionInjection` 出現在其他所有項目之前，有 1 個單位輸出。請注意，它實際上並沒有注入任何解決方案。您可以看到下一個運算子 `DFESubquery` 具有 0 個單位輸入。

在 `SolutionInjection` 之後，位於頂層的是 `DFESubquery` 和 `TermResolution` 運算子。`DFESubquery` 會封裝要推送至 [DFE 引擎](neptune-dfe-engine.md)之查詢執行計畫的多個部分 (對於 OpenCypher 查詢，整個查詢計畫是由 DFE 執行)。查詢計畫中的所有運算子都會在 `DFESubquery` 所參考的 `subQuery1` 內形成巢狀。唯一的例外是 `TermResolution`，其會將內部 ID 具體化為完全序列化的 OpenCypher 物件。

向下推送至 DFE 引擎的所有運算子都具有以 `DFE` 字首開頭的名稱。如上所述，整個 OpenCypher 查詢計畫是由 DFE 執行，因此，除了最終的 `TermResolution` 運算子之外，所有運算子都會以 `DFE` 開頭。

在 `subQuery1` 內部，可有零個或多個 `DFEChunkLocalSubQuery` 或 `DFELoopSubQuery` 運算子，封裝在記憶體受限機制中執行的推送執行計畫的一部分。這裡的 `DFEChunkLocalSubQuery` 包含一個用作子查詢輸入的 `SolutionInjection`。若要在輸出中尋找該子查詢的資料表，請搜尋在 `DFEChunkLocalSubQuery` 或 `DFELoopSubQuery` 運算子的 `Arguments` 資料行中指定的 `subQuery={{graph URI}}`。

在 `subQuery1` 中，`ID` 為 0 的 `DFEPipelineScan` 會掃描資料庫找出指定的 `pattern`。該模式會對所有標籤掃描屬性 `code` 儲存為變數 `?n_code2` 的實體 (您可以透過將 `airport` 附加到 `n:airport` 根據特定標籤進行篩選)。`inlineFilters` 引數顯示等於 `ATL` 的 `code` 屬性的篩選。

接下來，`DFEChunkLocalSubQuery` 運算子加入包含 `DFEPipelineJoin` 的子查詢的中繼結果。這可確保 `?n` 實際上是一個節點，因為先前的 `DFEPipelineScan` 會掃描任何具有 `code` 屬性的實體。