Генерация нового столбца в Spark SQL или MySQL на основе условия - PullRequest
3 голосов
/ 18 апреля 2020

Создание таблицы:

CREATE TABLE temp (
name varchar(20), 
dep varchar(20));

INSERT INTO temp VALUES 
('a', null), 
('b', null), 
('c', 'b'), 
('d', 'c'), 
('e', 'b'), 
('e', 'd');

Мне нужна помощь сообщества в написании запроса, который генерирует новый столбец, скажем, xyz , который будет иметь значение 1, если dep равно нулю. В противном случае необходимо принять dep для соответствующего имени и добавить 1 к xyz значению столбца.

Например: Здесь c зависит от b , поэтому он должен взять xyz из b , который имеет 1, и добавить 1 к нему, что дает xyz значение c как 2 и т. д.

вывод:

+------+------+-----+
| name |  dep | xyz |
+------+------+-----+
|  a   | null |  1  |
|  b   | null |  1  |
|  c   |  b   |  2  |
|  d   |  c   |  3  |
|  e   |  b   |  2  |
|  e   |  d   |  4  |
+------+------+-----+

Создание таблицы:

create table temp1(name varchar(20), dependency varchar(20));
insert into temp1 values
    ('city', null), ('state', null), ('country', 'city'),
    ('country','state'), ('pin','country'), ('pin','state'),
    ('continent','country'), ('continent','pin'), ('continent','city');

Ожидаемый результат: Здесь последовательность - это новый столбец, который должен быть сгенерирован.

| name     | dependency | sequence |
|----------|------------|----------|
| city     | null       | 1        |
| state    | null       | 1        |
| country  | city       | 2        |
| country  | state      | 2        |
| pin      | country    | 3        |
| pin      | state      | 2        |
| continent| country    | 3        |
| continent| pin        | 4        |
| continent| city       | 2        |

Мой первый вопрос сообществу :) Заранее благодарю людей.

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

@ ревностный ответ, кажется, делает свое дело.

Я могу предложить вам эквивалентный синтаксис pyspark (поскольку pyspark входит в число тегов)

Во-первых, создание вашего фрейма данных

import pyspark.sql.window as psw
import pyspark.sql.functions as psf

​df = spark.createDataFrame([("a",None , 1), ("b", None ,1),
                            ("c","b",2), ("d","c",3),
                            ("e","b",2),("e","d",4)],
                           ['name','dep','xyz'])

df.show(5)

+----+----+---+
|name| dep|xyz|
+----+----+---+
|   a|null|  1|
|   b|null|  1|
|   c|   b|  2|
|   d|   c|  3|
|   e|   b|  2|
+----+----+---+
only showing top 5 rows

Идея состоит в том, чтобы упорядочить по dep: сначала значения Null, а затем вы получите порядок букв. С psf.dense_rank у вас нет пробелов в вашем заказе. Чтобы применить dense_rank в Spark, вам нужна функция Window:

w = psw.Window.orderBy('dep')
df.withColumn("xyz", psf.dense_rank().over(w))
​
df.show(5)
+----+----+---+
|name| dep|xyz|
+----+----+---+
|   a|null|  1|
|   b|null|  1|
|   c|   b|  2|
|   d|   c|  3|
|   e|   b|  2|
+----+----+---+
only showing top 5 rows

Обновление

Для вашего второго вопроса я не видел ни одного шаблона, который бы позволял решение. Вам понадобится ряд psf.when утверждений.

import pyspark.sql.functions as psf

df = spark.createDataFrame([('city', None),('state', None),
                            ('country', 'city'),('country','state'),
                            ('pin','country'),('pin','state'),
                            ('continent','country'),('continent','pin'),
                            ('continent','city')], ['name','type'])

df = df.withColumn("sequence", psf.when(
        ((psf.col('name') == "country" ) & (psf.col('type') == "city")) |
        ((psf.col('name') == "continent") & (psf.col('type') == "city")) |
        ((psf.col('name') == "pin") & (psf.col('type') == "state")) |
        ((psf.col('name') == "country") & (psf.col('type') == "state")),
        2
    ).when(
        ((psf.col('name') == "pin") & (psf.col('type') == "country")) |
        ((psf.col('name') == "continent") & (psf.col('type') == "country"))
  ,
        3
    ).when(
        (psf.col('name') == "continent") & (psf.col('type') == "pin"),
        4        
    ).otherwise(1)
    )

df.show(10)

+---------+-------+--------+
|     name|   type|sequence|
+---------+-------+--------+
|     city|   null|       1|
|    state|   null|       1|
|  country|   city|       2|
|  country|  state|       2|
|      pin|country|       3|
|      pin|  state|       2|
|continent|country|       3|
|continent|    pin|       4|
|continent|   city|       2|
+---------+-------+--------+

Чтобы избежать psf.when

Поскольку в ваших условиях нет явной закономерности, я не вижу других способов сделать это. чем использовать цепочку when или join, которую я сейчас предлагаю

Идея состоит в том, чтобы создать фрейм данных, задающий условие для ваших двух столбцов, а затем объединить его. Решение не проверено.

conditions = spark.createDataFrame([('country', 'city',2),('continent','city',2),
                            ('pin','state',2),('country','state',2),
                            ('pin','country',3),('continent','country',3),
                            ('continent','pin', 4)],
['name','type','sequence'])

df = df.join(psf.broadcast(conditions),
             ['name', 'type'], 'left_outer')
       .fillna(1, subset=['sequence'])

Кстати, я использую psf.broadcast для ускорения слияния, потому что conditions DataFrame должен быть разумного размера.

Если у вас есть Большое количество условий, я думаю, такой подход должен быть предпочтительным. Это сделает ваш код более читабельным

1 голос
/ 18 апреля 2020

Попробуйте, посмотрите на Демо здесь в My SQL 8.0

select
  name,
  dep,
  dense_rank() over (order by dep) as xyz
from myTable
order by
  name, dep

Вывод:

+--------------+
name  dep   xyz
+--------------+
 a  (null)   1
 b  (null)   1
 c    b      2
 d    c      3
 e    b      2
 e    d      4

По второму вопросу вы можете достичь его простой case оператор следующим образом

select
    name,
    type,
    case
    when 
        (name = 'country' and type = 'city') 
        OR (name = 'continent' and type = 'city')
        OR (name = 'pin' and type = 'state')
        OR (name = 'country' and type = 'state') 
    then
        2
    when
        (name = 'pin' and type = 'country')
        OR (name = 'continent' and type = 'country')
    then
        3
    when
        (name = 'continent' and type = 'pin')
    then
        4
    else
        1
    end as ranks
from myTable

Вывод:

+--------------------------+
name        type      ranks
+--------------------------+
city        null        1
state       null        1
country     city        2
country     state       2
pin         country     3
pin         state       2
continent   country     3
continent   pin         4
continent   city        2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...