跳到主要内容
跳到主要内容

从输入数据自动推断模式

ClickHouse可以在几乎所有支持的 输入格式 中自动确定输入数据的结构。本文档将描述何时使用模式推断,它如何与不同的输入格式配合使用,以及可以控制它的哪些设置。

使用方法

当ClickHouse需要以特定的数据格式读取数据而结构未知时,会使用模式推断。

表函数 file, s3, url, hdfs, azureBlobStorage

这些表函数有一个可选参数 structure,用于输入数据的结构。如果未指定此参数或设置为 auto,则将根据数据推断结构。

示例:

假设我们在 user_files 目录中有一个 hobbies.jsonl 文件,格式为 JSONEachRow,内容如下:

ClickHouse可以在您未指定其结构的情况下读取此数据:

注意:格式 JSONEachRow 是通过文件扩展名 .jsonl 自动确定的。

您可以使用 DESCRIBE 查询查看自动确定的结构:

表引擎 File, S3, URL, HDFS, azureBlobStorage

如果在 CREATE TABLE 查询中未指定列的列表,则表的结构将从数据中自动推断。

示例:

让我们使用文件 hobbies.jsonl。我们可以使用文件中的数据创建一个引擎为 File 的表:

clickhouse-local

clickhouse-local 有一个可选参数 -S/--structure,用于输入数据的结构。如果未指定此参数或设置为 auto,则将根据数据推断结构。

示例:

让我们使用文件 hobbies.jsonl。我们可以使用 clickhouse-local 查询该文件中的数据:

使用插入表的结构

当表函数 file/s3/url/hdfs 用于将数据插入表中时,可以选择使用插入表的结构,而不是从数据中提取。这可以提高插入性能,因为模式推断可能需要一些时间。此外,当表具有优化的结构时,它会很有用,因此不会在类型之间执行转换。

有一个特殊的设置 use_structure_from_insertion_table_in_table_functions 控制此行为。它有3种可能的值:

  • 0 - 表函数将从数据中提取结构。
  • 1 - 表函数将使用插入表的结构。
  • 2 - ClickHouse 将自动确定是否可以使用插入表的结构或使用模式推断。默认值。

示例 1:

让我们以以下结构创建表 hobbies1

并从文件 hobbies.jsonl 中插入数据:

在这种情况下,文件中的所有列都将插入到表中而不作更改,因此ClickHouse将使用插入表的结构,而不是模式推断。

示例 2:

让我们以以下结构创建表 hobbies2

并从文件 hobbies.jsonl 中插入数据:

在这种情况下,SELECT 查询中的所有列都存在于表中,因此ClickHouse将使用插入表的结构。注意,它只适用于支持读取子集列的输入格式,如 JSONEachRow、TSKV、Parquet 等(因此它不适用于 TSV 格式)。

示例 3:

让我们以以下结构创建表 hobbies3

并从文件 hobbies.jsonl 中插入数据:

在这种情况下,列 idSELECT 查询中使用,但表中没有此列(它有一个名为 identifier 的列),因此ClickHouse无法使用插入表的结构,将使用模式推断。

示例 4:

让我们以以下结构创建表 hobbies4

并从文件 hobbies.jsonl 中插入数据:

在这种情况下,在 SELECT 查询中对列 hobbies 执行了一些操作以将其插入到表中,因此ClickHouse无法使用插入表的结构,将使用模式推断。

模式推断缓存

对于大多数输入格式,模式推断读取一些数据以确定其结构,而此过程可能需要一些时间。为了防止ClickHouse在每次从同一文件读取数据时推断相同的模式,推断出的模式会被缓存,当再次访问同一文件时,ClickHouse将使用缓存中的模式。

有一些特殊设置控制此缓存:

  • schema_inference_cache_max_elements_for_{file/s3/hdfs/url/azure} - 对应表函数的最大缓存模式数。默认值为 4096。这些设置应在服务器配置中进行设置。
  • schema_inference_use_cache_for_{file,s3,hdfs,url,azure} - 允许开启/关闭用于模式推断的缓存。这些设置可以在查询中使用。

文件的模式可以通过修改数据或更改格式设置来更改。因此,模式推断缓存是通过文件来源、格式名称、所用格式设置和文件的最后修改时间来识别模式的。

注意:某些通过URL在 url 表函数中访问的文件可能不包含有关最后修改时间的信息;在这种情况下,有一个特殊设置 schema_inference_cache_require_modification_time_for_url。禁用此设置允许在没有最后修改时间的情况下使用缓存中的模式。

还有一个系统表 schema_inference_cache,其中包含所有当前缓存的模式,并且系统查询 SYSTEM DROP SCHEMA CACHE [FOR File/S3/URL/HDFS] 允许清除所有源或特定源的模式缓存。

示例:

让我们尝试从s3中的示例数据集 github-2022.ndjson.gz 推断结构,并查看模式推断缓存是如何工作的:

如您所见,第二个查询几乎瞬间成功。

让我们尝试更改一些可能影响推断模式的设置:

如您所见,对于同一文件,未使用缓存中的模式,因为改变了可能影响推断模式的设置。

让我们检查一下 system.schema_inference_cache 表的内容:

如您所见,对于同一文件有两种不同的模式。

我们可以使用系统查询清除模式缓存:

文本格式

对于文本格式,ClickHouse逐行读取数据,根据格式提取列值,然后使用一些递归解析器和启发式方法来确定每个值的类型。在模式推断时,从数据中读取的最大行数和字节数由设置 input_format_max_rows_to_read_for_schema_inference(默认25000)和 input_format_max_bytes_to_read_for_schema_inference(默认32Mb)控制。默认情况下,所有推断的类型都是 Nullable,但您可以通过设置 schema_inference_make_columns_nullable 来更改此设置(请参见 设置 部分的示例)。

JSON 格式

在JSON格式中,ClickHouse 根据JSON规范解析值,然后尝试为其找到最合适的数据类型。

让我们看看它是如何工作的,可以推断出哪些类型以及可以在JSON格式中使用哪些特定设置。

示例

在这里及后面的示例中,将使用 format 表函数。

整数、浮点、布尔值、字符串:

日期、日期时间:

数组:

如果数组包含 null,ClickHouse 会使用其他数组元素的类型:

具名元组:

启用设置 input_format_json_try_infer_named_tuples_from_objects 后,在模式推断过程中,ClickHouse 将尝试从JSON对象中推断具名元组。结果的具名元组将包含来自示例数据的所有相应JSON对象的所有元素。

无名元组:

在JSON格式中,我们将具有不同类型元素的数组视为无名元组。

如果某些值为 null 或为空,我们会使用其他行对应值的类型:

映射:

在JSON中,我们可以读取具有相同类型值的对象作为Map类型。 注意:只有在禁用设置 input_format_json_read_objects_as_stringsinput_format_json_try_infer_named_tuples_from_objects 时此设置才会生效。

JSON对象类型(如果启用设置 allow_experimental_object_type):

嵌套复杂类型:

如果ClickHouse无法确定某些键的类型,因为数据仅包含null/空对象/空数组,如果启用设置 input_format_json_infer_incomplete_types_as_strings,将使用类型 String,否则将抛出异常:

JSON设置

input_format_json_try_infer_numbers_from_strings

启用此设置可允许从字符串值中推断数字。

此设置默认禁用。

示例:

input_format_json_try_infer_named_tuples_from_objects

启用此设置可允许从JSON对象中推断具名元组。结果的具名元组将包含来自示例数据的所有相应JSON对象的所有元素。 当JSON数据不稀疏时,这可能会很有用,因为数据样本将包含所有可能的对象键。

此设置默认启用。

示例

结果:

结果:

input_format_json_use_string_type_for_ambiguous_paths_in_named_tuples_inference_from_objects

启用此设置可允许在从JSON对象推断具名元组(当启用 input_format_json_try_infer_named_tuples_from_objects 时)时,对模糊路径使用字符串类型,而不是抛出异常。 它允许将JSON对象读取为具名元组,即使存在模糊路径。

默认禁用。

示例

禁用设置:

结果:

启用设置:

结果:

input_format_json_read_objects_as_strings

启用此设置可允许将嵌套JSON对象作为字符串读取。 此设置可用于在不使用JSON对象类型的情况下读取嵌套JSON对象。

此设置默认启用。

注意:启用此设置仅在禁用设置 input_format_json_try_infer_named_tuples_from_objects 时生效。

input_format_json_read_numbers_as_strings

启用此设置可允许将数值作为字符串读取。

此设置默认启用。

示例

input_format_json_read_bools_as_numbers

启用此设置可允许将布尔值作为数字读取。

此设置默认启用。

示例:

input_format_json_read_bools_as_strings

启用此设置可允许将布尔值作为字符串读取。

此设置默认启用。

示例:

input_format_json_read_arrays_as_strings

启用此设置可允许将JSON数组值作为字符串读取。

此设置默认启用。

示例

input_format_json_infer_incomplete_types_as_strings

启用此设置可允许在模式推断期间使用字符串类型,用于数据样本中仅包含 Null/{}/[] 的JSON键。 在JSON格式中,如果启用(默认启用),任何值都可以读取为字符串,并且我们可以通过使用未知类型的键的字符串类型避免错误,例如“无法确定列 'column_name' 的类型,因为前25000行数据大多包含空值或空数组/映射”的错误。

示例:

结果:

CSV

在CSV格式中,ClickHouse根据分隔符从行中提取列值。ClickHouse期望除数字和字符串之外的所有类型都用双引号括起来。如果值在双引号中,ClickHouse尝试使用递归解析器解析引号内的数据,然后尝试为其找到最合适的数据类型。如果值不在双引号中,ClickHouse尝试将其解析为数字,如果值不是数字,ClickHouse将其视为字符串。

如果您不希望ClickHouse尝试使用一些解析器和启发式方法来确定复杂类型,可以禁用设置 input_format_csv_use_best_effort_in_schema_inference,ClickHouse将把所有列视为字符串。

如果启用设置 input_format_csv_detect_header,ClickHouse将在推断模式时尝试检测带有列名(可能还有类型)的头部。此设置默认启用。

示例:

整数、浮点、布尔值、字符串:

没有引号的字符串:

日期、日期时间:

数组:

如果数组包含null,ClickHouse将使用其他数组元素的类型:

映射:

嵌套数组和映射:

如果ClickHouse无法确定引号内的类型,因为数据仅包含空值,ClickHouse将其视为字符串:

禁用设置 input_format_csv_use_best_effort_in_schema_inference 的示例:

标题自动检测示例(当启用 input_format_csv_detect_header 时):

仅名称:

名称和类型:

请注意,标题仅在至少有一列具有非字符串类型的情况下才能检测到。如果所有列都是字符串类型,则不会检测到标题:

CSV设置

input_format_csv_try_infer_numbers_from_strings

启用此设置可允许从字符串值中推断数字。

此设置默认禁用。

示例:

TSV/TSKV

在TSV/TSKV格式中,ClickHouse根据表格分隔符从行中提取列值,然后使用递归解析器解析提取的值,以确定最合适的类型。如果无法确定类型,ClickHouse将此值视为字符串。

如果您不希望ClickHouse尝试使用一些解析器和启发式方法来确定复杂类型,可以禁用设置 input_format_tsv_use_best_effort_in_schema_inference,ClickHouse将把所有列视为字符串。

如果启用设置 input_format_tsv_detect_header,ClickHouse将在推断模式时尝试检测带有列名(可能还有类型)的头部。此设置默认启用。

示例:

整数、浮点、布尔值、字符串:

日期、日期时间:

数组:

如果数组包含null,ClickHouse将使用其他数组元素的类型:

元组:

映射:

嵌套数组、元组和映射:

如果ClickHouse无法确定类型,因为数据仅包含空值,ClickHouse将其视为字符串:

禁用设置 input_format_tsv_use_best_effort_in_schema_inference 的示例:

标题自动检测示例(当启用 input_format_tsv_detect_header 时):

仅名称:

名称和类型:

请注意,标题仅在至少有一列具有非字符串类型的情况下才能检测到。如果所有列都是字符串类型,则不会检测到标题:

在Values格式中,ClickHouse从行中提取列值,然后使用递归解析器进行解析,类似于字面值的解析。

示例:

整数、浮点、布尔值、字符串:

日期、日期时间:

数组:

如果数组包含null,ClickHouse将使用其他数组元素的类型:

元组:

映射:

嵌套数组、元组和映射:

如果ClickHouse无法确定类型,因为数据仅包含空值,将抛出异常:

禁用设置 input_format_tsv_use_best_effort_in_schema_inference 的示例:

自描述格式

自描述格式在数据本身中包含有关数据结构的信息,可以是带有描述的某个头部、二进制类型树或某种表。为了自动从这种格式的文件中推断模式,ClickHouse读取包含类型信息的数据部分并将其转换为ClickHouse表的模式。

带有 -WithNamesAndTypes 后缀的格式

ClickHouse支持一些带有后缀 -WithNamesAndTypes 的文本格式。此后缀表示数据在实际数据之前包含两行列名和类型。在此类格式的模式推断中,ClickHouse读取前两行,并提取列名和类型。

示例

带有元数据的JSON格式

某些JSON输入格式(JSON, JSONCompact, JSONColumnsWithMetadata)包含带有列名和类型的元数据。 在此类格式的模式推断中,ClickHouse会读取这些元数据。

示例

Avro

在Avro格式中,ClickHouse从数据中读取其模式,并使用以下类型匹配将其转换为ClickHouse模式:

Avro数据类型ClickHouse数据类型
booleanBool
intInt32
int (date) *Date32
longInt64
floatFloat32
doubleFloat64
bytes, stringString
fixedFixedString(N)
enumEnum
array(T)Array(T)
union(null, T), union(T, null)Nullable(T)
nullNullable(Nothing)
string (uuid) *UUID
binary (decimal) *Decimal(P, S)

* Avro逻辑类型

其他Avro类型不支持。

Parquet

在 Parquet 格式中,ClickHouse 从数据中读取其模式并使用以下类型匹配将其转换为 ClickHouse 模式:

Parquet 数据类型ClickHouse 数据类型
BOOLBool
UINT8UInt8
INT8Int8
UINT16UInt16
INT16Int16
UINT32UInt32
INT32Int32
UINT64UInt64
INT64Int64
FLOATFloat32
DOUBLEFloat64
DATEDate32
TIME (ms)DateTime
TIMESTAMP, TIME (us, ns)DateTime64
STRING, BINARYString
DECIMALDecimal
LISTArray
STRUCTTuple
MAPMap

其他 Parquet 类型不被支持。默认情况下,所有推断的类型都是 Nullable,但可以通过设置 schema_inference_make_columns_nullable 进行更改。

Arrow

在 Arrow 格式中,ClickHouse 从数据中读取其模式并使用以下类型匹配将其转换为 ClickHouse 模式:

Arrow 数据类型ClickHouse 数据类型
BOOLBool
UINT8UInt8
INT8Int8
UINT16UInt16
INT16Int16
UINT32UInt32
INT32Int32
UINT64UInt64
INT64Int64
FLOAT, HALF_FLOATFloat32
DOUBLEFloat64
DATE32Date32
DATE64DateTime
TIMESTAMP, TIME32, TIME64DateTime64
STRING, BINARYString
DECIMAL128, DECIMAL256Decimal
LISTArray
STRUCTTuple
MAPMap

其他 Arrow 类型不被支持。默认情况下,所有推断的类型都是 Nullable,但可以通过设置 schema_inference_make_columns_nullable 进行更改。

ORC

在 ORC 格式中,ClickHouse 从数据中读取其模式并使用以下类型匹配将其转换为 ClickHouse 模式:

ORC 数据类型ClickHouse 数据类型
BooleanBool
TinyintInt8
SmallintInt16
IntInt32
BigintInt64
FloatFloat32
DoubleFloat64
DateDate32
TimestampDateTime64
String, Char, Varchar,BINARYString
DecimalDecimal
ListArray
StructTuple
MapMap

其他 ORC 类型不被支持。默认情况下,所有推断的类型都是 Nullable,但可以通过设置 schema_inference_make_columns_nullable 进行更改。

Native

Native 格式在 ClickHouse 内部使用,并在数据中包含模式。 在模式推断中,ClickHouse 从数据中读取模式而不进行任何转换。

Formats with external schema

这样的格式需要在特定模式语言的单独文件中描述数据的模式。 为了自动推断这些格式文件的模式,ClickHouse 从单独的文件中读取外部模式并将其转换为 ClickHouse 表模式。

Protobuf

在 Protobuf 格式的模式推断中,ClickHouse 使用以下类型匹配:

Protobuf 数据类型ClickHouse 数据类型
boolUInt8
floatFloat32
doubleFloat64
int32, sint32, sfixed32Int32
int64, sint64, sfixed64Int64
uint32, fixed32UInt32
uint64, fixed64UInt64
string, bytesString
enumEnum
repeated TArray(T)
message, groupTuple

CapnProto

在 CapnProto 格式的模式推断中,ClickHouse 使用以下类型匹配:

CapnProto 数据类型ClickHouse 数据类型
BoolUInt8
Int8Int8
UInt8UInt8
Int16Int16
UInt16UInt16
Int32Int32
UInt32UInt32
Int64Int64
UInt64UInt64
Float32Float32
Float64Float64
Text, DataString
enumEnum
ListArray
structTuple
union(T, Void), union(Void, T)Nullable(T)

Strong-typed binary formats

在这样的格式中,每个序列化值包含有关其类型(可能还有名称)的信息,但没有关于整个表的信息。 在这些格式的模式推断中,ClickHouse 按行读取数据(最多读取 input_format_max_rows_to_read_for_schema_inference 行或 input_format_max_bytes_to_read_for_schema_inference 字节),并从数据中提取每个值的类型(可能还有名称),然后将这些类型转换为 ClickHouse 类型。

MsgPack

在 MsgPack 格式中,各行之间没有分隔符,要对该格式使用模式推断,您应使用设置 input_format_msgpack_number_of_columns 指定表中的列数。ClickHouse 使用以下类型匹配:

MessagePack 数据类型 (INSERT)ClickHouse 数据类型
int N, uint N, negative fixint, positive fixintInt64
boolUInt8
fixstr, str 8, str 16, str 32, bin 8, bin 16, bin 32String
float 32Float32
float 64Float64
uint 16Date
uint 32DateTime
uint 64DateTime64
fixarray, array 16, array 32Array
fixmap, map 16, map 32Map

默认情况下,所有推断的类型都是 Nullable,但可以通过设置 schema_inference_make_columns_nullable 进行更改。

BSONEachRow

在 BSONEachRow 中,每行数据以 BSON 文档的形式呈现。在模式推断中,ClickHouse 逐一读取 BSON 文档并提取值、名称和数据类型,然后使用以下类型匹配将这些类型转换为 ClickHouse 类型:

BSON 类型ClickHouse 类型
\x08 booleanBool
\x10 int32Int32
\x12 int64Int64
\x01 doubleFloat64
\x09 datetimeDateTime64
\x05 binary with\x00 binary subtype, \x02 string, \x0E symbol, \x0D JavaScript codeString
\x07 ObjectId,FixedString(12)
\x05 binary with \x04 uuid subtype, size = 16UUID
\x04 arrayArray/Tuple (如果嵌套类型不同)
\x03 documentNamed Tuple/Map (带字符串键)

默认情况下,所有推断的类型都是 Nullable,但可以通过设置 schema_inference_make_columns_nullable 进行更改。

Formats with constant schema

这些格式中的数据始终具有相同的模式。

LineAsString

在这种格式中,ClickHouse 将整个行从数据读取到具有 String 数据类型的单个列中。该格式的推断类型始终为 String,列名为 line

示例

JSONAsString

在这种格式中,ClickHouse 将整个 JSON 对象从数据读取到具有 String 数据类型的单个列中。该格式的推断类型始终为 String,列名为 json

示例

JSONAsObject

在这种格式中,ClickHouse 将整个 JSON 对象从数据读取到具有 Object('json') 数据类型的单个列中。该格式的推断类型始终为 String,列名为 json

注意:此格式仅在启用 allow_experimental_object_type 时有效。

示例

Schema inference modes

从数据文件集推断模式可以在两种不同模式下工作:defaultunion。 模式由设置 schema_inference_mode 控制。

Default mode

在默认模式下,ClickHouse 假设所有文件具有相同的模式,并尝试通过逐个读取文件推断模式,直到成功为止。

示例:

假设我们有 3 个文件 data1.jsonldata2.jsonldata3.jsonl,内容如下:

data1.jsonl:

data2.jsonl:

data3.jsonl:

让我们尝试在这 3 个文件上使用模式推断:

结果:

如我们所见,文件 data3.jsonl 中没有 field3。 这是因为 ClickHouse 首先尝试从文件 data1.jsonl 推断模式,但由于 field2 仅为 null 而失败, 然后尝试从 data2.jsonl 推断模式并成功,所以没有读取文件 data3.jsonl 的数据。

Union mode

在联接模式下,ClickHouse 假设文件可以具有不同的模式,因此它推断所有文件的模式,然后将它们联接到公共模式。

假设我们有 3 个文件 data1.jsonldata2.jsonldata3.jsonl,内容如下:

data1.jsonl:

data2.jsonl:

data3.jsonl:

让我们尝试在这 3 个文件上使用模式推断:

结果:

如我们所见,我们有来自所有文件的所有字段。

注意:

  • 由于某些文件可能不包含结果模式中的某些列,因此联接模式仅支持读取列子集的格式(如 JSONEachRow、Parquet、TSVWithNames 等),而不适用于其他格式(如 CSV、TSV、JSONCompactEachRow 等)。
  • 如果 ClickHouse 无法从某个文件推断模式,则将抛出异常。
  • 如果您有很多文件,从所有文件读取模式可能需要很长时间。

Automatic format detection

如果数据格式未指定且无法通过文件扩展名确定,ClickHouse 将尝试通过其内容检测文件格式。

示例:

假设我们有 data,其内容如下:

我们可以在不指定格式或结构的情况下检查和查询此文件:

备注

ClickHouse 只能检测某些格式的子集,这种检测需要一些时间,最好明确指定格式。