संदर्भ

मेरे द्वारा लिखे गए कई sql प्रश्नों में, मैं खुद को स्पार्क पूर्वनिर्धारित कार्यों को ठीक उसी तरह से मिलाता हूं, जिसके परिणामस्वरूप अक्सर वर्बोज़ और डुप्लिकेट कोड होता है, और मेरी डेवलपर वृत्ति इसे फिर से तैयार करना चाहती है।

तो, मेरा प्रश्न यह है: क्या udfs का उपयोग किए बिना फ़ंक्शन संयोजनों के लिए किसी प्रकार के उपनाम को परिभाषित करने का कोई तरीका है (जो निष्पादन कारणों से बचने के लिए हैं) - लक्ष्य कोड को स्पष्ट करना और सफाई वाला। अनिवार्य रूप से, मैं जो चाहता हूं वह udfs जैसा है, लेकिन प्रदर्शन दंड के बिना। साथ ही, ये फ़ंक्शन spark.sql कॉल में प्रयोग करने योग्य स्पार्क-एसक्यूएल क्वेरी के भीतर से कॉल करने योग्य होना चाहिए।

उदाहरण

उदाहरण के लिए, मान लें कि मेरा व्यावसायिक तर्क कुछ स्ट्रिंग को उलटना है और इसे इस तरह हैश करना है: (कृपया ध्यान दें कि यहां फ़ंक्शन संयोजन अप्रासंगिक है, महत्वपूर्ण यह है कि यह मौजूदा पूर्व-परिभाषित स्पार्क फ़ंक्शंस का कुछ संयोजन है - संभवतः कई उन्हें)

SELECT 
    sha1(reverse(person.name)),
    sha1(reverse(person.some_information)),
    sha1(reverse(person.some_other_information))
    ...
FROM person

udf का उपयोग करने के प्रदर्शन मूल्य का भुगतान किए बिना business फ़ंक्शन घोषित करने का कोई तरीका है, जिससे ऊपर दिए गए कोड को फिर से लिखा जा सकता है:

SELECT 
    business(person.name),
    business(person.some_information),
    business(person.some_other_information)
    ...
FROM person

मैंने स्पार्क दस्तावेज़ीकरण और इस वेबसाइट पर काफी खोज की है और इसे प्राप्त करने का कोई तरीका नहीं मिला है, जो मेरे लिए बहुत अजीब है क्योंकि यह एक बहुत ही प्राकृतिक आवश्यकता की तरह दिखता है, और मुझे समझ में नहीं आता कि आपको इसकी आवश्यकता क्यों है udf को परिभाषित करने और कॉल करने का ब्लैक-बॉक्स मूल्य चुकाएं।

2
Thundzz 27 जुलाई 2019, 18:22

1 उत्तर

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

क्या यूडीएफ का उपयोग करने के प्रदर्शन मूल्य का भुगतान किए बिना व्यावसायिक कार्य घोषित करने का कोई तरीका है?

आपको udf का उपयोग करने की आवश्यकता नहीं है, आप Expression वर्ग का विस्तार कर सकते हैं, या सबसे सरल संचालन के लिए - UnaryExpression। फिर आपको बस कई तरीकों को लागू करना होगा और यहां हम जाते हैं। यह मूल रूप से स्पार्क में एकीकृत है, इसके अलावा कोड जनरेशन जैसी कुछ लाभ सुविधाओं का उपयोग करने देता है।

आपके मामले में business फ़ंक्शन जोड़ना बहुत सीधा है:

def business(column: Column): Column = {
  sha1(reverse(column))
}

स्पार्क.एसक्यूएल कॉल में प्रयोग करने योग्य स्पार्क-एसक्यूएल क्वेरी के भीतर से कॉल करने योग्य होना चाहिए

यह अधिक कठिन है लेकिन प्राप्त करने योग्य है।
आपको कस्टम फ़ंक्शन रजिस्ट्रार बनाने की आवश्यकता है:

import org.apache.spark.sql.catalyst.FunctionIdentifier
import org.apache.spark.sql.catalyst.expressions.Expression 

object FunctionAliasRegistrar {

val funcs: mutable.Map[String, Seq[Column] => Column] = mutable.Map.empty

  def add(name: String, builder: Seq[Column] => Column): this.type = {
    funcs += name -> builder
    this
  }

  def registerAll(spark: SparkSession) = {
    funcs.foreach { case (alias, builder) => {
      def b(children: Seq[Expression]) = builder.apply(children.map(expr => new Column(expr))).expr
      spark.sessionState.functionRegistry.registerFunction(FunctionIdentifier(alias), b)
    }}
  }
}

फिर आप इसे इस प्रकार उपयोग कर सकते हैं:

FunctionAliasRegistrar
  .add("business1", child => lower(reverse(child.head)))
  .add("business2", child => upper(reverse(child.head)))
  .registerAll(spark) 

dataset.createTempView("data")

spark.sql(
  """
    | SELECT business1(name), business2(name) FROM data
    |""".stripMargin)
.show(false)

आउटपुट:

+--------------------+--------------------+
|lower(reverse(name))|upper(reverse(name))|
+--------------------+--------------------+
|sined               |SINED               |
|taram               |TARAM               |
|1taram              |1TARAM              |
|2taram              |2TARAM              |
+--------------------+--------------------+

उम्मीद है ये मदद करेगा।

3
Gelerion 28 जुलाई 2019, 14:38