Преобразовать набор данных Dataframe <Row>в формат строкового типа JSON для определенных столбцов и преобразовать строку JSON обратно в датафрейм. - PullRequest
0 голосов
/ 20 октября 2019

У меня есть датафрейм. Мне нужно вызывать Rest API для каждой записи.

Допустим, что Dataframe выглядит следующим образом:

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

Строка запроса JSON для первой строки должна выглядеть следующим образом (Примечание: json созданна 2 столбца, а не на все), поскольку для вызова API Rest требуется ввод в следующем формате:

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

Значение ключа индекса необходимо генерировать на лету, используя для каждого инкрементный счетчикrow.

Затем мне нужно вызвать API Rest, отправив вышеуказанный 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 требует ввода в определенном формате, упомянутом выше. Пожалуйста, помогите.

Ответы [ 2 ]

1 голос
/ 20 октября 2019

Для вышеизложенного, я предполагаю, что набор данных был разбит на несколько рабочих мест Spark, и это общий набор данных Row (фрейм данных), тогда можно использовать приведенный ниже механизм.

  1. Определить класс с необходимыми атрибутами в качестве контейнера данных
  2. Принять содержимое набора данных в качестве списка (метод takeAsList, если набор данных, относится )
  3. Создатьи заполнить объекты вашего контейнера данных (и сохранить их таким образом, чтобы позже их можно было идентифицировать, вам придется заново заполнить их расшифрованными данными)
  4. Сериализовать список в массив JSON с Джексоном (см. )) Шаг 4 и 5 можно комбинировать с пользовательским сериализатором Джексона см. Пример
  5. Выполнить вызов REST и повторно заполнить объекты контейнера данных (после десериализации ответа с Джексоном)
  6. Создание фрейма данных ( пример )
  7. Обработка фрейма данных (набор данных строк)

ПРИМЕЧАНИЕ. Структура JSON у вас есть provided, кажется, не является правильным, массив 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

Обработать список, полученный из фрейма данных, и заполнить классы модели, а затем преобразовать с помощью Джексона, чтобы получитьзапрос 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
0 голосов
/ 23 октября 2019

Я обновил свой код, чтобы исправить цикл for. Теперь он дает правильный результат.

Но как сгладить строку ответа и извлечь значения PID и FIRSTNAME из объекта ResponseModel.

        List<Row> list = df.collectAsList();
        List<Row> responseList = new ArrayList<>();

            for(Row r: list) {
                            ObjectMapper objectMapper = new ObjectMapper();
                objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

String responseStr = "{\"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}}";
                ResponseModel responseModel = objectMapper.readValue(responseStr, ResponseModel.class);
               responseList.add(RowFactory.create((String) r.getAs("UUID"),(String) r.getAs("DEVID")));
            Dataset<Row> test= spark.createDataFrame(responseList,schema);

}

Для целей тестирования я жестко закодировал строку ответавнутри цикла.

Как извлечь и добавить значения PID и FIRSTNAME в приведенный выше список responseList для создания кадра данных (UUID, PID, DEVID, FIRSTNAME). Здесь

ResponseModel class has- ResultCounts, List<ResponseData>, String responseCode, String responseMessage
ResponseData class has- String resultCode, String secureData, String secureDataType, int index

Пожалуйста, помогите

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...