如何在非行键列上连接KSQL表和流

时间:2020-06-03 22:18:59

标签: ksqldb confluent-platform

我正在使用融合版Platform 5.4.1的社区版。我没有找到任何CLI命令来打印KSQL Server版本,但是当我输入KSQL时,可以在所附的屏幕截图中找到。 enter image description here

我有一个地理围栏表-

CREATE TABLE GEOFENCE (GEOFENCEID INT, 
                       FLEETID VARCHAR, 
                       GEOFENCECOORDINATES VARCHAR) 
                 WITH (KAFKA_TOPIC='MONGODB-GEOFENCE', 
                       VALUE_FORMAT='JSON', 
                       KEY= 'GEOFENCEID');

每当从REST API支持的Web应用程序对geofence MongoDB集合执行插入或更新操作时,数据就会从Kafka MongoDB源连接器发送到Geofence KSQL表。将地理围栏制成表格的想法是,由于表格是可变的,因此它将保存更新的地理围栏信息,并且由于插入或更新操作不会非常频繁,并且只要在Geofence MongoDB集合中发生更改,它们就会在Geofence KSQL上进行更新表格,因为这里的键是GeofenceId。

我有车辆位置的实时直播-

CREATE STREAM VEHICLE_POSITION (VEHICLEID INT, 
                                FLEETID VARCHAR, 
                                LATITUDE DOUBLE, 
                                LONGITUDE DOUBLE) 
                          WITH (KAFKA_TOPIC='VEHICLE_POSITION', 
                          VALUE_FORMAT='JSON')

我想像这样加入表和流-

CREATE STREAM VEHICLE_DISTANCE_FROM_GEOFENCE AS 
    SELECT  GF.GEOFENCEID, 
            GF.FLEETID, 
            VP.VEHICLEID, 
            GEOFENCE_UDF(GF.GEOFENCECOORDINATES, VP.LATITUDE, VP.LONGITUDE)  
       FROM GEOFENCE GF 
             LEFT JOIN VEHICLE_POSITION VP 
                ON GF.FLEETID = VP.FLEETID;

但是KSQL不允许我这样做,因为我正在对非行键列的FLEETID执行连接。尽管这在SQL中是可能的,但是如何在KSQL中实现呢?

注意:根据我的应用程序的业务逻辑,Fleet Id用于组合地理围栏和属于车队的车辆。

表的样本数据-

INSERT INTO GEOFENCE
(GEOFENCEID INT, FLEETID VARCHAR, GEOFENCECOORDINATES VARCHAR) 
VALUES (10, 123abc, 52.4497_13.3096);

流的样本数据-

INSERT INTO VEHICLE_POSITION 
(VEHICLEID INT, FLEETID VARCHAR, LATITUDE DOUBLE, LONGITUDE DOUBLE) 
VALUES (1289, 125abc, 57.7774, 12.7811):

1 个答案:

答案 0 :(得分:0)

要解决您的问题,您需要的是FENCEID到GEOFENCECOORDINATES的表。您可以使用这样的表加入VEHICLE_POSITION流,以获得所需的结果。

那么,如何获取FENCEID表到GEOFENCECOORDINATES?

简单的答案是您不能使用当前表定义!您声明该表仅具有GEOFENCEID作为主键。然而,FleetId可以有很多栅栏。为了能够对此进行模式设置,GEOFENCEIDFENCEID都需要成为表主键的一部分。

考虑示例:

INSERT INTO GEOFENCE VALUES (10, 'fleet-1', 'coords-1');
INSERT INTO GEOFENCE VALUES (10, 'fleet-2', 'coords-2');

在运行这两个插入时,表将仅包含一行,键为10,值为'fleet-2', 'coords-2'

即使我们能以某种方式在表中捕获上述信息,也请考虑一下该主题中是否存在逻辑删除,该怎么办,因为第一行已从源Mongo表中删除。逻辑删除是键(10)和null值。然后,ksqlDB将使用键10从其表中删除该行,从而留下一个空表。

这是您问题的症结所在!

首先,您需要配置源连接器,以将围栏ID和车队ID都放入消息的密钥中。

接下来,您需要在ksqlDB中访问它。不幸的是,尽管很快this is being worked on,但ksqlDB从0.10.0 / CP 6.0.0版本开始不支持多个键列。

同时,如果您的密钥是包含两个密钥字段的JSON文档,例如

{
   "GEOFENCEID": 10,
   "FLEETID": "fleet-1"
}

然后您可以将其作为STRING导入到ksqlDB中:

-- 5.4.1 syntax:
-- ROWKEY will contain the JSON document, containing GEOFENCEID and FLEETID
CREATE TABLE GEOFENCE (
    GEOFENCECOORDINATES VARCHAR
  ) 
  WITH (
     KAFKA_TOPIC='MONGODB-GEOFENCE', 
     VALUE_FORMAT='JSON'
  );

-- 6.0.0 syntax:
CREATE TABLE GEOFENCE (
    JSONKEY STRING PRIMARY KEY, 
    GEOFENCECOORDINATES VARCHAR
  ) 
  WITH (
    KAFKA_TOPIC='MONGODB-GEOFENCE', 
    VALUE_FORMAT='JSON'
  );

现在正确定义了表,您可以使用EXTRACTJSONFIELD访问JSON密钥中的数据,并使用COLLECT_SET收集所有围栅坐标。我不是100%肯定会在5.4.1上使用(请参阅您的操作方法),但不会在6.0.0上使用。

-- 6.0.0 syntax
CREATE TABLE FLEET_COORDS AS
   SELECT
    EXTRACTJSONFIELD(JSONKEY, '$.FLEETID') AS FLEETID,
    COLLECT_SET(GEOFENCECOORDINATES)
   FROM GEOFENCE
   GROUP BY EXTRACTJSONFIELD(JSONKEY, '$.FLEETID');

这将为您提供一个FleetId表,用于一组围栏坐标。您可以使用它来加入车辆位置流。当然,您的GEOFENCE_UDF udf将需要接受ARRAY<STRING>作为篱笆坐标,因为可能有很多。

祝你好运!