来自主题的KSQL流具有异构JSON结构

时间:2018-12-18 21:00:35

标签: ksql

是否有一种方法可以从主题创建流,该主题指定应将整个记录视为VARCHAR,以便可以使用extractjsonfield()从该记录创建流?样本记录可能类似于:

{
  "Header": {
    "RecType": "RecA",
    ... more header records in a fairly consistent format ...
  },
  "RAFld1": {
    "someFld": "some data",
    "someOtherField": 1.001,
  },
  "RAFld2": {
    "aFld": "data",
    "anotherFld": 98.6,
    ...
  },
  ...
}

但是下一条记录可能如下:

{
  "Header": {
    "RecType": "RecB",
    ... more header records in a fairly consistent format ...
  },
  "RBFld1": {
    "randomFld": "random data",
    "randomOtherField": 1.001,
    ...
  }
}

我可以弄清楚如何使用已知的字段(类型为VARCHAR)定义初始流,然后再定义extractjsonfield()(带有适当的where子句),但是看不出有什么方法可以说顶级结构并不一致命名字段。

这是我的输入主题的格式设置方式;我无法更改该格式。我希望KSQL将成为一个优雅的解决方案,但是我似乎一开始就因为无法处理这种动态结构而陷入困境。

1 个答案:

答案 0 :(得分:1)

是否命名不是每个消息中都存在的模式字段都无关紧要;您将只获得null个值。

我认为您的问题是一个有趣的问题,并撰写了有关KSQL如何在这里工作的解释-让我知道您是否还想使用它,我可以扩展答案。


  1. 检查原始数据:

    ksql> PRINT 'source_data' FROM BEGINNING;
    Format:JSON
    {"ROWTIME":1545239521600,"ROWKEY":"null","Header":{"RecType":"RecA"},"RAFld1":{"someFld":"some data","someOtherField":1.001},"RAFld2":{"aFld":"data","anotherFld":98.6}}
    {"ROWTIME":1545239526600,"ROWKEY":"null","Header":{"RecType":"RecB"},"RBFld1":{"randomFld":"random data","randomOtherField":1.001}}
    
  2. 注册source_data主题以用作称为my_stream的KSQL流:

    CREATE STREAM my_stream (Header VARCHAR, \
                             RAFld1 VARCHAR, \
                             RAFld2 VARCHAR, \
                             RBFld1 VARCHAR) \
    WITH (KAFKA_TOPIC='source_data', VALUE_FORMAT='JSON');
    
  3. 检查消息。请注意,在第二条消息(记录类型为“ B”)中,“ RAFld1”没有值,因此显示了null

    ksql> SELECT Header, RAFld1 FROM my_stream LIMIT 2;
    {"RecType":"RecA"} | {"someOtherField":1.001,"someFld":"some data"}
    {"RecType":"RecB"} | null
    
  4. 使用记录类型“ A”的值填充新的Kafka主题,使用EXTRACTFROMJSON过滤Header值上的记录类型,并从有效负载中提取命名字段:

    CREATE STREAM recA_data WITH (VALUE_FORMAT='AVRO') AS \
    SELECT EXTRACTJSONFIELD(RAFld1,'$.someOtherField') AS someOtherField, \
            EXTRACTJSONFIELD(RAFld1,'$.someFld')        AS someFld, \
            EXTRACTJSONFIELD(RAFld2,'$.aFld')           AS aFld, \
            EXTRACTJSONFIELD(RAFld2,'$.anotherFld')     AS anotherFld \
            FROM my_stream \
    WHERE EXTRACTJSONFIELD(Header,'$.RecType') = 'RecA';
    

    请注意,序列化已切换到Avro,以便任何使用者都可以自动使用该模式,而不必手动声明它。

  5. 观察到新流具有一个模式,并在消息到达原始source_data主题时不断填充消息:

    ksql> DESCRIBE recA_data;
    
    Name                 : RECA_DATA
    Field          | Type
    --------------------------------------------
    ROWTIME        | BIGINT           (system)
    ROWKEY         | VARCHAR(STRING)  (system)
    SOMEOTHERFIELD | VARCHAR(STRING)
    SOMEFLD        | VARCHAR(STRING)
    AFLD           | VARCHAR(STRING)
    ANOTHERFLD     | VARCHAR(STRING)
    --------------------------------------------
    For runtime statistics and query details run: DESCRIBE EXTENDED <Stream,Table>;
    
    ksql> SELECT * FROM recA_data;
    1545240188787 | null | 1.001 | some data | data | 98.6