ExcelReader

文档中心 › 组件索引 › ExcelReader

ExcelReader Controller Service

类型全限定名:cn.org.acal.lynxus.excel.ExcelReader

所属 Bundle:cn.org.acal.lynxus:lynxus-poi-nar:2.11.8

描述

解析 Microsoft Excel 文档,将每个工作表中的每一行作为单独的记录返回。 该阅读器允许从所有必需的工作表中推断模式或提供用于解释值的显式模式。有关更多文档,请参阅Controller Service的用法。 该阅读器能够处理受密码和非密码保护的现代 XLSX 以及较旧的 XLS Excel 电子表格。

标签

excelspreadsheetxlsxlsxparserecordrowreadervaluescell

属性

下表中,加粗的属性为必填项;其余为可选项。表格同时标注默认值、是否支持表达式语言,以及是否为敏感属性(值会被加密)。

名称默认值可选值描述
Schema Access StrategyUse Starting Row
  • 使用 'Schema Name' 属性 — 要使用的 Schema 名称由 'Schema Name' 属性指定。此属性的值用于在配置的 Schema Registry 服务中查找 Schema。
  • 使用 'Schema Text' 属性 — Schema 本身的文本由 'Schema Text' 属性指定。此属性的值必须是有效的 Avro Schema。如果使用表达式语言,则 'Schema Text' 属性的值在替换表达式后必须有效。
  • Schema 引用读取器 — Schema 引用信息将通过配置的 Schema 引用读取器服务实现提供。
  • 使用起始行 — 配置的 Excel 文件第一行是包含列名的标题行。Schema 将通过使用第一个工作表标题中的列名来推导,根据所选策略,使用后续的 10 行或所有后续行。但是后续工作表的配置标题行将被跳过。注意:如果存在重复的列名,则每个后续重复列名将被赋予一个递增编号。例如,列名 "Name"、"Name" 将更改为 "Name"、"Name_1"。
  • 推断 Schema — 在读取数据时将自动推断数据的 Schema。有关如何推断 Schema 的信息,请参阅组件的使用说明和其他详细信息。
指定如何获取用于解释数据的架构。
Schema Registry控制器服务 API:
SchemaRegistry
cn.org.acal.lynxus-lynxus-standard-services-api-nar-2.11.8
指定用于架构Registry的Controller Service
Schema Name${schema.name}指定要在架构Registry属性中查找的架构名称
支持表达式语言:是(使用 FlowFile 属性与环境/系统变量求值)
Schema Version指定在 Schema Registry 中查找 Schema 的版本。如果未指定,则检索 Schema 的最新版本。
支持表达式语言:是(使用 FlowFile 属性与环境/系统变量求值)
Schema Branch指定在 Schema Registry 属性中查找 Schema 时使用的分支名称。如果选择的 Schema Registry 不支持分支,则此值将被忽略。
支持表达式语言:是(使用 FlowFile 属性与环境/系统变量求值)
Schema Text${avro.schema}Avro 格式的架构文本
支持表达式语言:是(使用 FlowFile 属性与环境/系统变量求值)
Schema Reference Reader控制器服务 API:
SchemaReferenceReader
cn.org.acal.lynxus-lynxus-standard-services-api-nar-2.11.8
服务实现负责读取 FlowFile 属性或内容以确定架构参考标识符
Input File TypeXLSX
  • XLS — XLS 1997-2007 文件格式
  • XLSX — XLSX 2007 至今的 OOXML 文件格式
指定 Excel 输入文件的类型。
Protection TypeUNPROTECTED
  • Unprotected — 未受密码保护的 Excel 电子表格
  • Password Protected — 受密码保护的 Excel 电子表格
指定 Excel 电子表格是否受密码保护。
Password受密码保护的 Excel 电子表格的密码
敏感属性:是
起始行1开始处理的第一行的行号(基于 1)。用于跳过工作表顶部不属于数据集的行。使用 'Use Starting Row' 策略时,此处应为列标题行。
支持表达式语言:是(使用 FlowFile 属性与环境/系统变量求值)
Row Evaluation StrategySTANDARD
  • Standard — Use 10 rows after the starting row.
  • All Rows — 使用起始行之后的所有行。
选择起始行之后有多少行用于确定架构的策略。
Required Sheets逗号分隔的 Excel 文档工作表名称列表,应从中提取行。如果此属性留空,则将从所有工作表中提取所有行。名称列表区分大小写。未在此值中指定的任何工作表将被忽略。如果指定的工作表未找到,将抛出异常。
支持表达式语言:是(使用 FlowFile 属性与环境/系统变量求值)
Date Format指定读取/写入日期字段时使用的格式。如果未指定,日期字段将被视为自纪元(1970 年 1 月 1 日午夜 GMT)以来的毫秒数。如果指定,值必须匹配 Java java.time.format.DateTimeFormatter 格式(例如,MM/dd/yyyy 表示两位数字的月份,后跟两位数字的日期,后跟四位数字的年份,全部以 '/' 字符分隔,如 01/01/2017)。
Time Format指定读取/写入时间字段时使用的格式。如果未指定,时间字段将被视为自纪元(1970 年 1 月 1 日午夜 GMT)以来的毫秒数。如果指定,值必须匹配 Java java.time.format.DateTimeFormatter 格式(例如,HH:mm:ss 表示 24 小时格式的两位数字的小时,后跟两位数字的分钟,后跟两位数字的秒,全部以 ':' 字符分隔,如 18:04:15)。
Timestamp Format指定读取/写入时间戳字段时使用的格式。如果未指定,时间戳字段将被视为自纪元(1970 年 1 月 1 日午夜 GMT)以来的毫秒数。如果指定,值必须匹配 Java java.time.format.DateTimeFormatter 格式(例如,MM/dd/yyyy HH:mm:ss 表示两位数字的月份,后跟两位数字的日期,后跟四位数字的年份,全部以 '/' 字符分隔;然后后跟 24 小时格式的两位数字的小时,后跟两位数字的分钟,后跟两位数字的秒,全部以 ':' 字符分隔,如 01/01/2017 18:04:15)。

状态管理

该组件不存储状态。

受限 (Restricted)

该组件不受限。

提供的 Service API

  • RecordReaderFactory (cn.org.acal.lynxus-lynxus-standard-services-api-nar-2.11.8)

详细说明

ExcelReader

ExcelReader 允许把输入数据解释为带分隔符的 Record。Excel 电子表格中的每一行是一条记录,每个单元格被视为一个字段。 该读取器允许选择从哪一行开始,以及摄取电子表格中的哪些工作表。 使用 "Use Starting Row" 策略时,字段名会取自所配置起始行的列名。如果 起始行有任何空白列,会自动为其分配以 "column_" 为前缀、以单元格编号命名的字段名。使用 "Infer Schema" 策略时,字段名会取自每列的单元格编号,并以 "column_" 为前缀。其他情况下,可以通过 Schema Text 指定 schema 或在 Schema Registry 中查找 schema 来提供字段名。

Schema 与类型强制转换

从传入数据解析记录时,记录会被拆分为字段。每个字段会按字段名 在配置的 schema 中查找,以确定数据的类型。如果字段不在 schema 中,该字段会从 Record 中省略。如果字段在 schema 中,接收到的数据类型会与 schema 指定的数据类型比较。如果类型匹配,字段值直接使用。如果 schema 表明字段应为不同类型,该 Controller Service 会尝试把数据强制转换为 schema 指定的类型。如果字段无法强制转换为指定类型,会抛出异常。

尝试把字段值从一种数据类型强制转换为另一种时,适用以下规则:

  • Excel 把所有数值类型存储为 Double,它可以强制转换为其他任何数值数据类型(Byte、Short、Int、Long、Float)。
  • 任何数据类型都可以强制转换为 String 类型。请注意,由于 Excel 把所有数字存储为 Double,把大数字强制转换为 String 会得到科学计数法的字符串表示。如果不希望这样,可以把数字强制转换为 Long 数值类型。
  • 任何数值都可以强制转换为 Date、Time 或 Timestamp 类型,前提是把 Long 值视为自纪元(1970 年 1 月 1 日 GMT 午夜)以来的毫秒数。
  • 如果 String 值的格式匹配配置的 "Date Format"、"Time Format" 或 "Timestamp Format",它可以强制转换为 Date、Time 或 Timestamp 类型。
  • 如果值是合适的类型,String 值可以强制转换为数值。例如,String 值 8 可以强制转换为任何数值类型。但 String 值 8.2 可以强制转换为 Double 或 Float 类型,不能转换为 Integer。
  • "true" 或 "false"(不区分大小写)的 String 值可以强制转换为 Boolean 值。
  • 非空的 String 值可以强制转换为 Char 类型。如果 String 包含多个字符,使用第一个字符,其余字符被忽略。
  • 任何"日期/时间"类型(Date、Time、Timestamp)都可以强制转换为 其他任何"日期/时间"类型。
  • 任何"日期/时间"类型都可以强制转换为 Long 类型,表示自纪元(1970 年 1 月 1 日 GMT 午夜)以来的毫秒数。
  • 任何"日期/时间"类型都可以强制转换为 String。String 的格式是对应属性(Date Format、Time Format、 Timestamp Format 属性)所配置的 DateFormat。

尝试把值从一种数据类型强制转换为另一种时,如果上述规则都不适用, 强制转换会失败并抛出异常。

使用起始行与

Schema 推断

虽然 Lynxus 的 Record API 要求每条记录都有 schema,但根据数据中的值推断 schema 通常比手动创建 schema 更方便。这通过把 "Schema Access Strategy" 属性设为 "Use Starting Row" 或 "Infer Schema" 实现。使用 "Use Starting Row" 策略时,Reader 会解析 FlowFile 数据中所配置起始行之后的前十行来确定 schema,同时跟踪遇到的所有字段及每个字段的类型。然后形成一个 涵盖所有遇到字段的 schema。即使这十行中存在空白行也能推断出 schema,但如果它们全是空白行,该策略将无法创建 schema。使用 "Infer Schema" 策略时,Reader 会先解析 FlowFile 中的所有数据,跟踪遇到的所有字段及每个字段的类型, 以此确定 schema。所有数据解析完成后,形成一个涵盖所有遇到字段的 schema。

推断 schema 时的一个常见疑虑是如何处理同一字段两个值类型不同的情况。 例如,考虑包含以下两条记录的 FlowFile:

name, age
John, 8
Jane, Ten

显然 "name" 字段会被推断为 STRING 类型。但 "age" 字段该怎么处理?该字段应该是 INT 和 STRING 之间的 CHOICE 吗?应该优先 LONG 还是 INT?直接用 STRING 吗?该字段应该可为 null 吗?

为帮助理解该 Record Reader 如何推断 schema,以下是推断逻辑遵循的规则列表:

  • 所有字段都被推断为可为 null。
  • 当两条不同记录中同一字段遇到两个值(或 ARRAY 类型遇到两个值)时,推断引擎倾向于使用"更宽"的数据类型, 而不是 CHOICE 数据类型。当且仅当数据类型 "A" 包含数据类型 "B" 的所有值以及其他值时,称数据类型 "A" 比 "B" 宽。例如,LONG 类型比 INT 类型宽,但不比 BOOLEAN 类型宽(BOOLEAN 也不比 LONG 宽)。INT 比 SHORT 宽。STRING 类型被认为比除 MAP、RECORD、ARRAY 和 CHOICE 之外的所有类型都宽。
  • 在推断值的类型之前,会移除首尾空白。此外,如果值被双引号 (") 包围,双引号会被移除。因此,值 16 与 "16" 的解释相同,两者都会被解释为 INT。但值 " 16" 会被推断为 STRING 类型,因为空白被包含在双引号内,意味着空白被视为值的一部分。
  • 如果配置了 "Time Format"、"Timestamp Format" 或 "Date Format" 属性,任何原本会被视为 STRING 类型的值都会先与配置的格式比对,看是否匹配其中任何一个。 如果值匹配 Timestamp Format,该值被视为 Timestamp 字段。如果匹配 Date Format,被视为 Date 字段。如果匹配 Time Format,被视为 Time 字段。在不太可能的情况下,值匹配多个配置的格式时, 匹配顺序为:Timestamp、Date、Time。也就是说,如果一个值同时匹配 Timestamp Format 和 Date Format,推断出的类型是 Timestamp。由于解析日期和时间可能开销较大,如果不期望出现 日期、时间和时间戳,或把数据处理为 STRING 也可接受,建议不要配置这些格式。不过,对于这很重要的 用例,推断引擎足够智能,会先检查几个开销很小的条件来优化解析。 例如,检查字符串长度是否过长或过短而无法匹配模式。这比尝试把 每个字符串值解析为时间戳要高效得多。
  • 从不推断 MAP 类型。
  • 从不推断 ARRAY 类型。
  • 从不推断 RECORD 类型。
  • 如果字段存在但所有值都为 null,该字段被推断为 STRING 类型。

推断

Schema 的缓存

该 Record Reader 要求:如果要推断 schema,必须读取所有记录,以确保推断出的 schema 适用于 FlowFile 中的所有记录。但这可能开销较大,尤其是数据要经过许多 不同转换时。为减轻推断 schema 的开销,可以为 Record Reader 配置 "Schema Inference Cache"(填写同名属性)。这是一个可以被 Record Reader 和 Record Writer 共享的 Controller Service。

每当使用 Record Writer 写入数据时,如果配置了 "Schema Cache",它也会把 schema 添加到 Schema Cache。这会把该 schema 的标识符作为 Attribute 添加到 FlowFile。

每当使用 Record Reader 读取数据时,如果配置了 "Schema Inference Cache",它会先查找 FlowFile 上的 "schema.cache.identifier" Attribute。如果该 Attribute 存在,它会用该 Attribute 的值在 schema 缓存中查找 schema。如果能在缓存中找到该标识符对应的 schema,就直接使用该 schema,而不是读取、解析和分析数据来推断 schema。如果 FlowFile 上没有该 Attribute,或该 Attribute 存在但缓存中没有该标识符对应的 schema,Record Reader 就会按上述方式推断 schema。

最终效果是,用户可以串联许多不同的 Processor 来处理面向记录的数据。通常,只有链中的第一个 Processor 会承担推断 schema 的"代价"。对于链中的所有其他 Processor,Record Reader 只需按标识符在 Schema Cache 中查找 schema 即可。这让 Record Reader 能准确推断 schema(因为它基于 FlowFile 中的所有数据推断),同时仍然高效,因为无论有多少 Processor 处理数据,schema 通常只推断一次。

示例

示例

1

例如,考虑一个内容为 Excel 电子表格的 FlowFile,其唯一的工作表包含以下内容:

id, name, balance, join_date, notes
1, John, 48.23, 04/03/2007, "Our very   first customer!"
2, Jane, 1245.89, 08/22/2009,     
3, Frank Franklin, "48481.29", 04/04/2016,

另外,假设该 Controller Service 配置为跳过第一行,并配置了指向 AvroSchemaRegistry 的 Schema Registry,其中包含以下 schema:

{
  "namespace": "lynxus",
  "name": "balances",
  "type": "record",
  "fields": [
    {
      "name": "id",
      "type": "int"
    },
    {
      "name": "name",
      "type": "string"
    },
    {
      "name": "balance",
      "type": "double"
    },
    {
      "name": "join_date",
      "type": {
        "type": "int",
        "logicalType": "date"
      }
    },
    {
      "name": "notes",
      "type": "string"
    }
  ]
}

在上面的示例中,'join_date' 列是 Date 类型。为了让 Excel Reader 能正确把值解析为日期,需要给读取器提供要使用的日期格式。 本例中,我们会把 Date Format 属性配置为 MM/dd/yyyy,表示两位月份,后跟两位日期,再跟四位年份——各部分以 斜杠分隔。此时,结果是该 FlowFile 由 3 条不同的记录组成。第一条记录包含以下值:

字段名 字段值
id 1
name John
balance 48.23
join_date 04/03/2007
notes Our very
first customer!

第二条记录包含以下值:

字段名 字段值
id 2
name Jane
balance 1245.89
join_date 08/22/2009
notes

第三条记录包含以下值:

字段名 字段值
id 3
name Frank Franklin
balance 48481.29
join_date 04/04/2016