Как преобразовать один столбец (тип UDO) в несколько столбцов в Spark [duplicate]

x скрыт во время наследования. Вы можете показывать через:

template <typename T>
class derived : public base<T> {

public:
    using base<T>::x;             // added "using" statement
    int f() { return x; }
};
3
задан Jonathan Leffler 23 November 2015 в 20:38
поделиться

1 ответ

Вы получаете эти ошибки, потому что схема, определенная sqlType, никогда не отображается и не предназначена для прямого доступа. Он просто предоставляет способ выражения сложных типов данных с использованием собственных типов Spark SQL.

Вы можете получить доступ к отдельным атрибутам с помощью UDF, но сначала покажите, что внутренняя структура действительно не отображается:

dataFrame.printSchema
// root
//  |-- person_id: integer (nullable = true)
//  |-- person: mockperso (nullable = true)

Для создания UDF нужны функции, которые принимают в качестве аргумента объект типа, представленного данным UDT:

import org.apache.spark.sql.functions.udf

val getFirstName = (person: MockPerson) => person.getFirstName
val getLastName = (person: MockPerson) => person.getLastName
val getAge = (person: MockPerson) => person.getAge

, который можно обернуть с помощью функции udf:

val getFirstNameUDF = udf(getFirstName)
val getLastNameUDF = udf(getLastName)
val getAgeUDF = udf(getAge)

dataFrame.select(
  getFirstNameUDF($"person").alias("first_name"),
  getLastNameUDF($"person").alias("last_name"),
  getAgeUDF($"person").alias("age")
).show()

// +----------+---------+---+
// |first_name|last_name|age|
// +----------+---------+---+
// |    First1|    Last1|  1|
// |    First2|    Last2|  2|
// +----------+---------+---+

Чтобы использовать их с необработанным SQL, у вас есть функции регистрации через SQLContext:

sqlContext.udf.register("first_name", getFirstName)
sqlContext.udf.register("last_name", getLastName)
sqlContext.udf.register("age", getAge)

sqlContext.sql("""
  SELECT first_name(person) AS first_name, last_name(person) AS last_name
  FROM person
  WHERE age(person) < 100""").show

// +----------+---------+
// |first_name|last_name|
// +----------+---------+
// |    First1|    Last1|
// |    First2|    Last2|
// +----------+---------+

К сожалению, он поставляется с прикрепленной ценой. Прежде всего, для каждой операции требуется десериализация. Это также существенно ограничивает способы оптимизации запроса. В частности, для любой операции join в одном из этих полей требуется декартово произведение.

На практике, если вы хотите кодировать сложную структуру, которая содержит атрибуты, которые могут быть выражены с помощью встроенных типов, лучше использовать StructType:

case class Person(first_name: String, last_name: String, age: Int)

val df = sc.parallelize(
  (1 to 2).map(i => (i, Person(s"First$i", s"Last$i", i)))).toDF("id", "person")

df.printSchema

// root
//  |-- id: integer (nullable = false)
//  |-- person: struct (nullable = true)
//  |    |-- first_name: string (nullable = true)
//  |    |-- last_name: string (nullable = true)
//  |    |-- age: integer (nullable = false)

df
  .where($"person.age" < 100)
  .select($"person.first_name", $"person.last_name")
  .show

// +----------+---------+
// |first_name|last_name|
// +----------+---------+
// |    First1|    Last1|
// |    First2|    Last2|
// +----------+---------+

и зарезервировать UDT для фактических расширений типа, подобных встроенным VectorUDT, или вещам, которые могут извлечь выгоду из определенного представления , как перечисления .

3
ответ дан Community 17 August 2018 в 16:56
поделиться
  • 1
    Переполнение стека не позволит мне помещать здесь большую часть комментария, поэтому я собираюсь отредактировать исходный пост. Я пытаюсь создать UDT, как описано в технической документации Spark SQL, раздел 4.4.2 – andygrove 17 November 2015 в 17:41
  • 2
    Мой ответ все тот же. Если вы хотите использовать атрибуты, вы должны использовать UDF. – zero323 17 November 2015 в 17:55
  • 3
    @ zero323 Хороший и аккуратный ответ! Я до сих пор не использую UDT или UDF, но решение кажется мне очень разумным. ;) – eliasah 18 November 2015 в 10:13
  • 4
    Спасибо, @eliasah. – zero323 18 November 2015 в 11:46
  • 5
    @andygrove Насколько я могу судить о том, что в документации Spark SQL ничего не говорится о том, что вы можете напрямую обращаться к внутреннему представлению. Напротив, он описывает UDF как метод доступа к UDT. – zero323 24 December 2015 в 12:41
Другие вопросы по тегам:

Похожие вопросы: