Как я могу объединить два фрейма данных и преобразовать столбцы во вложенный тип данных, содержащий значения из обоих фреймов в pyspark 2.4.3? - PullRequest
0 голосов
/ 05 июля 2019

Я использую pyspark 2.4.3 с python 2

Как объединить два кадра данных и объединить столбцы, чтобы отразить их источники во вложенной структуре?

Я создал схему для применения к каждому столбцу. Но я не уверен, как его применить, поскольку для этого требуется информация из другого столбца.

схема данных 1 и 2:

root
  |-- id: long
  |-- tag: string
  |-- container: string
  |-- color: string
  |-- count: long

входные файлы

operator1.json
{"color":"blue","container":"abc123","count":1,"id":1,"tag":"op1"}
{"color":"grey","container":"abc123","count":2,"id":2,"tag":"op1"}
{"color":"red","container":"abc333","count":1,"id":3,"tag":"op1"}

operator2.json
{"color":"","container":"abc123","count":3,"id":1,"tag":"op2"}
{"color":"grey","container":"abc999","count":2,"id":2,"tag":"op2"}
{"color":"red","container":"abc333","count":1,"id":3,"tag":"op2"}


df1:  id | tag | container | color |  count
     -----------------------------------------
       1 | op1 |  abc123   | blue  |    1
       2 | op1 |  abc124   | grey  |    2
       3 | op1 |  abc333   | red   |    1


df1:  id | tag  | container | color |  count
     -----------------------------------------
       1 | op2 |  abc123   |        |    3
       2 | op2 |  abc999   | grey   |    2
       3 | op2 |  abc333   | red    |    1

То, что я хотел бы получить, это фрейм данных, который имеет вложенную структуру для каждого столбца. Ниже приведено описание того, что я пытаюсь получить

+-------------------------------------------------+--------------------------------------------------------------+-------------------------------------------+---+----------+
|color |container |count |id |tags |
+-------------------------------------------------+--------------------------------------------------------------+-------------------------------------------+---+----------+
|[false, [[op1, String, blue], [op2, String, ]], ]|[true, [[op1, String, abc123], [op2, String, abc123]], abc123]|[false, [[op1, Long, 1], [op2, Long, 3]], ]|1 |[op1, op2]|
+-------------------------------------------------+--------------------------------------------------------------+-------------------------------------------+---+----------+

root
|-- color: struct (nullable = true)
| |-- match: boolean (nullable = true)
| |-- tags: array (nullable = true)
| | |-- element: struct (containsNull = true)
| | | |-- tag: string (nullable = true)
| | | |-- type: string (nullable = true)
| | | |-- value: string (nullable = true)
| |-- value: string (nullable = true)
|-- container: struct (nullable = true)
| |-- match: boolean (nullable = true)
| |-- tags: array (nullable = true)
| | |-- element: struct (containsNull = true)
| | | |-- tag: string (nullable = true)
| | | |-- type: string (nullable = true)
| | | |-- value: string (nullable = true)
| |-- value: string (nullable = true)
|-- count: struct (nullable = true)
| |-- match: boolean (nullable = true)
| |-- tags: array (nullable = true)
| | |-- element: struct (containsNull = true)
| | | |-- tag: string (nullable = true)
| | | |-- type: string (nullable = true)
| | | |-- value: string (nullable = true)
| |-- value: string (nullable = true)
|-- id: long (nullable = true)
|-- tags: array (nullable = true)
| |-- element: string (containsNull = true)

Не очень хорошо владеет Python. Но у меня есть основы, где я могу как-то обойтись. Я пытался объединить два кадра данных по идентификатору, но не нашел способа объединить соответствующие столбцы в один.

Например.

new_col_schema = t.StructType([ t.StructField('match', t.BooleanType(), True),
                                t.StructField('value', t.StringType(), True),
                                t.StructField('tags', t.ArrayType(
                                  t.StructType([
                                    t.StructField('tag', t.StringType(), True),
                                    t.StructField('value', t.StringType(), True),
                                    t.StructField('type', t.StringType(), True)
                                  ])
                                ))
                             ])


def make_nested(o1, v1, o2, v2):
  match = False
  value = ''
  if v1 == v2:
    match=True
    value = v1

  return {'match': match, 'value': value, 'tags', [{'tag': o1, 'value': v1, 'type': type(v1)},{'tag':o2, 'value':v2, 'type':type(v2)}]}

nestudf = f.udf(make_nested, t.StructType())

df1 = sqlContext.read.json('/data/op1.json')
df2 = sqlContext.read.json('/data/op2.json')

df = df1.join(df2, ['id'])
# see if I can get one column to be nested
df = df.withColumn('

Это создаст кадр данных с дублирующимися столбцами, оставляя то, что я ищу, доступным, но недоступным.

df = df.withColumn('container', nestudf(df1.op, df1.container, df2.op, df2.container))

Но, как я понял. Я думаю, что единственная причина, по которой дубликаты столбцов после объединения доступны. Это так можно уронить. Кроме этого, у меня не было доступа к ним или их значениям для моей функции.

Я надеюсь, что смогу вложить столбцы окончательного фрейма данных со связанной с ними информацией о столбцах, связанной с их идентификатором. Фрейм данных будет записан в файл json, поэтому он должен выглядеть примерно так:

{"id":1,
 "tags" : ["op1", "op2"],
 "container" : {
              "match": true,
              "value": "abc123",
              "tags" : [
                        {"tag": "op1",
                         "value": "abc123",
                         "type" : "String"
                        },
                        {"tag": "op2",
                         "value": "abc123",
                         "type" : "String"
                        }
                       ]
               },
 "color" : {
              "match": false,
              "value": "",
              "tags" : [
                        {"tag": "op1",
                         "value": "blue",
                         "type" : "String"
                        },
                        {"tag": "op2",
                         "value": "",
                         "type" : "String"
                        }
                       ]
               },
 "count" : {
              "match": false,
              "value": "",
              "tags" : [
                        {"tag": "op1",
                         "value": "1",
                         "type" : "Integer"
                        },
                        {"tag": "op2",
                         "value": "3",
                         "type" : "Integer"
                        }
                       ]
               }
},
{'id': 2, ......
...