

# 为不同的数据格式编写自定义分类器
<a name="custom-classifier"></a>

您可以提供自定义分类器来对 Amazon Glue 中的数据进行分类。您可以使用 grok 模式、XML 标签、JavaScript 对象表示法 (JSON) 或逗号分隔值 (CSV) 来创建自定义分类器。Amazon Glue 爬网程序调用自定义分类器。如果分类器可识别数据，则它会将数据的分类和架构返回到爬网程序。如果数据与任何内置分类器不匹配，或者您希望自定义由爬网程序创建的表，则可能需要定义自定义分类器。

 有关使用 Amazon Glue 控制台创建分类器的更多信息，请参阅[使用 Amazon Glue 控制台创建分类器](console-classifiers.md)。

Amazon Glue 按照您指定的顺序在内置分类器之前运行自定义分类器。当爬网程序找到与数据匹配的分类器时，分类字符串和架构将在写入 Amazon 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)，用于一次匹配一行数据。Amazon Glue 使用 grok 模式来推断数据的架构。当 grok 模式与您的数据匹配时，Amazon Glue 使用该模式来确定数据的结构并将其映射到字段。

Amazon Glue 提供许多内置模式，或者您也可以定义自己的模式。您可以使用自定义分类器定义中的内置模式和自定义模式来创建 grok 模式。您可以定制 grok 模式来对自定义文本文件格式进行分类。

**注意**  
Amazon Glue grok 自定义分类器对在 Amazon Glue Data Catalog 中创建的表使用 `GrokSerDe` 序列化库。如果您要将 Amazon Glue Data Catalog 与 Amazon Athena、Amazon EMR 或 Redshift Spectrum 结合使用，请参阅有关这些服务的文档以了解有关 `GrokSerDe` 支持的信息。目前，在从 Amazon EMR 和 Redshift Spectrum 查询使用 `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 模式**  
应用于数据存储以确定是否存在匹配的模式集。这些模式来自 Amazon 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` 尝试匹配消息前缀字符串。

Amazon Glue 跟踪分类器的创建时间、上次更新时间和版本。

### 内置模式
<a name="classifier-builtin-patterns"></a>

Amazon 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 分类器时，可以向 Amazon Glue 提供以下值以创建分类器。此分类器的分类字段设置为 `xml`。

**名称**  
分类器的名称。

**行标签**  
在 XML 文档中定义表行的 XML 标记名称，不带尖括号 `< >`.. 名称必须符合标签的 XML 规则。  
包含行数据的元素**不能**是自结束的空元素。例如，** **不Amazon Glue解析此空元素：  

```
            <row att1=”xx” att2=”yy” />  
```
 可以如下所示编写空元素：  

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

Amazon Glue 跟踪分类器的创建时间、上次更新时间和版本。

例如，假设您具有以下 XML 文件。要创建仅包含作者和标题列的 Amazon Glue 表，请在 Amazon Glue 控制台中创建 **Row tag (行标签)** 为 `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 路径。

### Amazon Glue 中的自定义分类器值
<a name="classifier-values-json"></a>

定义 JSON 分类器时，可以向 Amazon Glue 提供以下值以创建分类器。此分类器的分类字段设置为 `json`。

**名称**  
分类器的名称。

**JSON 路径**  
一个 JSON 路径，指向用于定义表架构的对象。JSON 路径可以用点表示法或括号表示法编写。支持以下运算符：      
[\[See the AWS documentation website for more details\]](http://docs.amazonaws.cn/glue/latest/dg/custom-classifier.html)

Amazon 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 数据遵循来自 [http://everypolitician.org/](http://everypolitician.org/) 的示例 JSON 文件 `s3://awsglue-datasets/examples/us-legislators/all/areas.json` 的模式。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
```
但是，要仅使用“`id`”对象创建架构，请创建自定义 JSON 分类器，并将 JSON 路径指定为 `$.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 文件中基于另一个深层嵌套对象（如“`name`”数组中的“`other_names`”字段）创建表，可以创建自定义 JSON 分类器，并将 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，该分类器将应用于 Data Catalog。

创建自定义分类器时，您也可以将该分类器重复用于不同的爬网程序。
+  对于只有标题（无数据）的 CSV 文件，由于提供的信息不足，这些文件将被归类为 UNKNOWN。如果您在*列标题*选项中指定 CSV“有标题”，并提供数据类型，我们可以正确地对这些文件进行分类。

您可以使用自定义 CSV 分类器来推断各种类型的 CSV 数据的架构。您可以为分类器提供的自定义属性包括分隔符、CSV SerDe 选项、有关标题的选项以及是否对数据执行某些验证。

### Amazon Glue 中的自定义分类器值
<a name="classifier-values-csv"></a>

定义 CSV 分类器时，可以向 Amazon Glue 提供以下值以创建分类器。此分类器的分类字段设置为 `csv`。

**分类器名称**  
分类器的名称。

**CSV Serde**  
设置用于在分类器中处理 CSV 的 SerDe，该分类器将应用于 Data Catalog。选项包括“Open CSV SerDe”、“Lazy Simple SerDe”和“无”。当您想让爬网程序执行检测时，可以指定“无”值。

**列分隔符**  
一个自定义符号，表示分隔行中每个列条目的内容。提供一个 Unicode 字符。如果您无法键入分隔符，则可以将其复制并粘贴。这适用于可打印字符，包括您的系统不支持的字符（通常显示为 □）。

**引用符号**  
一个自定义符号，表示将内容组合为单个列值的内容。必须与列分隔符不同。提供一个 Unicode 字符。如果您无法键入分隔符，则可以将其复制并粘贴。这适用于可打印字符，包括您的系统不支持的字符（通常显示为 □）。

**列标题**  
指示有关应如何在 CSV 文件中检测列标题的行为。如果您的自定义 CSV 文件包含列标题，请输入列标题的逗号分隔列表。

**处理选项：允许具有单列的文件**  
允许处理仅包含一列的文件。

**处理选项：在标识列值之前去除空格**  
指定是否在标识列值类型之前去除值。

**自定义数据类型 - *可选***  
 输入用逗号分隔的自定义数据类型。在 CSV 文件中指定自定义数据类型。自定义数据类型必须为受支持的数据类型。受支持的数据类型有：“BINARY”、“BOOLEAN”、“DATE”、“DECIMAL”、“DOUBLE”、“FLOAT”、“INT”、“LONG”、“SHORT”、“STRING”、“TIMESTAMP”。不受支持的数据类型将显示错误。