Scala - 特征中的模板方法模式
Posted
技术标签:
【中文标题】Scala - 特征中的模板方法模式【英文标题】:Scala - template method pattern in a trait 【发布时间】:2019-07-23 10:54:36 【问题描述】:我正在 Scala 中实现模板方法模式。这个想法是该方法返回一个Dataset[Metric]
。
但是当我将enrichedMetrics 转换为DataSet enrichedMetrics.as[Metric]
时,我必须使用implicits 来将记录映射到指定的类型。这意味着将 SparkSession 传递给MetricsProcessor
,这对我来说似乎不是最好的解决方案。
我现在看到的解决方案是将spark: SparkSession
作为参数传递给模板方法。然后在模板方法中导入 spark.implicits._。
在这种情况下,有没有更合适的方式来实现模板方法模式?
trait MetricsProcessor
// Template method
def parseMetrics(startDate: Date, endDate: Date, metricId: Long): Dataset[Metric] =
val metricsFromSource: DataFrame = queryMetrics(startDate, endDate)
val enrichedMetrics = enrichMetrics(metricsFromSource, metricId)
enrichedMetrics.as[Metric] <--- //requires spark.implicits
// abstract method
def queryMetrics(startDate: Date, endDate: Date): DataFrame
def enrichMetrics(metricsDf: DataFrame, metricId: Long): DataFrame =
/*Default implementation*/
【问题讨论】:
实际上你不需要spark.implicits._
,而只是它带来的一个隐含含义,一个Encoder[Metrics]。您可能只要求将其作为方法的隐式参数。此外,如果Metrics
是一个具体的案例类,您可以使用org.apache.spark.sql.Encoders.product
辅助方法自己创建Encoder。 (我可能有错别字,但我希望这可以帮助你).
@LuisMiguelMejíaSuárez 你能举个例子吗?
如果 Metric 是用户无法指定的类型参数,则 def parseMetrics(...)(implicit encoder: Encoder[Metric]): Dataset[Metric]
(其中的点是您的常规参数)。 - 如果 Metric 是一个具体的案例类,则为 MetricProcessor 创建一个伴随对象,并将其放在那里 implicit val metricEncoder: Encoder[Metric] = Encoders.product
& 要么放在特征的主体上,要么放在方法添加import MetricProcessor._
- 顺便说一句,我会把这个方法定为最终的。
【参考方案1】:
您在此处缺少您的类型 Metric
的 Encoder
,这是 spark 无法隐式找到的,对于 String
、Int
等常见类型,spark 具有隐式编码器。
此外,如果源类型和目标类型中的列不同,则不能对数据框执行简单的.as
。我会在这里做一些假设。
对于case class
指标
case class Metric( ??? )
parseMetrics
中的行将变为,
选项 1 - 显式传递编码器
enrichedMetrics.map(row => Metric( ??? ))(Encoders.product[Metric])
选项 2 - 隐式传递编码器
implicit val enc : Encoder[Metric] = Encoders.product[Metric]
enrichedMetrics.map(row => Metric( ??? ))
请注意,正如其中一个 cmets 所指出的,如果您的 parseMetric
方法始终返回 Dataset[Metric]
,您可以将隐式编码器添加到特征主体。
希望这会有所帮助。
【讨论】:
以上是关于Scala - 特征中的模板方法模式的主要内容,如果未能解决你的问题,请参考以下文章