

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

# 為各種資料格式撰寫自訂分類器
<a name="custom-classifier"></a>

您可以提供自訂分類器，分類在 AWS Glue中的資料。您可以使用 grok 模式、XML 標籤、JavaScript Object 符號 (JSON) 或逗號分隔值 (CSV)，建立自訂分類器。AWS Glue 爬蟲程式呼叫自訂分類器。如果分類器能夠辨識資料，它會將資料的分類和結構描述傳回爬蟲程式。如果您的資料不符合任何內建的分類器，或者想要自訂由爬蟲程式建立的資料表，那麼您可能需要定義自訂分類器。

 如需使用 AWS Glue 主控台建立分類器的詳細資訊，請參閱[使用 AWS Glue 主控台建立分類器](console-classifiers.md)。

AWS Glue 會依照您指定的順序，在內建的分類器之前執行自訂分類器。當爬蟲程式找到符合資料的分類器時，分類字串和結構描述將用於資料表的定義中，這些資料表將寫入至您的 AWS Glue Data Catalog。

**Topics**
+ [撰寫 grok 自訂分類器](#custom-classifier-grok)
+ [撰寫 XML 自訂分類器](#custom-classifier-xml)
+ [撰寫 JSON 自訂分類器](#custom-classifier-json)
+ [撰寫 CSV 自訂分類器](#custom-classifier-csv)

## 撰寫 grok 自訂分類器
<a name="custom-classifier-grok"></a>

Grok 是一種工具，用於剖析指定相符模式的文字資料。grok 模式是一組命名規則表達式 (regex)， 用於每次比對一行。AWS Glue 使用 grok 模式來推斷資料的結構描述。當 grok 模式符合您的資料時，AWS Glue 將使用此模式判斷您資料的結構，並將其映射到欄位。

AWS Glue 提供許多內建模式，或者您可以定義自己的模式。您可以在自訂分類器定義中使用內建模式和自訂模式來建立 grok 模式。您可以量身打造 grok 模式來分類自訂文字檔案格式。

**注意**  
針對 AWS Glue Data Catalog中建立的資料表，AWS Glue Grok 自訂分類器會使用 `GrokSerDe` 序列化程式庫。如果您將 AWS Glue Data Catalog 與 Amazon Athena、Amazon EMR 或 Redshift Spectrum 搭配使用，請查看這些服務的文件，以取得 支援的相關資訊`GrokSerDe`。目前，當您從 Amazon EMR 和 Redshift 查詢利用 `GrokSerDe` 建立的資料表時，可能會遇到問題。

以下是 grok 模式元件的基本語法：

```
%{PATTERN:field-name}
```

符合具名的 `PATTERN` 的資料會映射到結構描述中的 `field-name` 欄位符合，預設資料類型為 `string`。除此之外，您亦可選擇在產生的結構描述中，將欄位的資料類型轉換為 `byte`、`boolean`、`double`、`short`、`int`、`long` 或 `float`。

```
%{PATTERN:field-name:data-type}
```

例如，若要將 `num` 欄位轉換為 `int` 資料類型，您可以使用此模式：

```
%{NUMBER:num:int}
```

模式可由其他模式組成。舉例而言，您可使用月、日及時間的模式來定義 `SYSLOG` 時間戳記的模式 (例如 `Feb 1 06:25:43`)。您能夠使用下列模式來定義此資料：

```
SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
```

**注意**  
Grok 模式每次只能處理一行。不支援多行模式。此外，不支援在模式中的換行。

### grok 分類器的自訂值
<a name="classifier-values"></a>

定義 grok 分類器時，請提供以下值以建立自訂分類器。

**名稱**  
分類器名稱。

**分類**  
寫入的字串用於描述分類資料的格式；例如 `special-logs`。

**Grok 模式**  
套用到資料存放區的一組模式可判斷是否符合。這些模式皆來自 AWS Glue [ 內建模式](#classifier-builtin-patterns)，以及您所定義的任何自訂模式。  
以下為 grok 模式的範例：  

```
%{TIMESTAMP_ISO8601:timestamp} \[%{MESSAGEPREFIX:message_prefix}\] %{CRAWLERLOGLEVEL:loglevel} : %{GREEDYDATA:message}
```
當資料符合 `TIMESTAMP_ISO8601`，將會建立結構描述欄位 `timestamp`。此行為類似範例中的其他具名模式。

**自訂模式**  
您定義的選用自訂模式。分類您的資料的 grok 模式會參考這些模式。您可以在套用至您資料的 grok 模式中參考這些自訂模式。每個自訂元件模式都必須位於不同的行。[規則表達式 (regex)](http://en.wikipedia.org/wiki/Regular_expression) 語法可用來定義模式。  
以下是使用指定模式的範例：  

```
CRAWLERLOGLEVEL (BENCHMARK|ERROR|WARN|INFO|TRACE)
MESSAGEPREFIX .*-.*-.*-.*-.*
```
當資料符合其中一個列舉字串時，第一個自訂具名模式 `CRAWLERLOGLEVEL` 即為相符。第二個自訂模式 `MESSAGEPREFIX` 嘗試符合訊息字首字串。

AWS Glue 追蹤建立時間、上次更新時間和您的分類器版本。

### 內建模式
<a name="classifier-builtin-patterns"></a>

AWS Glue 提供許多常見的模式，您可用來建立自訂分類器。您將一個具名模式新增到分類器定義中的 `grok pattern`。

以下清單包含各個模式的一行。在每一行中，模式名稱之後是它的定義。[規則表達式 (regex)](http://en.wikipedia.org/wiki/Regular_expression) 語法可用來定義模式。

```
#<noloc>&GLU;</noloc> Built-in patterns
 USERNAME [a-zA-Z0-9._-]+
 USER %{USERNAME:UNWANTED}
 INT (?:[+-]?(?:[0-9]+))
 BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+)))
 NUMBER (?:%{BASE10NUM:UNWANTED})
 BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))
 BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b
 BOOLEAN (?i)(true|false)
 
 POSINT \b(?:[1-9][0-9]*)\b
 NONNEGINT \b(?:[0-9]+)\b
 WORD \b\w+\b
 NOTSPACE \S+
 SPACE \s*
 DATA .*?
 GREEDYDATA .*
 #QUOTEDSTRING (?:(?<!\\)(?:"(?:\\.|[^\\"])*"|(?:'(?:\\.|[^\\'])*')|(?:`(?:\\.|[^\\`])*`)))
 QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))
 UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}
 
 # Networking
 MAC (?:%{CISCOMAC:UNWANTED}|%{WINDOWSMAC:UNWANTED}|%{COMMONMAC:UNWANTED})
 CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})
 WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})
 COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})
 IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?
 IPV4 (?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])
 IP (?:%{IPV6:UNWANTED}|%{IPV4:UNWANTED})
 HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-_]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-_]{0,62}))*(\.?|\b)
 HOST %{HOSTNAME:UNWANTED}
 IPORHOST (?:%{HOSTNAME:UNWANTED}|%{IP:UNWANTED})
 HOSTPORT (?:%{IPORHOST}:%{POSINT:PORT})
 
 # paths
 PATH (?:%{UNIXPATH}|%{WINPATH})
 UNIXPATH (?>/(?>[\w_%!$@:.,~-]+|\\.)*)+
 #UNIXPATH (?<![\w\/])(?:/[^\/\s?*]*)+
 TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+))
 WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+
 URIPROTO [A-Za-z]+(\+[A-Za-z+]+)?
 URIHOST %{IPORHOST}(?::%{POSINT:port})?
 # uripath comes loosely from RFC1738, but mostly from what Firefox
 # doesn't turn into %XX
 URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+
 #URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)?
 URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]*
 URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?
 URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?
 
 # Months: January, Feb, 3, 03, 12, December
 MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b
 MONTHNUM (?:0?[1-9]|1[0-2])
 MONTHNUM2 (?:0[1-9]|1[0-2])
 MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])
 
 # Days: Monday, Tue, Thu, etc...
 DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)
 
 # Years?
 YEAR (?>\d\d){1,2}
 # Time: HH:MM:SS
 #TIME \d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?
 # TIME %{POSINT<24}:%{POSINT<60}(?::%{POSINT<60}(?:\.%{POSINT})?)?
 HOUR (?:2[0123]|[01]?[0-9])
 MINUTE (?:[0-5][0-9])
 # '60' is a leap second in most time standards and thus is valid.
 SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)
 TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9])
 # datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it)
 DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR}
 DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}
 DATESTAMP_US %{DATE_US}[- ]%{TIME}
 DATESTAMP_EU %{DATE_EU}[- ]%{TIME}
 ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE}))
 ISO8601_SECOND (?:%{SECOND}|60)
 TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
 TZ (?:[PMCE][SD]T|UTC)
 DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ}
 DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE}
 DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR}
 DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND}
 CISCOTIMESTAMP %{MONTH} %{MONTHDAY} %{TIME}
 
 # Syslog Dates: Month Day HH:MM:SS
 SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
 PROG (?:[\w._/%-]+)
 SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])?
 SYSLOGHOST %{IPORHOST}
 SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}>
 HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT}
 
 # Shortcuts
 QS %{QUOTEDSTRING:UNWANTED}
 
 # Log formats
 SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}:
 
 MESSAGESLOG %{SYSLOGBASE} %{DATA}
 
 COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{Bytes:bytes=%{NUMBER}|-})
 COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent}
 COMMONAPACHELOG_DATATYPED %{IPORHOST:clientip} %{USER:ident;boolean} %{USER:auth} \[%{HTTPDATE:timestamp;date;dd/MMM/yyyy:HH:mm:ss Z}\] "(?:%{WORD:verb;string} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion;float})?|%{DATA:rawrequest})" %{NUMBER:response;int} (?:%{NUMBER:bytes;long}|-)
 
 
 # Log Levels
 LOGLEVEL ([A|a]lert|ALERT|[T|t]race|TRACE|[D|d]ebug|DEBUG|[N|n]otice|NOTICE|[I|i]nfo|INFO|[W|w]arn?(?:ing)?|WARN?(?:ING)?|[E|e]rr?(?:or)?|ERR?(?:OR)?|[C|c]rit?(?:ical)?|CRIT?(?:ICAL)?|[F|f]atal|FATAL|[S|s]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)
```

## 撰寫 XML 自訂分類器
<a name="custom-classifier-xml"></a>

XML 會利用檔案中的標籤來定義文件的結構。使用 XML 自訂分類器，您可以指定用來定義一個列的標籤名稱。

### XML 分類器的自訂分類器值
<a name="classifier-values-xml"></a>

當您定義 XML 分類器時，您將以下值提供至 AWS Glue 以建立分類器。此分類器的分類欄位設定為 `xml`。

**名稱**  
分類器名稱。

**Row 標籤**  
在 XML 文件中用於定義資料表列的 XML 標籤名稱，不含角括號 `< >`。此名稱必須符合 XML 的標籤規則。  
包含列資料的元素**不得**為自我封閉的空元素。舉例而言，** **不會AWS Glue剖析此空元素：  

```
            <row att1=”xx” att2=”yy” />  
```
 空元素可撰寫如下：  

```
            <row att1=”xx” att2=”yy”> </row> 
```

AWS Glue 追蹤建立時間、上次更新時間和您的分類器版本。

例如，假設您擁有以下 XML 檔案。若要建立僅含有作者和標題的 AWS Glue 資料表，請在 AWS Glue 主控台中以 **Row 標籤**做為 `AnyCompany` 來建立分類器。接著，新增並執行採用此自訂分類器的爬蟲程式即可。

```
<?xml version="1.0"?>
<catalog>
   <book id="bk101">
     <AnyCompany>
       <author>Rivera, Martha</author>
       <title>AnyCompany Developer Guide</title>
     </AnyCompany>
   </book>
   <book id="bk102">
     <AnyCompany>   
       <author>Stiles, John</author>
       <title>Style Guide for AnyCompany</title>
     </AnyCompany>
   </book>
</catalog>
```

## 撰寫 JSON 自訂分類器
<a name="custom-classifier-json"></a>

JSON 是資料交換格式。它定義資料結構與名稱值組或值的排序清單。使用 JSON 自訂分類器時，您可以指定資料結構的 JSON 路徑，以用於定義資料表的結構描述。

### AWS Glue 中的自訂分類器值
<a name="classifier-values-json"></a>

當您定義 JSON 分類器時，您將以下值提供至 AWS Glue 以建立分類器。此分類器的分類欄位設定為 `json`。

**名稱**  
分類器名稱。

**JSON 路徑**  
JSON 路徑會指向用來定義資料表結構描述的物件。您可以用點標記法或括號標記法來撰寫 JSON 路徑。以下是支援的運算子：      
[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_tw/glue/latest/dg/custom-classifier.html)

AWS Glue 追蹤建立時間、上次更新時間和您的分類器版本。

**Example 使用 JSON 分類器從陣列中提取記錄**  
此處會假設您的 JSON 資料是一系列的記錄。舉例來說，檔案的前面幾行可能如下所示：  

```
[
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:ak",
    "name": "Alaska"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:1",
    "name": "Alabama's 1st congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:2",
    "name": "Alabama's 2nd congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:3",
    "name": "Alabama's 3rd congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:4",
    "name": "Alabama's 4th congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:5",
    "name": "Alabama's 5th congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:6",
    "name": "Alabama's 6th congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:al\/cd:7",
    "name": "Alabama's 7th congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:ar\/cd:1",
    "name": "Arkansas's 1st congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:ar\/cd:2",
    "name": "Arkansas's 2nd congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:ar\/cd:3",
    "name": "Arkansas's 3rd congressional district"
  },
  {
    "type": "constituency",
    "id": "ocd-division\/country:us\/state:ar\/cd:4",
    "name": "Arkansas's 4th congressional district"
  }
]
```
透過內建 JSON 分類器執行爬蟲程式時，即可將整個檔案用來定義結構描述。因為您尚未 JSON 路徑，該爬蟲程式會將資料視為一個物件，亦即只是一個陣列。例如，結構描述看起來類似如下：  

```
root
|-- record: array
```
然而，若要在 JSON 陣列中根據每個記錄建立結構描述，請建立自訂 JSON 分類器並指定 JSON 路徑為 `$[*]`。當您指定此 JSON 路徑時，分類器會詢問陣列中的 12 筆記錄以判斷結構描述。產生的結構描述將包含各個物件的獨立欄位，如以下範例所示：  

```
root
|-- type: string
|-- id: string
|-- name: string
```

**Example 使用 JSON 分類器僅檢查檔案的部分**  
此處假設 JSON 資料會遵循範例 JSON 檔案 `s3://awsglue-datasets/examples/us-legislators/all/areas.json` 的模式，該檔案取自 [http://everypolitician.org/](http://everypolitician.org/)。JSON 檔案中的範例物件看起來會像下述內容：  

```
{
  "type": "constituency",
  "id": "ocd-division\/country:us\/state:ak",
  "name": "Alaska"
}
{
  "type": "constituency",
  "identifiers": [
    {
      "scheme": "dmoz",
      "identifier": "Regional\/North_America\/United_States\/Alaska\/"
    },
    {
      "scheme": "freebase",
      "identifier": "\/m\/0hjy"
    },
    {
      "scheme": "fips",
      "identifier": "US02"
    },
    {
      "scheme": "quora",
      "identifier": "Alaska-state"
    },
    {
      "scheme": "britannica",
      "identifier": "place\/Alaska"
    },
    {
      "scheme": "wikidata",
      "identifier": "Q797"
    }
  ],
  "other_names": [
    {
      "lang": "en",
      "note": "multilingual",
      "name": "Alaska"
    },
    {
      "lang": "fr",
      "note": "multilingual",
      "name": "Alaska"
    },
    {
      "lang": "nov",
      "note": "multilingual",
      "name": "Alaska"
    }
  ],
  "id": "ocd-division\/country:us\/state:ak",
  "name": "Alaska"
}
```
透過內建 JSON 分類器執行爬蟲程式時，即可將整個檔案用來建立結構描述。您得到的結構描述可能類似：  

```
root
|-- type: string
|-- id: string
|-- name: string
|-- identifiers: array
|    |-- element: struct
|    |    |-- scheme: string
|    |    |-- identifier: string
|-- other_names: array
|    |-- element: struct
|    |    |-- lang: string
|    |    |-- note: string
|    |    |-- name: string
```
不過，您必須建立自訂 JSON 分類器並將 JSON 路徑指定為 `id`，才能僅使用「`$.id`」物件建立結構描述。如此一來，系統僅會依據「`id`」欄位來產生結構描述：  

```
root
|-- record: string
```
使用此結構描述所擷取的前幾行資料如下所示：  

```
{"record": "ocd-division/country:us/state:ak"}
{"record": "ocd-division/country:us/state:al/cd:1"}
{"record": "ocd-division/country:us/state:al/cd:2"}
{"record": "ocd-division/country:us/state:al/cd:3"}
{"record": "ocd-division/country:us/state:al/cd:4"}
{"record": "ocd-division/country:us/state:al/cd:5"}
{"record": "ocd-division/country:us/state:al/cd:6"}
{"record": "ocd-division/country:us/state:al/cd:7"}
{"record": "ocd-division/country:us/state:ar/cd:1"}
{"record": "ocd-division/country:us/state:ar/cd:2"}
{"record": "ocd-division/country:us/state:ar/cd:3"}
{"record": "ocd-division/country:us/state:ar/cd:4"}
{"record": "ocd-division/country:us/state:as"}
{"record": "ocd-division/country:us/state:az/cd:1"}
{"record": "ocd-division/country:us/state:az/cd:2"}
{"record": "ocd-division/country:us/state:az/cd:3"}
{"record": "ocd-division/country:us/state:az/cd:4"}
{"record": "ocd-division/country:us/state:az/cd:5"}
{"record": "ocd-division/country:us/state:az/cd:6"}
{"record": "ocd-division/country:us/state:az/cd:7"}
```
若要根據 JSON 檔案中的深度巢狀物件 (例如「`identifier`」) 來建立結構描述，則可建立自訂 JSON 分類器並將 JSON 路徑指定為 `$.identifiers[*].identifier`。儘管產生的結構描述與先前範例類似，但它是依據 JSON 檔案中不同的物件建立而成。  
結構描述看起來類似如下：  

```
root
|-- record: string
```
若列出資料表的前面幾行，即會顯示以「`identifier`」物件中資料為基礎的結構描述：  

```
{"record": "Regional/North_America/United_States/Alaska/"}
{"record": "/m/0hjy"}
{"record": "US02"}
{"record": "5879092"}
{"record": "4001016-8"}
{"record": "destination/alaska"}
{"record": "1116270"}
{"record": "139487266"}
{"record": "n79018447"}
{"record": "01490999-8dec-4129-8254-eef6e80fadc3"}
{"record": "Alaska-state"}
{"record": "place/Alaska"}
{"record": "Q797"}
{"record": "Regional/North_America/United_States/Alabama/"}
{"record": "/m/0gyh"}
{"record": "US01"}
{"record": "4829764"}
{"record": "4084839-5"}
{"record": "161950"}
{"record": "131885589"}
```
您可以建立自訂 JSON 分類器並將 JSON 路徑指定為 `$.other_names[*].name`，藉此根據 JSON 檔案中其他深度巢狀物件 (例如「`other_names`」陣列中的「`name`」欄位) 來建立資料表。儘管產生的結構描述與先前範例類似，但它是依據 JSON 檔案中不同的物件建立而成。結構描述看起來類似如下：  

```
root
|-- record: string
```
若列出資料表的前面幾行，即會顯示以「`name`」陣列中「`other_names`」物件資料為基礎的結構描述：  

```
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "Аляска"}
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "ألاسكا"}
{"record": "ܐܠܐܣܟܐ"}
{"record": "الاسكا"}
{"record": "Alaska"}
{"record": "Alyaska"}
{"record": "Alaska"}
{"record": "Alaska"}
{"record": "Штат Аляска"}
{"record": "Аляска"}
{"record": "Alaska"}
{"record": "আলাস্কা"}
```

## 撰寫 CSV 自訂分類器
<a name="custom-classifier-csv"></a>

 自訂 CSV 分類器可讓您在自訂 csv 分類器欄位中為每一欄指定資料類型。您可以指定每欄的資料類型，用逗號分隔。透過指定資料類型，您可以覆寫爬蟲程式推斷的資料類型，並確保資料將適當地分類。

您可以在該分類器中設定用於處理 CSV 的 SerDe，並且將在資料目錄中套用該 SerDe。

當您建立自訂分類器時，您也可以針對不同的爬蟲程式重複使用分類器。
+  對於只有標題 (沒有資料) 的 csv 檔案，這些檔案將被分類為 UNKNOWN，因為沒有提供足夠的資訊。如果您在 *Column headings* (欄位標題) 中指定 CSV「具有標題」，並提供資料類型，我們可以正確地對這些檔案進行分類。

您可以使用自訂 CSV 分類器來推論各種 CSV 資料類型的結構描述。您可以為分類器提供的自訂屬性包含分隔符號、CSV SerDe 選項、標頭相關選項，以及是否要對資料執行特定驗證。

### AWS Glue 中的自訂分類器值
<a name="classifier-values-csv"></a>

當定義 CSV 分類器時，您要將下列值提供至 AWS Glue 以便建立分類器。此分類器的分類欄位設定為 `csv`。

**分類器名稱**  
分類器名稱。

**CSV SerDe**  
設定用於在分類器中處理 CSV 的 SerDe，並且將在資料目錄中套用該 Serde。選項有「開放式 CSV SerDe」、「延遲簡易 SerDe」和「無」。當您希望爬蟲程式執行偵測時，您可以指定「無」值。

**欄位分隔符號**  
表示用於分隔資料列中每個欄位項目的自訂符號。提供 Unicode 字元。如果無法輸入分隔符號，您可以複製並貼上它。這個方式適用於可列印字元，包括系統不支援的字元 (通常顯示為 □)。

**引號符號**  
用來表示將內容結合成單一欄位值的自訂符號。必須不同於欄位分隔符號。提供 Unicode 字元。如果無法輸入分隔符號，您可以複製並貼上它。這個方式適用於可列印字元，包括系統不支援的字元 (通常顯示為 □)。

**欄位標題**  
指示在 CSV 檔案中應如何偵測出欄位標題的行為。如果您的自訂 CSV 檔案包含欄位標題，請輸入以逗號分隔的欄位標題清單。

**處理選項：允許檔案包含單一欄位**  
啟用處理僅包含一個欄位的檔案。

**處理選項：裁剪空格後再識別欄位值**  
指定在確認欄位值類型之前是否要裁剪值。

**自訂資料類型 - *選用***  
 輸入以逗號分隔的自訂資料類型。指定 CSV 檔案中的自訂資料類型。自訂資料類型必須是受支援的資料類型。支援的資料類型為："BINARY"、"BOOLEAN"、"DATE"、"DECIMAL"、"DOUBLE"、"FLOAT"、"INT"、"LONG"、"SHORT"、"STRING"、"TIMESTAMP"。不受支援的資料類型會顯示錯誤。