编写自定义分类器 - Amazon Glue
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

编写自定义分类器

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

有关使用 Amazon Glue 控制台创建分类器的更多信息,请参阅在 Amazon Glue 控制台上使用分类器

Amazon Glue 按照您指定的顺序在内置分类器之前运行自定义分类器。当爬网程序找到与数据匹配的分类器时,分类字符串和架构将在写入 Amazon Glue Data Catalog的表的定义中使用。

编写 grok 自定义分类器

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。或者,该字段的数据类型可以在生成的架构中强制转换为 bytebooleandoubleshortintlongfloat

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

例如,要将 num 字段强制转换为 int 数据类型,您可以使用此模式:

%{NUMBER:num:int}

模式可以是由其他模式组成。例如,您可以为 SYSLOG 时间戳指定一个模式,该模式由月份、月份中的日期和时间的模式定义(例如,Feb 1 06:25:43)。对于此数据,您可能定义以下模式:

SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
注意

Grok 模式一次只能处理一行。不支持多行模式。此外,不支持模式中的换行符。

Amazon Glue 中的自定义分类器值

定义 grok 分类器时,可以向 Amazon Glue 提供以下值以创建自定义分类器。

名称

分类器的名称。

分类

写入的文本字符串,用于描述分类数据的格式;例如,special-logs

Grok 模式

应用于数据存储以确定是否存在匹配的模式集。这些模式来自 Amazon Glue 内置模式和您定义的任何自定义模式。

以下是 grok 模式的示例:

%{TIMESTAMP_ISO8601:timestamp} \[%{MESSAGEPREFIX:message_prefix}\] %{CRAWLERLOGLEVEL:loglevel} : %{GREEDYDATA:message}

当数据与 TIMESTAMP_ISO8601 匹配时,将会创建架构列 timestamp。此行为与示例中的其他命名模式类似。

自定义模式

您定义的可选自定义模式。这些模式由对您的数据进行分类的 grok 模式引用。您可以在应用于您的数据的 grok 模式中引用这些自定义模式。每个自定义组件模式必须位于不同的行上。正则表达式 (regex) 语法用于定义模式。

下面是如何使用自定义模式的示例:

CRAWLERLOGLEVEL (BENCHMARK|ERROR|WARN|INFO|TRACE) MESSAGEPREFIX .*-.*-.*-.*-.*

第一个自定义命名模式 CRAWLERLOGLEVEL 在数据与其中一个枚举字符串匹配时是匹配项。第二个自定义模式 MESSAGEPREFIX 尝试匹配消息前缀字符串。

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

Amazon Glue 内置模式

Amazon Glue 可提供许多常见模式,您可以用来构建自定义分类器。您将在分类器定义中向 grok pattern 添加命名模式。

以下列表为每个模式包含一行。在每个行中,模式名称遵循其定义。正则表达式 (regex) 语法用于定义模式。

#<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 自定义分类器

XML 使用文件中的标签定义文档的结构。使用 XML 自定义分类器,您可以指定用于定义行的标签名称。

Amazon Glue 中的自定义分类器值

定义 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 自定义分类器

JSON 一种数据交换格式。它使用名称-值对或值的有序列表来定义数据结构。使用 JSON 自定义分类器,您可以指定用于为表定义架构的数据结构的 JSON 路径。

Amazon Glue 中的自定义分类器值

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

名称

分类器的名称。

JSON 路径

一个 JSON 路径,指向用于定义表架构的对象。JSON 路径可以用点表示法或括号表示法编写。支持以下运算符:

操作符 描述
$ JSON 对象的根元素。这将启动所有路径表达式
* 通配符。在 JSON 路径中需要名称或数字的任何地方都可用。
.<name> 点表示的子字段。指定 JSON 对象中的子字段。
['<name>'] 括号表示的子字段。指定 JSON 对象中的子字段。只能指定单个子字段。
[<number>] 数组索引。按索引指定数组的值。

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

例 使用 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
例 使用 JSON 分类器仅检查文件的一部分

假设 JSON 数据遵循来自 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 自定义分类器

自定义 CSV 分类器允许您在自定义 CSV 分类器字段中为每列指定数据类型。您可以指定每列的数据类型,用逗号分隔。通过指定数据类型,您可以覆盖爬网程序推断出的数据类型,并确保对数据进行适当分类。创建自定义分类器时,您也可以将该分类器重复用于不同的爬网程序。

  • 对于只有标题(无数据)的 CSV 文件,由于提供的信息不足,这些文件将被归类为 UNKNOWN。如果您在列标题选项中指定 CSV“有标题”,并提供数据类型,我们可以正确地对这些文件进行分类。

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

Amazon Glue 中的自定义分类器值

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

名称

分类器的名称。

列分隔符

一个自定义符号,表示分隔行中每个列条目的内容。

引用符号

一个自定义符号,表示将内容组合为单个列值的内容。必须与列分隔符不同。

列标题

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

处理选项:允许具有单列的文件

允许处理仅包含一列的文件。

处理选项:在标识列值之前去除空格

指定是否在标识列值类型之前去除值。

自定义数据类型 - 可选

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