从HDFS中读取Avro数据

使用PXF HDFS连接器读取Avro格式数据。本节描述如何使用PXF访问HDFS中的Avro数据,包括如何创建和查询引用HDFS中Avro文件的外部表。

先决条件

在尝试从HDFS读取或向HDFS写入数据之前,请确保已满足PXF Hadoop先决条件

使用Avro数据

Apache Avro是一个数据序列化框架,其中的数据都以压缩二进制格式序列化。Avro在Json中指定数据类型。 Avro格式数据具有独立的模式, 这也在Json中定义。 Avro模式及其数据完全是自描述的。

数据类型映射

Avro支持原生数据类型和复杂数据类型。

要在Greenplum数据库中表示Avro原生数据类型,请将数据值映射到相同类型的Greenplum列。

Avro支持复杂数据类型数组(array), 映射(map), 记录(record), 枚举(enumeration)以及固定长度类型(fixed type)。 将这些复杂数据类型的顶层字段映射为Greenplum数据库的 TEXT类型。虽然Greenplum本身并不支持这些类型,您可以创建Greenplum数据库函数或应用程序代码来提取或进一步处理这些复杂数据类型的子部件。

下表总结了Avro数据的外部映射规则。

Avro数据类型 PXF/Greenplum 数据类型
boolean boolean
bytes bytea
double double
float real
int int or smallint
long bigint
string text
复杂类型: Array, Map, Record, or Enum text, 并在集合项、映射的键值对和记录数据之间插入分隔符。
复杂类型: Fixed bytea
并集 对于原始数据类型或复杂数据类型,遵循上述约定,具体取决于并集;支持Null值。

Avro 模式和数据

Avro 模式使用json定义,由上面数据类型映射部分中的原生类型和复杂类型组成。Avro 模式文件通常具有.avsc后缀。

Avro模式文件中的字段是通过对象数组定义的,每个对象都由名称和类型指定。

创建外部表

使用hdfs:avro配置文件读取HDFS中的Avro格式数据,以下语法创建了引用该配置文件的可读外部表:

CREATE EXTERNAL TABLE <table_name>
    ( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<path-to-hdfs-file>?PROFILE=hdfs:avro[&<custom-option>=<value>[...]]')
FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');

CREATE EXTERNAL TABLE命令中使用的特定关键字和值见下表中描述。

关键字
<path‑to‑hdfs‑file> HDFS数据存储中目录或文件的绝对路径
PROFILE PROFILE关键字必须指定为hdfs:avro.
SERVER=<server_name> PXF用于访问数据的命名服务器配置。可选的; 如果未指定,PXF将使用default服务器。
<custom‑option> <custom-option>描述见下方
FORMAT ‘CUSTOM’ hdfs:avro配置文件中使用FORMAT 'CUSTOM'CUSTOM FORMAT 要求您指定为 (FORMATTER='pxfwritable_import')

对于复杂数据类型,PXFhdfs:avro配置文件在集合项和值之间插入默认分隔符。您可以通过指定在CREATE EXTERNAL TABLE命令中指定hdfs:avro自定义选项来使用非默认分隔符。

hdfs:avro配置文件支持以下<custom-option>:

选项关键字 描述
COLLECTION_DELIM 当PXF将Avro复杂数据类型映射到文本列时,放置在顶层数组、映射或记录字段中的条目之间的分隔符。默认为逗号,字符。
MAPKEY_DELIM 当PXF将Avro复杂数据类型映射到文本列时,放置在映射项的键和值之间的分隔符。默认为冒号:字符。
RECORDKEY_DELIM 当PXF将Avro复杂数据类型映射到文本列时,放置在字段名称和记录条目之间的分隔符。 默认为冒号:字符。

示例:读取Avro数据

本节中的示例将对具有以下字段名称和数据类型模式的Avro数据进行操作:

  • id - 长整型
  • username - 字符串
  • followers - 字符串数组
  • fmap - 长整型映射
  • relationship - 枚举类型
  • address - 由街道号码(整型)、街道名称(字符串)、以及城市(字符串)组成的记录类型

创建模式

执行以下操作创建一个Avro模式,以表示上述模式。

  1. 创建一个名为avro_schema.avsc的文件:

    $ vi /tmp/avro_schema.avsc
    
  2. 将以下文本复制并粘贴到avro_schema.avsc中:

    {
    "type" : "record",
      "name" : "example_schema",
      "namespace" : "com.example",
      "fields" : [ {
        "name" : "id",
        "type" : "long",
        "doc" : "Id of the user account"
      }, {
        "name" : "username",
        "type" : "string",
        "doc" : "Name of the user account"
      }, {
        "name" : "followers",
        "type" : {"type": "array", "items": "string"},
        "doc" : "Users followers"
      }, {
        "name": "fmap",
        "type": {"type": "map", "values": "long"}
      }, {
        "name": "relationship",
        "type": {
            "type": "enum",
            "name": "relationshipEnum",
            "symbols": ["MARRIED","LOVE","FRIEND","COLLEAGUE","STRANGER","ENEMY"]
        }
      }, {
        "name": "address",
        "type": {
            "type": "record",
            "name": "addressRecord",
            "fields": [
                {"name":"number", "type":"int"},
                {"name":"street", "type":"string"},
                {"name":"city", "type":"string"}]
        }
      } ],
      "doc:" : "A basic schema for storing messages"
    }
    

创建Avro数据文件(JSON)

执行以下步骤来创建符合上述模式的示例Avro文件。

  1. 创建一个名为pxf_avro.txt的文本文件:

    $ vi /tmp/pxf_avro.txt
    
  2. pxf_avro.txt中输入以下数据:

    {"id":1, "username":"john","followers":["kate", "santosh"], "relationship": "FRIEND", "fmap": {"kate":10,"santosh":4}, "address":{"number":1, "street":"renaissance drive", "city":"san jose"}}
    
    {"id":2, "username":"jim","followers":["john", "pam"], "relationship": "COLLEAGUE", "fmap": {"john":3,"pam":3}, "address":{"number":9, "street":"deer creek", "city":"palo alto"}}
    

    示例数据使用逗号,分隔顶层字段,并使用冒号: 分隔键-值对以及记录字段和值.

  3. 将文本文件转换为Avro格式文件。有多种方法可以通过编程方式和通过命令行转换。在这个例子中,我们使用Java Avro toolsavro-tools-1.8.1.jar jar文件放置在当前目录中:

    $ java -jar ./avro-tools-1.8.1.jar fromjson --schema-file /tmp/avro_schema.avsc /tmp/pxf_avro.txt > /tmp/pxf_avro.avro
    

    生成的Avro二进制文件被写入/tmp/pxf_avro.avro

  4. 将生成的Avro文件复制到HDFS:

    $ hdfs dfs -put /tmp/pxf_avro.avro /data/pxf_examples/
    

使用hdfs:avro配置文件查询

执行以下来创建和查询引用您在上一节添加到HDFS的pxf_avro.avro文件。创建表时:

  • 使用PXF默认服务器。
  • 将顶层原生字段id (长整型)和username(字符串类型)映射到其等效的Greenplum的数据库类型(bigint和text)。
  • 将剩下的复杂类型映射为text类型
  • 使用hdfs:avro配置文件的自定义选项设置记录(record)、映射(map)和集合(collection)的分隔符
  1. 使用hdfs:avro配置文件从pxf_avro.avro文件创建可查询外部表:

    postgres=# CREATE EXTERNAL TABLE pxf_hdfs_avro(id bigint, username text, followers text, fmap text, relationship text, address text)
                LOCATION ('pxf://data/pxf_examples/pxf_avro.avro?PROFILE=hdfs:avro&COLLECTION_DELIM=,&MAPKEY_DELIM=:&RECORDKEY_DELIM=:')
              FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
    
  2. pxf_hdfs_avro表执行简单查询:

    postgres=# SELECT * FROM pxf_hdfs_avro;
    
     id | username |   followers    |        fmap         | relationship |                      address                      
    ----+----------+----------------+--------------------+--------------+---------------------------------------------------
      1 | john     | [kate,santosh] | {kate:10,santosh:4} | FRIEND       | {number:1,street:renaissance drive,city:san jose}
      2 | jim      | [john,pam]     | {pam:3,john:3}      | COLLEAGUE    | {number:9,street:deer creek,city:palo alto}
    (2 rows)
    

    外部表的简单查询显示了复杂数据类型的组成部分,这些组成部分由CREATE EXTERNAL TABLE中指定的分隔符分隔。

  3. 根据您的应用程序处理文本列中被分隔的部分。例如,以下命令使用Greenplum数据库内部的string_to_array函数将followers字段中的条目转换为新视图中的文本数组列。

    postgres=# CREATE VIEW followers_view AS 
    SELECT username, address, string_to_array(substring(followers FROM 2 FOR (char_length(followers) - 2)), ',')::text[] 
        AS followers 
      FROM pxf_hdfs_avro;
    
  4. 根据特定的关注者是否出现在视图中来执行查询并过滤行:

    postgres=# SELECT username, address FROM followers_view WHERE followers @> '{john}';
    
     username |                   address                   
    ----------+---------------------------------------------
     jim      | {number:9,street:deer creek,city:palo alto}