将具有JSON对象数组的Spark数据框列转换为多行

时间:2018-10-31 19:12:32

标签: apache-spark apache-spark-sql spark-streaming

我有一个流式JSON数据,其结构可以用下面的case类描述

    package edge;

    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import javax.swing.ImageIcon;
    import javax.swing.Timer;

public class Dungeon1 extends javax.swing.JPanel implements ActionListener, KeyListener {

    private static final long serialVersionUID = 1L;

    Timer timer = new Timer(1, this);
    Player player = new Player();
    DungeonBackground db = new DungeonBackground(0, 0);
    Enemy e1 = new Enemy(200, 200);

    /**
     * Creates new form Dungeon1
     */
    public Dungeon1() {
        initComponents();
        setSize(1366, 706);
        timer.start();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();

        setBackground(new java.awt.Color(0, 0, 0));
        setRequestFocusEnabled(false);

        jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edge/Dundeon 1 - 1.jpg"))); // NOI18N
        jLabel1.setText("\n");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 707, Short.MAX_VALUE)
        );
    }// </editor-fold>                        

    public void Paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;

        ImageIcon img = new ImageIcon("Dundeon 1 - 1.jpg");
        IMG = img.getImage();
        g2d.drawImage(IMG, 0, 0, null);

        if (firstform == true && secondform == false && thirdform == false) {
            ImageIcon imageIcon2 = new ImageIcon("enemy1.bmp");
            g2d.drawImage(imageIcon2.getImage(), e1.getX(), e1.getY(), this);
        } else if (secondform == true && firstform == false && thirdform == false) {
            ImageIcon imageIcon3 = new ImageIcon("enemy1-1.bmp");
            g2d.drawImage(imageIcon3.getImage(), e1.getX(), e1.getY(), this);
            secondform = false;
            thirdform = true;
            firstform = false;
        } else if (thirdform == true && firstform == false && secondform == false) {
            ImageIcon imageIcon4 = new ImageIcon("enemy1-2.bmp");
            g2d.drawImage(imageIcon4.getImage(), e1.getX(), e1.getY(), this);
            firstform = true;
            secondform = false;
            thirdform = false;
            RageGUI rg1 = new RageGUI();
            rg1.setVisible(true);
        }
        ImageIcon imageIcon = new ImageIcon("characterfinal.jpg");
        g2d.drawImage(imageIcon.getImage(), player.getX(), player.getY(), this);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e1.getX() == (player.getX() + 190) && e1.getY() == player.getY()
                || e1.getY() == (player.getY() - 190) && e1.getX() == player.getX()) {
            firstform = false;
            secondform = true;
        }
        if (e1.getX() == (player.getX() - 190) && e1.getY() == player.getY()) {
            firstform = false;
            secondform = true;
        }
        if (e1.getY() == (player.getY() - 190) && e1.getX() == player.getX()) {
            firstform = false;
            secondform = true;
        }
        while (e1isalive == true) {
            double rdn = Math.random();
            if (rdn <= 0.25) {
                e1.MoveSequence1();
            }
            if (rdn <= 0.5) {
                e1.MoveSequence2();
            }
            if (rdn <= 0.75) {
                e1.MoveSequence3();
            }
            if (rdn <= 1) {
                e1.MoveSequence4();
            }

        }
        if (player.getX() == 87 && player.getY() == 81 && player.getDirection() == 4) {
            player.MoveLeft();
            player.MoveDown();
        }
        if (player.getX() == 380 && player.getY() == 500 && player.getDirection() == 4) {
            player.MoveLeft();
        }
        if (player.getX() == 91 && player.getY() == 520 && player.getDirection() == 4) {
            player.MoveLeft();
        }
        if (player.getX() == 85 && player.getY()== 355 && player.getDirection() == 4) {
            player.MoveLeft();
        } 
        if (player.getX() == 284 && player.getY() == 399 && player.getDirection() == 3) {
            player.MoveRight();
        }
        if (player.getX() == 284 && player.getY() == 399 && player.getDirection() == 1) {
            player.MoveDown();
        }
        if (player.getX() == 649 && player.getY() == 515 && player.getDirection() == 3) {
            player.MoveRight();
        }
        if (player.getX() == 811 && player.getY() == 243 && player.getDirection() == 2) {
            player.MoveUp();
        }
        if (player.getX() == 811 && player.getY() == 243 && player.getDirection() == 1) {
            player.MoveDown();
        }
        if (player.getX() == 671 && player.getY() == 365 && player.getDirection() == 4) {
            player.MoveLeft();
        }
        if (player.getX() == 940 && player.getY() == 350 && player.getDirection() == 3) {
            player.MoveLeft();
        }
        if (player.getX() == 812 && player.getY() == 513 && player.getDirection() == 1) {
            player.MoveDown();
        }
        if (player.getX() == 140 && player.getY() == 150 && player.getDirection() == 4) {
            player.MoveLeft();
        }
        if (player.getX() == 900 && player.getY() == 600 && player.getDirection() == 3 ) {
            player.MoveRight();
        }
        if (player.getX() == 1159 && player.getY() == 461 && player.getDirection() == 3 ) {
            player.MoveRight();
        }
        if (player.getX() == 660 && player.getY() == 110 && player.getDirection() == 4 ) {
            player.MoveLeft();
        }
        if (player.getX() == 995 && player.getY() == 285 && player.getDirection() == 1) {
            player.MoveDown();
        }
        if (player.getX() == 1160 && player.getY() == 120 && player.getDirection() == 3 ) {
            player.MoveRight();
        }
        if (player.getX() == 393 && player.getY() == 634 && player.getDirection() == 4) {

            System.out.println("do you want to die???"
                    + " or did you think you found a secret way out of the dungeon??"
                    + " well you are right, you win");
            RageQuitGUI rg = new RageQuitGUI() ;
            rg.setVisible(true) ;
        }
        repaint();
    }

    @Override
    public void keyTyped(KeyEvent ke) {

    }

    @Override
    public void keyPressed(KeyEvent ke) {
         if (ke.getKeyCode() == KeyEvent.VK_W) {
            player.MoveUp();
            System.out.println("w key has been pressed");
        } else if (ke.getKeyCode() == KeyEvent.VK_A) {
            player.MoveLeft();
            System.out.println("a key has been pressed");
        } else if (ke.getKeyCode() == KeyEvent.VK_D) {
            player.MoveRight();
            System.out.println("d key has been pressed");
        } else if (ke.getKeyCode() == KeyEvent.VK_S) {
            player.MoveDown();
            System.out.println("s key has been pressed");
        }
        if (ke.getKeyCode() == KeyEvent.VK_ALT + KeyEvent.VK_F4) {
            RageQuitGUI rg = new RageQuitGUI();
            rg.setVisible(true);
        }
    }

    @Override
    public void keyReleased(KeyEvent ke) {

    }
    boolean e1isalive = true;
    boolean firstform = true;
    boolean secondform = false;
    boolean thirdform = false;
    Image IMG;
//  sometimes the code works and soetimes it doesnt.
    // Variables declaration - do not modify                     
    private javax.swing.JLabel jLabel1;
    // End of variables declaration                   
}

相同的样本数据如下

case class Hello(A: String, B: Array[Map[String, String]])

我想将其转换为

|  A    | B                                        |
|-------|------------------------------------------|
|  ABC  |  [{C:1, D:1}, {C:2, D:4}]                | 
|  XYZ  |  [{C:3, D :6}, {C:9, D:11}, {C:5, D:12}] |

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

不确定最好的方法,但是可以分两步完成。抛开您的案例类,以下内容:

import org.apache.spark.sql.functions._
//case class ComponentPlacement(A: String, B: Array[Map[String, String]])
val df = Seq (
              ("ABC", List(Map("C" -> "1",  "D" -> "2"))),
              ("XYZ", List(Map("C" -> "11", "D" -> "22")))
             ).toDF("A", "B")

val df2 = df.select($"A", explode($"B")).toDF("A", "Bn")

val df3 = df2.select($"A", explode($"Bn")).toDF("A", "B", "C")

val df4 = df3.select($"A", $"B", $"C").groupBy("A").pivot("B").agg(first($"C"))

返回:

+---+---+---+
|  A|  C|  D|
+---+---+---+
|XYZ| 11| 22|
|ABC|  1|  2|
+---+---+---+

答案 1 :(得分:1)

随着问题的发展,我将原来的答案留在那里,这解决了最后一个问题。

  

重要的一点,现在满足以下要求的输入内容:

val df0 = Seq (
            ("ABC", List(Map("C" -> "1", "D" -> "2"), Map("C" -> "3", "D" -> "4"))),
            ("XYZ", List(Map("C" -> "44", "D" -> "55"), Map("C" -> "188", "D" -> "199"), Map("C" -> "88", "D" -> "99")))
              )
             .toDF("A", "B")
  

也可以这样做,但是随后需要对此脚本进行修改,尽管这很简单:

val df0 = Seq (
           ("ABC", List(Map("C" -> "1",  "D" -> "2"))), 
           ("ABC", List(Map("C" -> "44", "D" -> "55"))),
           ("XYZ", List(Map("C" -> "11", "D" -> "22")))
              )
            .toDF("A", "B")
  

然后按照要求的格式进行操作:

val df1 = df0.select($"A", explode($"B")).toDF("A", "Bn")

val df2 = df1.withColumn("SeqNum", monotonically_increasing_id()).toDF("A", "Bn", "SeqNum") 

val df3 = df2.select($"A", explode($"Bn"), $"SeqNum").toDF("A", "B", "C", "SeqNum")

val df4 = df3.withColumn("dummy", concat( $"SeqNum", lit("||"), $"A"))

val df5 = df4.select($"dummy", $"B", $"C").groupBy("dummy").pivot("B").agg(first($"C")) 

val df6 = df5.withColumn("A", substring_index(col("dummy"), "||", -1)).drop("dummy")

df6.show(false)

返回:

+---+---+---+
|C  |D  |A  |
+---+---+---+
|3  |4  |ABC|
|1  |2  |ABC|
|88 |99 |XYZ|
|188|199|XYZ|
|44 |55 |XYZ|
+---+---+---+

您可以对列进行重新排序。