मैं इसे और अधिक प्रबंधनीय बनाने के लिए अपने जेसन डेटा को डेटाफ्रेम में परिवर्तित करना चाहता हूं।

जावा में डेटा प्राप्त करने का आदेश

Dataset<Row> df = spark.read()
   .option("multiline",true)
   .option("mode", "PERMISSIVE")
   .json("hdfs://hd-master:9820/houseInformation.txt");

डेटा

{
 "House1": {
   "House_Id": "1",
   "Cover": "1.000",
   "HouseType": "bungalow",
   "Facing": "South",
   "Region": "YVR",
   "Ru": "1",
   "HVAC": [
     "FAGF",
     "FPG",
     "HP"
   ]
 },
 "House2" : {...},
 "House3" : {...},
}

यदि यह संभव है तो मैं "हाउस 1" कुंजी को हटाना चाहता हूं और फिर शेष डेटा को डीएफ में परिवर्तित करना चाहता हूं। नहीं तो भी ठीक है।

लेकिन आदर्श रूप से ऐसा कुछ मेरा वांछित आउटपुट है

HouseName  House_Id  Cover   HouseType Facing Region Ru HVAC
 House1       1     1.000     bungalow  South   YVR   1  []   

स्कीमा

root
 |-- House1: struct (nullable = true)
 |    |-- Cover: string (nullable = true)
 |    |-- Facing: string (nullable = true)
 |    |-- HVAC: array (nullable = true)
 |    |    |-- element: string (containsNull = true)
 |    |-- HouseType: string (nullable = true)
 |    |-- House_Id: string (nullable = true)
 |    |-- Region: string (nullable = true)
 |    |-- Ru: string (nullable = true)

बस छपाई

df.select(functions.col("House1")).show(false);

इसे लौटाता है

+----------------------------------------------------+
|House1                                              |
+----------------------------------------------------+
|[1.000, South, [FAGF, FPG, HP], bungalow, 1, YVR, 1]|
+----------------------------------------------------+
0
astronik 16 पद 2020, 00:51

4 जवाब

सबसे बढ़िया उत्तर

आपकी इनपुट जोंस फाइल jsonlines फॉर्मेट में होनी चाहिए (https://jsonlines.org/) जबकि यह सिंगल जोंस है। दस्तावेज़।

यदि इन सभी "हाउस" तत्वों की एक ही कुंजी थी और यदि फ़ाइल jsonlines प्रारूप में थी, तो वे स्वचालित रूप से आपके डेटाफ़्रेम में अलग-अलग पंक्तियाँ होंगी। लेकिन यहां की चाबियां अलग हैं यानी हाउस 1, हाउस 2 आदि और इसलिए इसे सिंगल रिकॉर्ड के रूप में देखा जाता है। "घरों" की एक मनमानी संख्या है, लेकिन प्रत्येक की एक अलग कुंजी है और इसलिए उन्हें अलग-अलग कॉलम के रूप में माना जाता है।

यदि आप अपने वांछित परिणाम को प्राप्त करने के लिए जटिल परिवर्तन लिखते हैं, तो यह कुशल नहीं होगा। एक एकल जोंस रिकॉर्ड चिंगारी द्वारा समानांतर नहीं होने जा रहा है। सभी कार्य करने वाला एक एकल निष्पादक होगा और आपके डेटाफ़्रेम में मनमाने ढंग से बड़ी संख्या में कॉलम होंगे। आप इस उपयोग के मामले के लिए स्पार्क का उपयोग भी नहीं कर सकते हैं।

इसलिए, आईएमओ इसे ठीक करने का अधिक समझदार तरीका आपके स्रोत दस्तावेज़ को ठीक करना होगा। इसका मतलब यह हो सकता है कि आपकी स्रोत फ़ाइल को jsonlines में गुप्त करने के लिए संभवतः पूर्व-संसाधित किया जा रहा है।

4
sparker 16 पद 2020, 17:42

स्कैला का उपयोग करना

<मजबूत>1. हाउस JSON डेटा पढ़ना। कृपया ध्यान दें कि, मैं सिंगल लाइन में एक json इनपुट रो दे रहा हूं

{ "House1": { "House_Id": "1", "Cover": "1.000", "HouseType": "bungalow", "Facing": "South", "Region": "YVR", "Ru": "1", "HVAC": [ "FAGF", "FPG", "HP" ] } }
{ "House2": { "House_Id": "2", "Cover": "1.000", "HouseType": "bungalow", "Facing": "North", "Region": "YVR", "Ru": "1", "HVAC": [ "FAGF", "FPG", "HP" ] } }

कोड

val houseDS = spark.read.json("<JSON_FILE_PATH>");
houseDS.printSchema
root
 |-- House1: struct (nullable = true)
 |    |-- Cover: string (nullable = true)
 |    |-- Facing: string (nullable = true)
 |    |-- HVAC: array (nullable = true)
 |    |    |-- element: string (containsNull = true)
 |    |-- HouseType: string (nullable = true)
 |    |-- House_Id: string (nullable = true)
 |    |-- Region: string (nullable = true)
 |    |-- Ru: string (nullable = true)
 |-- House2: struct (nullable = true)
 |    |-- Cover: string (nullable = true)
 |    |-- Facing: string (nullable = true)
 |    |-- HVAC: array (nullable = true)
 |    |    |-- element: string (containsNull = true)
 |    |-- HouseType: string (nullable = true)
 |    |-- House_Id: string (nullable = true)
 |    |-- Region: string (nullable = true)
 |    |-- Ru: string (nullable = true)

houseDS.show(false)
+----------------------------------------------------+----------------------------------------------------+
|House1                                              |House2                                              |
+----------------------------------------------------+----------------------------------------------------+
|[1.000, South, [FAGF, FPG, HP], bungalow, 1, YVR, 1]|null                                                |
|null                                                |[1.000, North, [FAGF, FPG, HP], bungalow, 2, YVR, 1]|
+----------------------------------------------------+----------------------------------------------------+

<मजबूत>2. हम कई कॉलमों को पंक्तियों में अलग करने के लिए stack() फ़ंक्शन का उपयोग कर रहे हैं। यहाँ stack फ़ंक्शन सिंटैक्स है: stack(n, expr1, ..., exprk) - expr1, ..., exprk को n पंक्तियों में अलग करता है।

val houseDS2 = houseDS.select(expr("stack(2,House1, 'House1', House2, 'House2') as (house,HouseName)")).na.drop
houseDS2.printSchema
root
 |-- house: struct (nullable = true)
 |    |-- Cover: string (nullable = true)
 |    |-- Facing: string (nullable = true)
 |    |-- HVAC: array (nullable = true)
 |    |    |-- element: string (containsNull = true)
 |    |-- HouseType: string (nullable = true)
 |    |-- House_Id: string (nullable = true)
 |    |-- Region: string (nullable = true)
 |    |-- Ru: string (nullable = true)
 |-- HouseName: string (nullable = true)

<मजबूत>3. फिर ऊपर से सभी आवश्यक कॉलमों का चयन करना houseDS2 डेटासेट

val finalHouseDS = houseDS2.select("HouseName","house.House_Id","house.Cover","house.HouseType","house.Facing","house.Region","house.Ru","house.HVAC")
finalHouseDS.show(false)

आपका अपेक्षित आउटपुट

+---------+--------+-----+---------+------+------+---+---------------+
|HouseName|House_Id|Cover|HouseType|Facing|Region|Ru |HVAC           |
+---------+--------+-----+---------+------+------+---+---------------+
|House1   |1       |1.000|bungalow |South |YVR   |1  |[FAGF, FPG, HP]|
|House2   |2       |1.000|bungalow |North |YVR   |1  |[FAGF, FPG, HP]|
+---------+--------+-----+---------+------+------+---+---------------+

आप जावा में इसी तरह लागू कर सकते हैं। कृपया मुझे बताएं कि क्या आपको बड़े डेटासेट के लिए किसी प्रदर्शन समस्या का सामना करना पड़ता है।

जावा का उपयोग करना

import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.functions.*;

public class ParseJson {
    public static void main(String[] args) {
        System.setProperty("hadoop.home.dir", "D:\\Software\\Hadoop");

        SparkSession spark = SparkSession
                .builder()
                .appName("Testing")
                .master("local[*]")
                .getOrCreate();
        // Read json data

        Dataset<Row> houseDS = spark.read().json("<JSON_FILE_PATH>");
        houseDS.printSchema();
        Dataset<Row> houseDS2 = houseDS.selectExpr("stack(2,House1, 'House1', House2, 'House2') as (house,HouseName)").na().drop();
        houseDS2.printSchema();
        Dataset<Row> finalHouseDS = houseDS2.select("HouseName","house.House_Id","house.Cover","house.HouseType","house.Facing","house.Region","house.Ru","house.HVAC");
        finalHouseDS.show(false);

    }
}

2
Vijay_Shinde 18 पद 2020, 12:53

चूंकि House1 कॉलम struct प्रकार का है struct से सभी कॉलम निकालने के लिए House1.* टाइप करें।

नीचे दिए गए कोड का प्रयास करें।

df
.select(functions.col("House1.*"))
.show(false)

2
Srinivas 16 पद 2020, 17:01

आप किसी संरचना के सभी तत्वों का चयन करने और स्तंभों में विस्तार करने के लिए तारांकन चिह्न का उपयोग कर सकते हैं:

Dataset<Row> df2 = df.select("House1.*")

df2.show(false)
+-----+------+---------------+---------+--------+------+---+
|Cover|Facing|HVAC           |HouseType|House_Id|Region|Ru |
+-----+------+---------------+---------+--------+------+---+
|1.000|South |[FAGF, FPG, HP]|bungalow |1       |YVR   |1  |
+-----+------+---------------+---------+--------+------+---+
1
mck 16 पद 2020, 10:43