【问题标题】:Convert Dataframe Dataset<Row> to JSON Format of String Data Type for particular Columns and convert the JSON String back to Dataframe将 Dataframe Dataset<Row> 转换为特定列的字符串数据类型的 JSON 格式,并将 JSON 字符串转换回 Dataframe
【发布时间】:2020-02-16 13:02:44
【问题描述】:

我有一个数据框。我需要为每条记录调用一个 Rest API。

假设数据框看起来像:

|----|-------------|-----|---------|
|UUID|PID          |DEVID|FIRSTNAME|
|----|-------------|-----|---------|
|1111|1234567891011|ABC11|JOHN     |
|2222|9876543256827|ABC22|HARRY    |
|----|-------------|-----|---------|

第一行的 JSON 请求字符串应该看起来像(注意:json 是在 2 列上创建的,而不是全部),因为要调用的 Rest API 需要这种格式的输入:

{"applicationInfo": {"appId": "ec78fef4-92b9-3b1b-a68d-c45376b6977a"}, "requestData": [{"secureData": "JOHN", "secureDataType": "FIRSTNAME", "index": 1 }, {"secureData": "1234567891011", "secureDataType": "PID", "index": 2 } ] }

索引键的值必须动态生成,每行使用一个增量计数器。

然后,我需要调用 Rest API 将上述 JSON 作为字符串参数发送。

加密后 API 的响应如下所示:

{"responseData":[{"resultCode":"00","secureData":"63ygdydshbhgvdyw3et7edgu","secureDataType":"FIRSTNAME","index":1},{"resultCode":"00","secureData":"HKJJBJHVHG66456456FXXFFCGF","secureDataType":"PID","index":2}],"responseCode":"00","responseMessage":"SUCCESS","resultCounts":{"totalCount":2,"successCount":2,"failedCount":0}}

然后我需要阅读上面的响应并创建一个如下所示的数据框:

|----|--------------------------|-----|------------------------|
|UUID|PID                       |DEVID|FIRSTNAME               |
|----|--------------------------|-----|------------------------|
|1111|HKJJBJHVHG66456456FXXFFCGF|ABC11|63ygdydshbhgvdyw3et7edgu|
|----|--------------------------|-----|------------------------|

如果我将初始输入数据帧转换为 JSON().collectAsList(),那么它看起来像:

[{"UUID":"1111","PID":"1234567891011","DEVID":"ABC11","FIRSTNAME":"JOHN"}, {"UUID":"2222","PID":"9876543256827","DEVID":"ABC22","FIRSTNAME":"HARRY"}]

但这不起作用,因为 Rest API 需要以某种格式输入,如上所述。 请帮忙。

【问题讨论】:

    标签: json apache-spark apache-spark-sql apache-spark-dataset


    【解决方案1】:

    对于上述情况,我假设数据集已按 Spark 工作人员的数量进行分区,并且是 Row(数据框)的通用数据集,则可以采用以下机制。

    1. 将具有所需属性的类定义为数据容器
    2. 将数据集内容作为List(如果是数据集则采用takeAsList方法,refer
    3. 创建和填充数据容器的对象(并以以后识别它们的方式存储,您必须使用解密的数据重新填充它们)
    4. 使用 Jackson (refer) 将列表序列化为 JSON 数组 第 4 步和第 5 步可以与 Jackson 自定义序列化程序 refer example 结合使用
    5. 进行 REST 调用并重新填充数据容器对象(在使用 Jackson 反序列化响应之后)
    6. 创建数据框 (an example)
    7. 处理数据框(行数据集)

    注意:您提供的 JSON 结构似乎不正确,JSON 数组为 [{},{},{}]


    在您的情况下,给定请求 JSON 的格式,行的直接转换将不起作用,如第 1 点所述,制作一组模型类,您可以考虑以下模型类。

    package org.test.json;
    
    import java.util.List;
    
    public class RequestModel {
    
    protected ApplicationInfo applicationInfo;
    protected List<RequestData> requestData;
    
    public ApplicationInfo getApplicationInfo() {return applicationInfo;}
    public void setApplicationInfo(ApplicationInfo applicationInfo) {this.applicationInfo = applicationInfo;}
    
    public List<RequestData> getRequestData() {return requestData;}
    public void setRequestData(List<RequestData> requestData) {this.requestData = requestData;}
    
    }//class closing
    
    
    
    
    package org.test.json;
    
    public class ApplicationInfo {
    
    protected String appId;
    
    public String getAppId() {return appId;}
    public void setAppId(String appId) {this.appId = appId;}
    
    }//class closing
    
    
    
    
    package org.test.json;
    
    public class RequestData {
    
    protected String secureData;
    protected String secureDataType;
    protected int index;
    
    public String getSecureData() {return secureData;}
    public void setSecureData(String secureData) {this.secureData = secureData;}
    
    public String getSecureDataType() {return secureDataType;}
    public void setSecureDataType(String secureDataType) {this.secureDataType = secureDataType;}
    
    public int getIndex() {return index;}
    public void setIndex(int index) {this.index = index;}
    
    }//class closing
    

    处理从数据框中获得的列表并填充模型类,然后使用 Jackson 转换以获取请求 JSON。


    下面应该做你要找的,不要直接运行这个,数据集为空

            //Do not run this, will generate NullPointer, for example only
        Dataset<Row> ds=null;
        List<Row> rows=ds.collectAsList();
    
        RequestModel request=new RequestModel();
    
        //Set application id
        ApplicationInfo appInfo=new ApplicationInfo();
        appInfo.setAppId("some id");
        request.setApplicationInfo(appInfo);
    
        List<RequestData> reqData=new ArrayList<>();
        for(int i=0;i<rows.size();i++) {
    
            //Incrementally generated for each row
            int index=i;
    
            Row r=rows.get(i);
            int rowLength=r.size();
    
            for(int j=0;j<rowLength;j++) {
    
                RequestData dataElement=new RequestData();
                dataElement.setIndex(index);
    
                switch(j) {
    
                    case 1:{dataElement.setSecureData(r.getString(j));dataElement.setSecureDataType("PID");break;}
                    case 3:{dataElement.setSecureDataType(r.getString(j));dataElement.setSecureDataType("FIRSTNAME");break;}
                    default:{break;}
    
                }//switch closing
    
                reqData.add(dataElement);
    
            }//for closing
    
        }//for closing
    

    【讨论】:

    • 根据我的要求编辑了 Qs。请看一看。
    • 请查看我的答案部分,我已更新代码,但列表已被覆盖
    • 添加了填充数据的循环。
    • 这不起作用,因为我没有阅读所有列,我只想阅读 4 列中的 2 列。我的第一个和第二个 cols 不一定会有 PID 和 FIRSTNAME。此外,您不会在任何地方将 reqData 添加到 request(RequestModel)
    • 我在第二个 for 循环结束之前添加了该行。 request.setRequestData(reqData);然后打印出结果: for(RequestData reqD:request.getRequestData()){ System.out.println( reqD.getSecureData()+" "+reqD.getSecureDataType()+" "+reqD.getIndex());结果: null null 0 1234567891011 PID 0 null null 0 null FIRSTNAME 0 null null 1 9876543256827 PID 1 null null 1 null FIRSTNAME 1
    猜你喜欢
    • 2018-09-15
    • 2018-07-13
    • 2020-04-12
    • 2020-09-02
    • 2020-02-29
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    相关资源
    最近更新 更多