

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

# Amazon Neptune 中的非字串 OpenSearch 索引編製。
<a name="full-text-search-non-string-indexing"></a>

Amazon Neptune 中的非字串 OpenSearch 索引編製可讓您使用串流輪詢器，將述詞的非字串值複寫到 OpenSearch。所有可以安全地轉換為對應的 OpenSearch 對應或資料類型的述詞值，接著會複寫至 OpenSearch。

若要在新堆疊上啟用非字串索引， CloudFormation 範本中的 `Enable Non-String Indexing`旗標必須設定為 `true`。這是預設設定。若要更新現有的堆疊以支援非字串索引編製，請參閱下面的 [更新現有堆疊](full-text-search-non-string-indexing-update.md)。

**注意**  
最好不要在 **`1.0.4.2`** 之前的引擎版本上啟用非字串索引編製。
針對符合多個欄位 (其中一些欄位包含字串值，而其他欄位則包含非字串值) 的欄位名稱使用規則表達式的 OpenSearch 查詢，會由於錯誤而失敗。如果 Neptune 中的全文檢索搜尋查詢屬於該類型，也會發生同樣的情況。
按非字串欄位進行排序時，請將「.value」附加到欄位名稱，以區分其與字串欄位。

**Contents**
+ [更新現有的 Neptune 全文檢索搜尋堆疊以支援非字串索引編製](full-text-search-non-string-indexing-update.md)
+ [篩選 Neptune 全文檢索搜尋中要編製索引的欄位](full-text-search-non-string-indexing-filters.md)
  + [按屬性或述詞名稱篩選](full-text-search-non-string-indexing-filters.md#full-text-search-non-string-indexing-filters-name)
  + [按屬性或述詞值類型篩選](full-text-search-non-string-indexing-filters.md#full-text-search-non-string-indexing-filters-datatype)
+ [將 SPARQL 和 Gremlin 資料類型對應至 OpenSearch](full-text-search-non-string-indexing-mapping.md)
+ [資料對應的驗證](full-text-search-data-validation.md)
+ [Neptune 中的範例非字串 OpenSearch 查詢](full-text-search-non-string-examples.md)
  + [取得效齡大於 30 且名稱開頭為「Si」的所有頂點](full-text-search-non-string-examples.md#full-text-search-non-string-example-1)
  + [取得效齡在 10 和 50 之間且名稱與「Ronka」模糊相符的所有節點](full-text-search-non-string-examples.md#full-text-search-non-string-example-2)
  + [取得時間戳記落在過去 25 天內的所有節點](full-text-search-non-string-examples.md#full-text-search-non-string-example-3)
  + [取得時間戳記落在給定年份和月份內的所有節點](full-text-search-non-string-examples.md#full-text-search-non-string-example-4)

# 更新現有的 Neptune 全文檢索搜尋堆疊以支援非字串索引編製
<a name="full-text-search-non-string-indexing-update"></a>

如果您已經在使用 Neptune 全文檢索搜尋，以下是支援非字串索引編製所需採取的步驟：

1. **停止串流輪詢器 Lambda 函數。**這可確保在匯出期間不會複製任何新更新。若要執行此操作，請停用調用 Lambda 函數的雲端事件規則：
   + 在 中 AWS 管理主控台，導覽至 CloudWatch。
   + 選取**規則**。
   + 選擇具有 Lambda 串流輪詢器名稱的規則。
   + 選取**停用**以暫時停用規則。

1. **在 OpenSearch 中刪除目前的 Neptune 索引。**使用下列 `curl` 查詢，從 OpenSearch 叢集中刪除 `amazon_neptune` 索引：

   ```
   curl -X DELETE "your OpenSearch endpoint/amazon_neptune"
   ```

1. **開始一次性從 Neptune 匯出至 OpenSearch。**最好在此時設定新的 OpenSearch 堆疊，以便可為執行匯出的輪詢器挑選新的成品。

   請遵循 [GitHub 中這裡]( https://github.com/awslabs/amazon-neptune-tools/blob/master/export-neptune-to-elasticsearch/readme.md)列出的步驟，開始將您的 Neptune 資料一次性匯出至 OpenSearch。

1. **更新現有串流輪詢器的 Lambda 成品。**在成功完成了將 Neptune 資料匯出至 OpenSearch 之後，請執行下列步驟：
   + 在 中 AWS 管理主控台，導覽至 CloudFormation。
   + 選擇主要父 CloudFormation 堆疊。
   + 為該堆疊選取**更新**選項。
   + 從選項中選取**取代目前的範本**。
   + 對於範本來源，請選取 **Amazon S3 URL**。
   + 對於 Amazon S3 URL，請輸入：

     ```
     https://aws-neptune-customer-samples.s3.amazonaws.com/neptune-stream/neptune_to_elastic_search.json
     ```
   + 選擇**下一步**，而不變更任何 CloudFormation 參數。
   + 選取**更新堆疊**。 CloudFormation 會將串流輪詢器的 Lambda 程式碼成品取代為最新的成品。

1. **重新啟動串流輪詢器。**若要這樣做，請啟用適當的 CloudWatch 規則：
   + 在 中 AWS 管理主控台，導覽至 CloudWatch。
   + 選取**規則**。
   + 選擇具有 Lambda 串流輪詢器名稱的規則。
   + 選取**啟用**。

# 篩選 Neptune 全文檢索搜尋中要編製索引的欄位
<a name="full-text-search-non-string-indexing-filters"></a>

 CloudFormation 範本詳細資訊中有兩個欄位，可讓您指定要從 OpenSearch 索引中排除的屬性或述詞索引鍵或資料類型：

## 按屬性或述詞名稱篩選
<a name="full-text-search-non-string-indexing-filters-name"></a>

您可以使用名為 的選用 CloudFormation 範本參數`Properties to exclude from being inserted into Elastic Search Index`，提供以逗號分隔的屬性清單或述詞索引鍵，以從 OpenSearch 索引中排除。

例如，假設您將此參數設為 `bob`：

```
"Properties to exclude from being inserted into Elastic Search Index" : bob
```

在這種情況下，下列 Gemlin 更新查詢的串流記錄將會遭到捨棄，而不是進入索引：

```
g.V("1").property("bob", "test")
```

同樣地，您可以將此參數設為 `http://my/example#bob`：

```
"Properties to exclude from being inserted into Elastic Search Index" : http://my/example#bob
```

在這種情況下，下列 Gemlin 更新查詢的串流記錄將會遭到捨棄，而不是進入索引：

```
PREFIX ex: <http://my/example#>
INSERT DATA { ex:s1 ex:bob "test"}.
```

如果您未在此 CloudFormation 範本參數中輸入任何內容，則所有未排除的屬性金鑰都會編製索引。

## 按屬性或述詞值類型篩選
<a name="full-text-search-non-string-indexing-filters-datatype"></a>

您可以使用名為 的選用 CloudFormation 範本參數`Datatypes to exclude from being inserted into Elastic Search Index`，提供以逗號分隔的屬性清單或述詞值資料類型，以從 OpenSearch 索引中排除。

對於 SPARQL，您不需要列出完整的 XSD 類型 URI，只需列出資料類型記號即可。您可以列出的有效資料類型記號如下：
+ `string`
+ `boolean`
+ `float`
+ `double`
+ `dateTime`
+ `date`
+ `time`
+ `byte`
+ `short`
+ `int`
+ `long`
+ `decimal`
+ `integer`
+ `nonNegativeInteger`
+ `nonPositiveInteger`
+ `negativeInteger`
+ `unsignedByte`
+ `unsignedShort`
+ `unsignedInt`
+ `unsignedLong`

對於 Gremlin，要列出的有效資料類型如下：
+ `string`
+ `date`
+ `bool`
+ `byte`
+ `short`
+ `int`
+ `long`
+ `float`
+ `double`

例如，假設您將此參數設為 `string`：

```
"Datatypes to exclude from being inserted into Elastic Search Index" : string
```

在這種情況下，下列 Gemlin 更新查詢的串流記錄將會遭到捨棄，而不是進入索引：

```
g.V("1").property("myStringval", "testvalue")
```

同樣地，您可以將此參數設為 `int`：

```
"Datatypes to exclude from being inserted into Elastic Search Index" : int
```

在這種情況下，下列 Gemlin 更新查詢的串流記錄將會遭到捨棄，而不是進入索引：

```
PREFIX ex: <http://my/example#>
PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>
INSERT DATA { ex:s1 ex:bob "11"^^xsd:int }.
```

如果您未在此 CloudFormation 範本參數中輸入任何內容，則其值可安全轉換為 OpenSearch 對等項目的所有屬性都會編製索引。系統會忽略查詢語言不支援的列出類型。

# 將 SPARQL 和 Gremlin 資料類型對應至 OpenSearch
<a name="full-text-search-non-string-indexing-mapping"></a>

OpenSearch 中的新資料類型映射是根據屬性或物件中使用的資料類型所建立。因為某些欄位包含不同類型的值，所以初始對應可能會排除欄位的某些值。

Neptune 資料類型會對應到 OpenSearch 資料類型，如下所示：


| SPARQL 類型 | Gremlin 類型 | OpenSearch 類型 | 
| --- | --- | --- | 
|  `XSD:int` `XSD:unsignedInt` `XSD:integer` `XSD:byte` `XSD:unsignedByte` `XSD:short` `XSD:unsignedShort` `XSD:long` `XSD:unsignedLong`  |  `byte` `short` `int` `long`  | `long` | 
|  `XSD:float` `XSD:double` `XSD:decimal`  |  `float` `double`  | `double` | 
| `XSD:boolean` | `bool` | `boolean` | 
|  `XSD:datetime` `XSD:date`  | `date` | `date` | 
|  `XSD:string` `XSD:time`  | `string` | `text` | 
| *自訂資料類型* | *無* | `text` | 
| *任何其他資料類型* | *無* | `text` | 

例如，下列 Gremlin 更新查詢會針對要新增至 OpenSearch 的「newField」產生新的對應，即 `{ "type" : "double" }`：

```
g.V("1").property("newField" 10.5)
```

同樣地，下列 SPARQL 更新查詢會針對要新增至 OpenSearch 的「ex:byte」產生新的對應，即 `{ "type" : "long" }`：

```
PREFIX ex: <http://my/example#>
PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>

INSERT DATA { ex:test ex:byte "123"^^xsd:byte }.
```

**注意**  
如您所見，從 Neptune 對應到 OpenSearch 的項目，其最後結果可能是在 OpenSearch 具有的資料類型與在 Neptune 具有的資料類型不同。不過，OpenSearch 中有一個明確的文字欄位「資料類型」，可記錄項目在 Neptune 中具有的資料類型。

# 資料對應的驗證
<a name="full-text-search-data-validation"></a>



使用下列程序將資料從 Neptune 複製到 OpenSearch：
+ 如果有問題欄位的對應已存在於 OpenSearch 中：
  + 如果可以使用資料驗證規則，將資料安全地轉換為現有的對應，請將欄位儲存在 OpenSearch 中。
  + 如果沒有，請捨棄相應的串流更新記錄。
+ 如果有問題的欄位中沒有現有的對應，請尋找與 Neptune 中欄位資料類型對應的 OpenSearch 資料類型。
  + 如果可以使用資料驗證規則，將欄位資料安全地轉換為 OpenSearch 資料類型，請將新對應和欄位資料儲存在 OpenSearch 中。
  + 如果沒有，請捨棄相應的串流更新記錄。

這些值是根據對等的 OpenSearch 類型或現有的 OpenSearch 對應 (而非 Neptune 類型) 進行驗證。例如，`"123"^^xsd:int` 中 `"123"` 值的驗證是針對 `long` 類型而非 `int` 類型執行的。

雖然 Neptune 嘗試將所有資料複製到 OpenSearch，但有些情況，OpenSearch 中的資料類型與 Neptune 中的資料類型完全不同，在這類情況下，會略過記錄，而不是在 OpenSearch 中編製索引。

例如，在 Neptune 中，一個屬性可以具有不同類型的多個值，而在 OpenSearch 中，一個欄位必須跨索引具有相同的類型。

透過啟用偵錯日誌，您可以檢視從 Neptune 匯出至 OpenSearch 期間已捨棄哪些記錄。除錯日誌項目的範例如下：

```
Dropping Record : Data type not a valid Gremlin type 
<Record>
```

資料類型的驗證方式如下：
+ **`text`** – Neptune 中的所有值都可以安全地對應到 OpenSearch 中的文字。
+ **`long`** – OpenSearch 對應類型很長時，適用 Neptune 資料類型的下列規則 (在以下範例中，假設 `"testLong"` 具有 `long` 對應類型)：
  + `boolean` – 無效、無法轉換，並會捨棄對應的串流更新記錄。

    無效的 Gremlin 範例如下：

    ```
      "testLong" : true.
      "testLong" : false.
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testLong" : "true"^^xsd:boolean
      ":testLong" : "false"^^xsd:boolean
    ```
  + `datetime` – 無效、無法轉換，並會捨棄對應的串流更新記錄。

    無效的 Gremlin 範例如下：

    ```
      ":testLong" :  datetime('2018-11-04T00:00:00').
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testLong" : "2016-01-01"^^xsd:date
    ```
  + `float`、`double`、或 `decimal` – 如果 Neptune 中的值是可以容納 64 位元的整數，則該值有效且會長時間儲存在 OpenSearch 中，但如果它具有小數部分，或是 `NaN` 或 `INF`，或是大於 9,223,372,036,854,775,807 或小於 -9,223,372,036,854,775,808，則它是無效的，且對應的串流更新記錄會遭到捨棄。

    有效的 Gremlin 範例如下：

    ```
      "testLong" :  145.0.
      ":testLong" :  123
      ":testLong" :  -9223372036854775807
    ```

    有效的 SPARQL 範例如下：

    ```
      ":testLong" : "145.0"^^xsd:float
      ":testLong" :  145.0
      ":testLong" : "145.0"^^xsd:double
      ":testLong" : "145.0"^^xsd:decimal
      ":testLong" : "-9223372036854775807"
    ```

    無效的 Gremlin 範例如下：

    ```
      "testLong" :  123.45
      ":testLong" :  9223372036854775900
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testLong" :  123.45
      ":testLong" :  9223372036854775900
      ":testLong" : "123.45"^^xsd:float
      ":testLong" : "123.45"^^xsd:double
      ":testLong" : "123.45"^^xsd:decimal
    ```
  + `string` – 如果 Neptune 中的值是可以包含在 64 位元整數中的整數的字串表示法，則它是有效的，且會轉換為 OpenSearch 中的 `long`。對於 Elasticseearch `long` 對應，任何其他字串值都是無效的，且相應的串流更新記錄會遭到捨棄。

    有效的 Gremlin 範例如下：

    ```
      "testLong" :  "123".
      ":testLong" :  "145.0"
      ":testLong" :  "-9223372036854775807"
    ```

    有效的 SPARQL 範例如下：

    ```
      ":testLong" : "145.0"^^xsd:string
      ":testLong" : "-9223372036854775807"^^xsd:string
    ```

    無效的 Gremlin 範例如下：

    ```
      "testLong" :  "123.45"
      ":testLong" :  "9223372036854775900"
      ":testLong" :  "abc"
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testLong" : "123.45"^^xsd:string
      ":testLong" : "abc"
      ":testLong" : "9223372036854775900"^^xsd:string
    ```
+ **`double`** – 如果 OpenSearch 對應類型為 `double`，則會套用下列規則 (此處假設「testDouble」欄位在 OpenSearch 中具有 `double` 對應)：
  + `boolean` – 無效、無法轉換，並會捨棄對應的串流更新記錄。

    無效的 Gremlin 範例如下：

    ```
      "testDouble" : true.
      "testDouble" : false.
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testDouble" : "true"^^xsd:boolean
      ":testDouble" : "false"^^xsd:boolean
    ```
  + `datetime` – 無效、無法轉換，並會捨棄對應的串流更新記錄。

    無效的 Gremlin 範例如下：

    ```
      ":testDouble" :  datetime('2018-11-04T00:00:00').
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testDouble" : "2016-01-01"^^xsd:date
    ```
  + 浮點 `NaN` 或 `INF` – 如果 SPARQL 中的值是浮點 `NaN` 或 `INF`，則它是無效的，且對應的串流更新記錄會遭到捨棄。

    無效的 SPARQL 範例如下：

    ```
    "  :testDouble" : "NaN"^^xsd:float
      ":testDouble" : "NaN"^^double
      ":testDouble" : "INF"^^double
      ":testDouble" : "-INF"^^double
    ```
  + 數字或數值字串 – 如果 Neptune 中的值是任何其他數字，或是可以安全地表示為 `double` 之數字的數值字串表示法，則它是有效的，且會在 OpenSearch 中轉換為 `double`。對於 OpenSearch `double` 對應，任何其他字串值都是無效的，且相應的串流更新記錄會遭到捨棄。

    有效的 Gremlin 範例如下：

    ```
      "testDouble" :  123
      ":testDouble" :  "123"
      ":testDouble" :  145.67
      ":testDouble" :  "145.67"
    ```

    有效的 SPARQL 範例如下：

    ```
      ":testDouble" :  123.45
      ":testDouble" :  145.0
      ":testDouble" : "123.45"^^xsd:float
      ":testDouble" : "123.45"^^xsd:double
      ":testDouble" : "123.45"^^xsd:decimal
      ":testDouble" : "123.45"^^xsd:string
    ```

    無效的 Gremlin 範例如下：

    ```
      ":testDouble" :  "abc"
    ```

    無效的 SPARQL 範例如下：

    ```
      ":testDouble" : "abc"
    ```
+ **`date`** – 如果 OpenSearch 對應類型為 `date`，Neptune `date` 和 `dateTime` 值都是有效的，任何可以成功剖析為 `dateTime` 格式的字串值也一樣有效。

  Gremlin 或 SPARQL 中的有效範例如下：

  ```
    Date(2016-01-01)
    "2016-01-01" "
    2003-09-25T10:49:41"
    "2003-09-25T10:49"
    "2003-09-25T10"
    "20030925T104941-0300"
    "20030925T104941"
    "2003-Sep-25" "
    Sep-25-2003"
    "2003.Sep.25"
    "2003/09/25"
    "2003 Sep 25" "
    Wed, July 10, '96"
    "Tuesday, April 12, 1952 AD 3:30:42pm PST"
    "123"
    "-123"
    "0"
    "-0"
    "123.00"
    "-123.00"
  ```

  無效的範例如下：

  ```
    123.45
    True
    "abc"
  ```

# Neptune 中的範例非字串 OpenSearch 查詢
<a name="full-text-search-non-string-examples"></a>

Neptune 目前不直接支援 OpenSearch 範圍查詢。不過，您可以使用 Lucene 語法和 query-type="query\$1string" 來達到相同的效果，正如您在下列範例查詢中看到的那樣。

## 取得效齡大於 30 且名稱開頭為「Si」的所有頂點
<a name="full-text-search-non-string-example-1"></a>

在 Gremlin 中：

```
g.withSideEffect('Neptune#fts.endpoint', 'http://your-es-endpoint')
 .withSideEffect("Neptune#fts.queryType", "query_string")
 .V().has('*', 'Neptune#fts predicates.age.value:>30 && predicates.name.value:Si*');
```

在 SPARQL 中：

```
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX neptune-fts: <http://aws.amazon.com/neptune/vocab/v01/services/fts#>
SELECT * WHERE {
  SERVICE neptune-fts:search {
    neptune-fts:config neptune-fts:endpoint 'http://localhost:9200' .
    neptune-fts:config neptune-fts:queryType 'query_string' .
    neptune-fts:config neptune-fts:query "predicates.\\*foaf\\*age.value:>30 AND predicates.\\*foaf\\*name.value:Si*" .
    neptune-fts:config neptune-fts:field '*' .
    neptune-fts:config neptune-fts:return ?res .
  }
}
```

為了簡潔起見，這裡使用 `"\\*foaf\\*age`，而不是完整的 URI。此規則表達式將擷取在 URI 中同時具有 `foaf` 和 `age` 的所有欄位。

## 取得效齡在 10 和 50 之間且名稱與「Ronka」模糊相符的所有節點
<a name="full-text-search-non-string-example-2"></a>

在 Gremlin 中：

```
g.withSideEffect('Neptune#fts.endpoint', 'http://your-es-endpoint')
 .withSideEffect("Neptune#fts.queryType", "query_string")
 .V().has('*', 'Neptune#fts predicates.age.value:[10 TO 50] AND predicates.name.value:Ronka~');
```

在 SPARQL 中：

```
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX neptune-fts: <http://aws.amazon.com/neptune/vocab/v01/services/fts#>
SELECT * WHERE {
  SERVICE neptune-fts:search {
    neptune-fts:config neptune-fts:endpoint 'http://localhost:9200' .
    neptune-fts:config neptune-fts:queryType 'query_string' .
    neptune-fts:config neptune-fts:query "predicates.\\*foaf\\*age.value:[10 TO 50] AND predicates.\\*foaf\\*name.value:Ronka~" .
    neptune-fts:config neptune-fts:field '*' .
    neptune-fts:config neptune-fts:return ?res .
  }
}
```

## 取得時間戳記落在過去 25 天內的所有節點
<a name="full-text-search-non-string-example-3"></a>

在 Gremlin 中：

```
g.withSideEffect('Neptune#fts.endpoint', 'http://your-es-endpoint')
 .withSideEffect("Neptune#fts.queryType", "query_string")
 .V().has('*', 'Neptune#fts predicates.timestamp.value:>now-25d');
```

在 SPARQL 中：

```
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX neptune-fts: <http://aws.amazon.com/neptune/vocab/v01/services/fts#>
SELECT * WHERE {
SELECT * WHERE {
  SERVICE neptune-fts:search {
    neptune-fts:config neptune-fts:endpoint 'http://localhost:9200' .
    neptune-fts:config neptune-fts:queryType 'query_string' .
    neptune-fts:config neptune-fts:query "predicates.\\*foaf\\*timestamp.value:>now-25d~" .
    neptune-fts:config neptune-fts:field '*' .
    neptune-fts:config neptune-fts:return ?res .
  }
}
```

## 取得時間戳記落在給定年份和月份內的所有節點
<a name="full-text-search-non-string-example-4"></a>

在 Gremlin 中，於 Lucene 語法中使用[日期數學運算式](https://www.elastic.co/guide/en/elasticsearch/reference/7.x/common-options.html#date-math)，表示 2020 年 12 月：

```
g.withSideEffect('Neptune#fts.endpoint', 'http://your-es-endpoint')
 .withSideEffect("Neptune#fts.queryType", "query_string")
 .V().has('*', 'Neptune#fts predicates.timestamp.value:>2020-12');
```

Gremlin 替代方案：

```
g.withSideEffect('Neptune#fts.endpoint', 'http://your-es-endpoint')
 .withSideEffect("Neptune#fts.queryType", "query_string")
 .V().has('*', 'Neptune#fts predicates.timestamp.value:[2020-12 TO 2021-01]');
```