Java 如何根据json中的特定键将接收器从一个数据流添加到不同的路径?

Java 如何根据json中的特定键将接收器从一个数据流添加到不同的路径?,java,json,apache-flink,flink-streaming,sink,Java,Json,Apache Flink,Flink Streaming,Sink,我有类似的JSON { "name":"someone", "job":"doctor", "etc":"etc" } 在每个json中,“工作”都有不同的价值,比如医生、飞行员、司机、看守员等。 我想根据“job”值分离每个json,并将其存储在不同的位置,如/home/doctor,/home/pilot,/home/driver等 我已经尝试使用SplitStream函数来实现这一点,但是我必须指定那些值来匹配条件 public class MyFlinkJob {

我有类似的JSON

{
  "name":"someone",
  "job":"doctor",
  "etc":"etc"
}
在每个json中,“工作”都有不同的价值,比如医生、飞行员、司机、看守员等。 我想根据“job”值分离每个json,并将其存储在不同的位置,如
/home/doctor
/home/pilot
/home/driver

我已经尝试使用SplitStream函数来实现这一点,但是我必须指定那些值来匹配条件

public class MyFlinkJob {   
    private static JsonParser jsonParser = new JsonParser();
    private static String key_1 = "doctor";
    private static String key_2 = "driver";
    private static String key_3 = "pilot";
    private static String key_default = "default";

    public static void main(String args[]) throws Exception {
        Properties prop = new Properties();
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        Properties props = new Properties();
        props.setProperty("bootstrap.servers", kafka);
        props.setProperty("group.id", "myjob");

        FlinkKafkaConsumer<String> myConsumer = new FlinkKafkaConsumer<>("topic", new SimpleStringSchema(), props);
        DataStream<String> record = env.addSource(myConsumer).rebalance()

        SplitStream<String> split = record.split(new OutputSelector<String>() {
            @Override
            public Iterable<String> select(String val) {
                JsonObject json = (JsonObject)jsonParser.parse(val);
                String jsonValue = CommonFields.getFieldValue(json, "job");
                List<String> output = new ArrayList<String>();

                if (key_1.equalsIgnoreCase(jsonValue)) {
                    output.add("doctor");
                } else if (key_2.equalsIgnoreCase(jsonValue)) {
                    output.add("driver");
                } else if (key_3.equalsIgnoreCase(jsonValue)) {
                    output.add("pilot");
                } else {
                    output.add("default");
                }
                return output;
            }});

        DataStream<String> doctor = split.select("doctor");
        DataStream<String> driver = split.select("driver");
        DataStream<String> pilot = split.select("pilot");
        DataStream<String> default1 = split.select("default");
        doctor.addSink(getBucketingSink(batchSize, prop, key_1));
        driver.addSink(getBucketingSink(batchSize, prop, key_2));
        pilot.addSink(getBucketingSink(batchSize, prop, key_3));
        default1.addSink(getBucketingSink(batchSize, prop, key_default));
        env.execute("myjob");
    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        if (input != null) {
            try {
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

public static BucketingSink<String> getBucketingSink(Long BatchSize, Properties prop, String key) {
    BucketingSink<String> sink = new BucketingSink<String>("hdfs://*/home/"+key);
    Configuration conf = new Configuration();
    conf.set("hadoop.job.ugi", "hdfs");
    sink.setFSConfig(conf);
    sink.setBucketer(new DateTimeBucketer<String>(prop.getProperty("DateTimeBucketer")));
    return sink;
}
}
公共类MyFlinkJob{
私有静态JsonParser JsonParser=新JsonParser();
私有静态字符串密钥_1=“医生”;
私有静态字符串密钥_2=“驱动程序”;
专用静态字符串密钥_3=“pilot”;
私有静态字符串密钥\u default=“default”;
公共静态void main(字符串args[])引发异常{
Properties prop=新属性();
StreamExecutionEnvironment env=StreamExecutionEnvironment.getExecutionEnvironment();
Properties props=新属性();
props.setProperty(“bootstrap.servers”,kafka);
props.setProperty(“group.id”、“myjob”);
FlinkKafkaConsumer myConsumer=新的FlinkKafkaConsumer(“主题”,新的SimpleStringSchema(),道具);
DataStream record=env.addSource(myConsumer.rebalance())
SplitStream split=record.split(新的OutputSelector(){
@凌驾
公共Iterable选择(字符串值){
JsonObject json=(JsonObject)jsonParser.parse(val);
字符串jsonValue=CommonFields.getFieldValue(json,“作业”);
列表输出=新的ArrayList();
if(键1.相等信号情况(jsonValue)){
输出。添加(“医生”);
}else if(键2.相等信号情况(jsonValue)){
输出。添加(“驱动程序”);
}else if(键3.相等信号情况(jsonValue)){
输出。添加(“试点”);
}否则{
输出。添加(“默认”);
}
返回输出;
}});
数据流医生=拆分。选择(“医生”);
数据流驱动程序=拆分。选择(“驱动程序”);
DataStream pilot=split.select(“pilot”);
DataStream default1=split.select(“默认”);
doctor.addSink(getBucketingSink(批量大小、道具、按键1));
驱动程序addSink(getBucketingSink(批大小、道具、键2));
pilot.addSink(getBucketingSink(批量大小,道具,键3));
default1.addSink(getBucketingSink(batchSize,prop,key_default));
环境执行(“我的工作”);
}捕获(IOEX异常){
例如printStackTrace();
}最后{
如果(输入!=null){
试一试{
input.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
}
公共静态BucketingSink getBucketingSink(长批量大小、属性属性、字符串键){
BucketingSink水槽=新的BucketingSink(“hdfs://*/home/”+键);
Configuration conf=新配置();
conf.set(“hadoop.job.ugi”、“hdfs”);
sink.setFSConfig(conf);
sink.setBucketer(新的DateTimeBucketer(prop.getProperty(“DateTimeBucketer”)));
回流槽;
}
}

假设“job”中有任何其他值,如engineer或其他内容,而我在类中没有指定,那么它将转到默认文件夹。是否有任何方法可以根据“job”的值自动拆分这些json事件,而无需指定它,并创建一个包含值名称的路径,如/home/enginerr?

要使用,它支持根据字段的值将记录写入单独的存储桶。我可能有一个map函数,它接收JSON字符串,解析它,并发出一个
Tuple2
,其中第一个元素是JSON中
job
字段的值,第二个元素是完整的JSON字符串。

感谢reply@kkrugler,正如你现在所说的,我已经创建了一个发出Tuple2的函数,但是我不知道如何将它与BucketingSink一起使用。我在回答中链接到的用于BucketingSink的JavaDocs显示了如何使用它的一般形式。对于您的特定情况,您需要一个实现Bucketer接口的类,并基于传递其
getBucketPath()
方法的元素中的
.f0
字段构造bucket路径。