为不同的数据格式编写自定义分类器 - AWS Glue

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

为不同的数据格式编写自定义分类器

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

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

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

编写 grok 自定义分类器

Grok 是一个工具,用于分析给定匹配模式的文本数据。grok 模式是一组命名的正则表达式 (regex),用于一次匹配一行数据。AWS Glue 使用 grok 模式来推断数据的架构。当 grok 模式与您的数据匹配时,AWS Glue 使用该模式来确定数据的结构并将其映射到字段。

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

注意

AWS Glue grok 自定义分类器对在 AWS Glue Data Catalog 中创建的表使用 GrokSerDe 序列化库。如果您要将 AWS 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 模式一次只能处理一行。不支持多行模式。此外,不支持模式中的换行符。

grok 分类器的自定义值

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

名称

分类器的名称。

分类

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

Grok 模式

应用于数据存储以确定是否存在匹配的模式集。这些模式来自 AWS 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 尝试匹配消息前缀字符串。

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

内置模式

AWS 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 自定义分类器,您可以指定用于定义行的标签名称。

XML 分类器的自定义分类器值

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

名称

分类器的名称。

行标签

在 XML 文档中定义表行的 XML 标记名称,不带尖括号 < >.. 名称必须符合标签的 XML 规则。

注意

包含行数据的元素不能是自结束的空元素。例如, 不AWS Glue解析此空元素:

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

可以如下所示编写空元素:

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

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

例如,假设您具有以下 XML 文件。要创建仅包含作者和标题列的 AWS Glue 表,请在 AWS 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 路径。

AWS Glue 中的自定义分类器值

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

名称

分类器的名称。

JSON 路径

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

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

AWS 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 的 SerDe,该分类器将应用于 Data Catalog。

创建自定义分类器时,您也可以将该分类器重复用于不同的爬网程序。

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

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

AWS Glue 中的自定义分类器值

定义 CSV 分类器时,可以向 AWS 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”。不受支持的数据类型将显示错误。