Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Spark中的UDF工作非常慢_Scala_Apache Spark_Emr_Ua Parser - Fatal编程技术网

Scala Spark中的UDF工作非常慢

Scala Spark中的UDF工作非常慢,scala,apache-spark,emr,ua-parser,Scala,Apache Spark,Emr,Ua Parser,我在spark(在EMR上运行)中有一个UDF,它是用scala编写的,使用scala的uap解析器库(uap scala)从用户代理解析设备。当在小型设备上工作时,它工作正常(5000行),但在大型设备(2M)上运行时,它工作非常缓慢。 我试图收集数据帧来列出并在驱动程序上循环,但速度也很慢,这让我相信UDF是在驱动程序上运行的,而不是在工人上运行的 我如何确定这一点?有人有别的理论吗 如果是这样,为什么会发生这种情况 这是udf代码: def calcDevice(userAgent: St

我在spark(在EMR上运行)中有一个UDF,它是用scala编写的,使用scala的uap解析器库(uap scala)从用户代理解析设备。当在小型设备上工作时,它工作正常(5000行),但在大型设备(2M)上运行时,它工作非常缓慢。 我试图收集数据帧来列出并在驱动程序上循环,但速度也很慢,这让我相信UDF是在驱动程序上运行的,而不是在工人上运行的

  • 我如何确定这一点?有人有别的理论吗
  • 如果是这样,为什么会发生这种情况
  • 这是udf代码:

    def calcDevice(userAgent: String): String = {
    
    val userAgentVal = Option(userAgent).getOrElse("")
    Parser.get.parse(userAgentVal).device.family
    }
    
    val calcDeviceValUDF: UserDefinedFunction = udf(calcDevice _)
    
    用法:

    .withColumn("agentDevice", udfDefinitions.calcDeviceValUDF($"userAgent"))
    
    谢谢
    Nir

    给定的
    解析器.get.parse
    在问题中缺失,只能判断
    udf
    部分

    为了提高性能,您可以删除
    选项

    def calcDevice(userAgent: String): String = {
      val userAgentVal = if(userAgent == null) "" else userAgent
      Parser.get.parse(userAgentVal).device.family
    }
    

    如果问题中缺少
    Parser.get.parse
    ,则只能判断
    udf
    部分

    为了提高性能,您可以删除
    选项

    def calcDevice(userAgent: String): String = {
      val userAgentVal = if(userAgent == null) "" else userAgent
      Parser.get.parse(userAgentVal).device.family
    }
    

    问题在于在UDF itelf中实例化构建器。解决方案是在udf之外创建对象,并在行级别使用它:

    val userAgentAnalyzerUAParser = Parser.get
    
    def calcDevice(userAgent: String): String = {
    
    val userAgentVal = Option(userAgent).getOrElse("")
    userAgentAnalyzerUAParser.parse(userAgentVal).device.family
    }
    
    val calcDeviceValUDF: UserDefinedFunction = udf(calcDevice _)
    

    问题在于在UDF itelf中实例化构建器。解决方案是在udf之外创建对象,并在行级别使用它:

    val userAgentAnalyzerUAParser = Parser.get
    
    def calcDevice(userAgent: String): String = {
    
    val userAgentVal = Option(userAgent).getOrElse("")
    userAgentAnalyzerUAParser.parse(userAgentVal).device.family
    }
    
    val calcDeviceValUDF: UserDefinedFunction = udf(calcDevice _)
    

    我们遇到了Spark jobs被绞死的问题。我们做的另一件事是使用广播变量。在所有的改变之后,这个UDF实际上非常慢,所以你的里程数可能会有所不同。另一个警告是获得SparkSession;我们在数据库中运行,如果SparkSession不可用,那么它将崩溃;如果你需要继续工作,那么你必须处理这个失败案例

    object UDFs extends Serializable {
      val uaParser = SparkSession.getActiveSession.map(_.sparkContext.broadcast(CachingParser.default(100000)))
    
      val parseUserAgent = udf { (userAgent: String) =>
        // We will simply return an empty map if uaParser is None because that would mean
        // there is no active spark session to broadcast the parser.
        //
        // Also if you wrap the potentially null value in an Option and use flatMap and map to
        // add type safety it becomes slower.
        if (userAgent == null || uaParser.isEmpty) {
          Map[String, Map[String, String]]()
        } else {
          val parsed = uaParser.get.value.parse(userAgent)
          Map(
            "browser" -> Map(
              "family"      -> parsed.userAgent.family,
              "major"       -> parsed.userAgent.major.getOrElse(""),
              "minor"       -> parsed.userAgent.minor.getOrElse(""),
              "patch"       -> parsed.userAgent.patch.getOrElse("")
            ),
            "os" -> Map(
              "family"      -> parsed.os.family,
              "major"       -> parsed.os.major.getOrElse(""),
              "minor"       -> parsed.os.minor.getOrElse(""),
              "patch"       -> parsed.os.patch.getOrElse(""),
              "patch-minor" -> parsed.os.patchMinor.getOrElse("")
            ),
            "device" -> Map(
              "family"      -> parsed.device.family,
              "brand"       -> parsed.device.brand.getOrElse(""),
              "model"       -> parsed.device.model.getOrElse("")
            )
          )
        }
      }    
    }
    

    您可能还想玩一下CachingParser的大小。

    我们遇到了同样的问题,Spark jobs被绞死了。我们做的另一件事是使用广播变量。在所有的改变之后,这个UDF实际上非常慢,所以你的里程数可能会有所不同。另一个警告是获得SparkSession;我们在数据库中运行,如果SparkSession不可用,那么它将崩溃;如果你需要继续工作,那么你必须处理这个失败案例

    object UDFs extends Serializable {
      val uaParser = SparkSession.getActiveSession.map(_.sparkContext.broadcast(CachingParser.default(100000)))
    
      val parseUserAgent = udf { (userAgent: String) =>
        // We will simply return an empty map if uaParser is None because that would mean
        // there is no active spark session to broadcast the parser.
        //
        // Also if you wrap the potentially null value in an Option and use flatMap and map to
        // add type safety it becomes slower.
        if (userAgent == null || uaParser.isEmpty) {
          Map[String, Map[String, String]]()
        } else {
          val parsed = uaParser.get.value.parse(userAgent)
          Map(
            "browser" -> Map(
              "family"      -> parsed.userAgent.family,
              "major"       -> parsed.userAgent.major.getOrElse(""),
              "minor"       -> parsed.userAgent.minor.getOrElse(""),
              "patch"       -> parsed.userAgent.patch.getOrElse("")
            ),
            "os" -> Map(
              "family"      -> parsed.os.family,
              "major"       -> parsed.os.major.getOrElse(""),
              "minor"       -> parsed.os.minor.getOrElse(""),
              "patch"       -> parsed.os.patch.getOrElse(""),
              "patch-minor" -> parsed.os.patchMinor.getOrElse("")
            ),
            "device" -> Map(
              "family"      -> parsed.device.family,
              "brand"       -> parsed.device.brand.getOrElse(""),
              "model"       -> parsed.device.model.getOrElse("")
            )
          )
        }
      }    
    }
    

    您可能还想使用CachingParser的大小。

    不同行可以共享
    userAgent
    的一些值吗?是的,用户代理会重复自身,但列表不是很小。解析可能很昂贵-如果使用缓存,命中率会是多少?不同行可以共享
    userAgent
    的一些值吗?是的,用户代理会重复自身,但列表不是很小。解析可能很昂贵-如果使用缓存,命中率会是多少?