Scala Class etc. 2

本文深入探讨Scala中的高阶函数、模式匹配、闭包、柯里化等高级特性,解析其在函数式编程中的应用,包括参数类型推导、匿名函数、控制抽象、偏函数及优化技巧。

Higher-Order Functions

  • def 定义的是方法,而不是函数
  • 函数可作为变量存在,可直接调用,也可作为值传递给其他函数
  • _ 后缀将普通方法变为函数: ceil _
    • 根据上下文编译器可以自动将方法转换为函数,也可省略 _ 后缀
  • 高阶函数,接收函数的函数
  • 参数类型推导
    • 匿名函数传递给其他函数或方法时,如果一直到参数类型,则可省略匿名函数的参数类型,可自动推导类型
    • 参数只有一个时可省略括号
      • 当参数在右侧只出现一次时,可使用 _ 简写
  • 闭包 Closures,特定作用域
  • SAM, single abstract method interface
    • 对应 Java 中的函数式接口 (1.8)
    • 可将 Scala 函数传递给 Java,只在函数字面量中起作用
  • 柯里化 Currying
    • 将接收两个参数的函数变为接收第一个参数的函数,该函数返回一个消费第二个参数的函数
  • 控制抽象 Control Abstractions
    • Scala 只包含少量的流程控制语句,用户可自定义控制语句

Pattern Matching and Case Classes

  • 可对任何类型进行模式匹配,匹配顺序从上至下

  • 模式匹配代替 switch,默认分支为 case _;可避免 switch 语句中因缺少 break 带来的 fall-through 问题

  • 模式匹配也是表达式,可将其返回值直接赋值给变量

  • 模式守卫 / guards,为匹配设置条件,任何 Boolean 条件都可作为模式守卫;case ... if ... => ...

  • case 关键字后接变量名或对应数据结构中使用变量名,那么匹配项就赋值给该变量,变量名必须以小写字母开头

  • 使用 | 分隔同一匹配的多个可选项,此时不可使用变量绑定元素

  • 类型匹配,代替 isInstanceOfasInstanceOf,直接进行类型转换

    • 必须为类型指定变量名,否则匹配的是实际的类型对象
    • 匹配在运行时发生,而 JVM 泛型会被擦除
      • 不可以匹配具体的 Map 类型(可使用 case Map[_, _],不可使用 case Map[Int, Int]
      • Array 的类型不会被擦除
  • 解构 destructuring

    • 匹配数组
      case Array(x, y) => s"$x $y"  // 匹配长度为2的数组,并将分别绑定到 x, y
      case Array(0, rest @ _*) => rest.min // 可变参数
      
    • 匹配 List
      case x :: y :: Nil => ...  // 绑定参数
      case head :: tail => ...  // 解构 head , tail
      
    • 匹配元组
      case (0, _) => ... // 匹配第一个元素为0
      case (x, y) => ... // 绑定参数
      
  • 定义变量,注意一定要小写开头;其实等价于 match 模式匹配加上赋值操作

    • val (x, y) = (1, 2)
    • val Array(f, s, rest @ _*) = arr
  • 用于 for 循环遍历集合,匹配符合条件的元素

    for ((k, v) <- System.getProperties()) println(s"$k $v")
    // 匹配 value 为 "" 的项,其他的则被忽略
    for ((k, "") <- System.getProperties()) println(k)
    // if guard 过滤
    for ((k, v) <- System.getProperties() if v == "") println(k)
    
  • Case Class

    • 用于模式匹配的特殊类
    • 构造参数默认为 val,默认提供 applyunapplytoStringequalshashCodecopy
      • copy 用于复制对象时,可使用命名参数来修改属性
    • case class X 使用时 case X() => ...,需要括号
    • case object S 单例,使用时 case S => ..., 不要括号
    • :: 也是 case class,配合中缀表达式,就是常见的匹配方式,case head :: tail,实际调用 ::(head, tail)
    • 可用于嵌套的结构;绑定变量、可变参数匹配类似
    • 适用于固定结构的类,如 List
  • sealed 密封的

    • 被修饰的类,则其子类必须和该类在同一个文件中定义
    • 在编译时即确定了所有匹配项的可能性
  • Option 也是使用 case class 来表示是否有值存在的

    • 子类 Some 封装值,子类 None 表示无值
    • 相比使用 ""null 更加安全
    • Map 进行 get 操作返回的也是 Option,也可使用模式匹配来处理
    • getOrElse 尝试获取值,未获取到则使用给定的值
  • Partial Function 偏函数

    • 没有对所有输入进行定义的函数
    • apply 从模式匹配中计算函数值,isDefinedAt 判断输入是否匹配定义的模式
    • case 语句块是偏函数
    • PartialFunction[A, B] 的实例, A 为输入类型,B 为输出类型
      • 可使用偏函数的 lift 方法,将偏函数变为常规函数,返回值为 Option[B]
      • 也可以通过 Function.unlift 将返回 Option[B] 的函数变为偏函数
    • Seq[A] 也是偏函数 PartialFunction[Int, A]
    • Map[K, V] 也是偏函数 PartialFunction[K, V]
    • catch 语句也是偏函数,可在 catch 块中使用模式匹配处理异常

注解

  • Scala 中注解可影响代码编译,如 @BeanProperty 会自动生成 getter/setter
  • 可用于 类、方法、字段、变量、参数等
    • 多个注解无顺序
    • 主构造器的注解,需要加括号 class Credential @Inject() (var username: String, var password: String)
    • 表达式的注解,使用分号加注解的方式 (map.get(key): @unchecked) ...
    • 类型参数的注解,class Test[@specialized T]
    • 实际类型的注解,放在类型之后,def name: String @Localized
  • 注解实现
    • 注解必须继承 Annotation
    • 类型注解必须继承 TypeAnnotation
    • 元注解 @param, @field, @getter, @setter, @beanGetter, @beanSetter
  • 对应 Java 修饰符、标记接口
    • @volatile 对应 volatile 关键字
    • @transient 对应 transient 关键字
    • @strictfp 对应 strictfp 关键字
    • @native 对应 native 关键字
    • @cloneable 对应 Cloneable
    • @remote 对应 java.rmi.Remote
    • @SerialVersionUID 代替序列化字段
  • 使用 @throws(classOf[Exception]) 来处理 Java 中的受检异常
  • @varargs 处理可变参数
    • @varargs def name(args: String*) 生成 void name(String... args)
    • 没有 @varargs 则可变参数会被转换成 Seq[T]
  • 优化
    • @tailrec 会尝试优化尾递归调用,将其变为循环
    • @switch 编译器会检查 match 表达式是否编译为 ableswitchlookupswitch,如果被编译成一系列条件表达式,则会抛出异常
    • @inline, @noinline 建议编译器是否将方法替换为行内调用
    • @elidable, 用于标注在生产代码中可移除的方法
      • elidable 对象定义了很多级别常量可直接使用,未指定参数时默认是 SERVERE 即 1000(包含1000)
    • @specialized 处理基础类型,自动生成基础类型对应包装类的方法
C:\Users\50125\PycharmProjects\pythonProject1\.venv\Scripts\python.exe E:\Heart-disease-analysis-main\pre\app.py Warning: Ignoring non-Spark config property: hive.metastore.uris 25/04/29 16:07:34 ERROR UserGroupInformation: Unable to find JAAS classes:com.ibm.security.auth.UsernamePrincipal Exception in thread "main" org.apache.hadoop.security.KerberosAuthException: failure to login: javax.security.auth.login.LoginException: No LoginModule found for com.ibm.security.auth.module.Win64LoginModule at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1847) at org.apache.hadoop.security.UserGroupInformation.createLoginUser(UserGroupInformation.java:710) at org.apache.hadoop.security.UserGroupInformation.getLoginUser(UserGroupInformation.java:660) at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:571) at org.apache.spark.util.Utils$.$anonfun$getCurrentUserName$1(Utils.scala:2414) at scala.Option.getOrElse(Option.scala:189) at org.apache.spark.util.Utils$.getCurrentUserName(Utils.scala:2414) at org.apache.spark.SecurityManager.<init>(SecurityManager.scala:79) at org.apache.spark.deploy.SparkSubmit.secMgr$lzycompute$1(SparkSubmit.scala:368) at org.apache.spark.deploy.SparkSubmit.secMgr$1(SparkSubmit.scala:368) at org.apache.spark.deploy.SparkSubmit.$anonfun$prepareSubmitEnvironment$8(SparkSubmit.scala:376) at scala.Option.map(Option.scala:230) at org.apache.spark.deploy.SparkSubmit.prepareSubmitEnvironment(SparkSubmit.scala:376) at org.apache.spark.deploy.SparkSubmit.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:871) at org.apache.spark.deploy.SparkSubmit.doRunMain$1(SparkSubmit.scala:180) at org.apache.spark.deploy.SparkSubmit.submit(SparkSubmit.scala:203) at org.apache.spark.deploy.SparkSubmit.doSubmit(SparkSubmit.scala:90) at org.apache.spark.deploy.SparkSubmit$$anon$2.doSubmit(SparkSubmit.scala:1007) at org.apache.spark.deploy.SparkSubmit$.main(SparkSubm
最新发布
04-30
<think>好的,我现在需要帮助用户解决Spark提交时遇到的JAAS类未找到和Kerberos身份验证失败的问题。首先,我得理清用户的问题描述,然后结合我现有的知识以及用户提供的引用内容,找到可能的解决方案。 用户提到的错误有两个:一个是No LoginModule found for com.ibm.security.auth.module.Win64LoginModule,另一个是KerberosAuthException。首先,Win64LoginModule这个模块属于IBM的特定实现,可能用户的环境里没有正确配置或缺少相关依赖。而Kerberos身份验证失败可能与JAAS配置、keytab文件或Hive Metastore的连接有关。 接下来,我需要参考用户提供的引用内容。例如,引用[2]中提到了ZooKeeper的SASL配置和JAAS文件,这可能涉及到如何正确设置JAAS配置文件,特别是与Kerberos相关的部分。引用[4]提到了Hive连接的URL中可能存在空格问题,这可能提示用户检查配置中的拼写错误或多余字符。 首先,JAAS配置问题。Spark在启用Kerberos时需要正确配置JAAS文件,指定使用正确的LoginModule。用户遇到的Win64LoginModule未找到可能是因为在非Windows环境或未安装IBM相关安全模块的情况下尝试使用它。解决方案应该是改用标准的Krb5LoginModule,比如将JAAS配置文件中的相关条目改为使用com.sun.security.auth.module.Krb5LoginModule。 然后,检查spark-submit命令中是否正确指定了JAAS文件的位置,通过--conf spark.executor.extraJavaOptions和--conf spark.driver.extraJavaOptions参数来传递Java选项,确保路径正确,并且文件权限适当。 其次,Kerberos身份验证失败可能涉及多个方面。需要确认用户是否已经通过kinit成功获取了TGT,或者是否正确指定了keytab文件。例如,在Spark配置中,应设置spark.kerberos.keytab和spark.kerberos.principal,确保keytab文件路径正确,并且principal名称无误。 另外,Hive Metastore的连接问题也可能导致身份验证失败。用户需要检查hive.metastore.uris是否正确配置,确保Hive Metastore服务已经启动并且Kerberos保护良好。引用[4]提到URL中的空格问题,用户需要检查连接字符串是否有拼写错误或多余的空格。 用户提供的引用[3]中提到了HDFS的JMX配置,虽然可能与当前问题关联不大,但需要注意环境变量是否正确设置,避免其他配置干扰。 可能还需要检查Kerberos配置文件(krb5.conf)是否正确,确保KDC服务器地址和域名配置正确。同时,确保所有节点的时钟同步,因为Kerberos对时间同步非常敏感。 最后,用户可能需要查看详细的调试日志,通过设置Spark的日志级别为DEBUG来获取更多信息,帮助定位问题根源。例如,在spark-submit中添加--verbose选项,或者在log4j.properties中调整日志级别。 总结步骤应该是:1. 修改JAAS配置使用正确的LoginModule;2. 确保Spark配置中正确指定keytab和principal;3. 检查Hive Metastore URI和Kerberos配置;4. 验证Kerberos票据和网络连通性;5. 查看日志进行详细错误分析。 在回答时,需要结构清晰,分步骤说明解决方案,并引用相关的引用内容作为支持。同时,生成相关问题,帮助用户进一步排查可能的问题点。</think>### Spark提交时JAAS类未找到及Kerberos身份验证失败解决方案 #### 一、JAAS类未找到问题分析 1. **错误原因** `No LoginModule found for com.ibm.security.auth.module.Win64LoginModule` 表示Spark尝试使用IBM特定的安全模块,但当前环境未配置该模块。通常应使用Java标准Kerberos模块 `Krb5LoginModule`[^2]。 2. **解决方案** - **修改JAAS配置文件**: 将`jaas.conf`中`Client`段的`LoginModule`替换为Java标准实现: ``` Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/path/to/user.keytab" principal="user@REALM"; }; ``` - **指定JAAS路径**: 在`spark-submit`中添加配置参数: ```bash --conf spark.executor.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" \ --conf spark.driver.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" ``` - **检查文件权限**:确保`jaas.conf`和`keytab`文件对Spark进程可读。 #### 二、Kerberos身份验证失败问题分析 1. **常见错误场景** - Kerberos票据未初始化(未执行`kinit`或`keytab`配置错误) - Hive Metastore URI配置错误或服务不可达 - 网络问题或时间不同步 2. **解决方案** - **初始化Kerberos票据**: 手动执行`kinit`或通过Spark配置自动获取: ```bash --conf spark.kerberos.keytab="/path/to/user.keytab" \ --conf spark.kerberos.principal="user@REALM" ``` - **检查Hive Metastore配置**: 确保`hive.metastore.uris`指向正确的服务地址,并验证URI格式(注意避免多余空格)[^4]: ```sql thrift://metastore-host:9083 ``` - **验证Kerberos配置**: - 检查`/etc/krb5.conf`中的`realm`和`kdc`配置 - 使用`telnet`或`nc`验证Hive Metastore端口连通性 - 确保所有节点时间同步(NTP服务) #### 三、综合配置示例 1. **完整`spark-submit`命令** ```bash spark-submit \ --master yarn \ --deploy-mode cluster \ --keytab "/path/to/user.keytab" \ --principal "user@REALM" \ --conf spark.hadoop.hive.metastore.uris="thrift://metastore-host:9083" \ --conf spark.executor.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" \ --conf spark.driver.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" \ --class com.example.MainApp \ /path/to/application.jar ``` 2. **调试日志启用** 在`log4j.properties`中添加: ``` log4j.logger.org.apache.hadoop.security=DEBUG log4j.logatorg.apache.spark=DEBUG ``` #### 四、注意事项 1. 若使用ZooKeeper,需同步检查SASL配置(如`quorum.auth.enableSasl`)[^2] 2. Windows环境下需替换路径分隔符(`\` → `/`) 3. Kerberos票据有效期需大于作业运行时间
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值