【问题标题】:ArrayIndexOutOfBounds Exception while accessing RDD element访问 RDD 元素时出现 ArrayIndexOutOfBounds 异常
【发布时间】:2017-12-29 21:10:52
【问题描述】:

我有一个文件如下:

dept.txt:
1,It,pune,2017-03-12
2,CS,delhi,2017-03-21
3,mech,mum,
4,fin,pune,2017-04-15
5,It,delhi,

我需要做的是:

  1. 从 2 个 RDD 中的 2 个文件中读取数据(我已经完成了)

  2. 对 dept 文件中的日期列应用过滤器并获取两个基于输出的文件 关于 null 而不是 null 值(我无法做到)

我能走多远:

val loadDept = sc.textFile("/path/to/file/dept.txt")
val cleanDept = loadDept.map(_.split(","))
val dateCol = cleanDept.filter(i => i(3) != "") 

最后一行出现错误:

java.lang.ArrayIndexOutOfBoundsException: 3

我知道,由于有一个空字符串/null,我得到了一个超出范围的异常(如果我错了,请纠正我),但是如何解决它呢?

注意:我只需要在 Scala 中使用 RDD

【问题讨论】:

  • 访问数组元素前先检查长度
  • @Saravana 感谢您的回复。如果您看到 dept.txt,则每行中有 4 个值,用逗号分隔。所以我相信当我分裂时,我应该得到 0,1,2,3 个位置。因此试图得到 i(3)。现在,我认为,如果您检查第 3 行“3,mech,mum”,最后一个逗号后面没有空格或没有空格,并且直接回车。因此我相信这个问题,但我不知道如何摆脱它并实现我想要的。
  • 请查看答案以检查长度并根据索引 3 处的元素对结果进行分组

标签: scala apache-spark rdd


【解决方案1】:

来自split(String regex, int limit)方法的描述:

limit 参数控制应用模式的次数,因此会影响结果数组的长度。如果限制 n 大于零,则模式将最多应用 n - 1 次,数组的长度将不大于 n,并且数组的最后一个条目将包含最后一个匹配分隔符之外的所有输入。 如果 n 为非正数,则该模式将被应用尽可能多的次数,并且数组可以具有任意长度。 如果 n 为零,则该模式将被应用尽可能多的次数,数组可以有任意长度,并且尾随的空字符串将被丢弃

由于split(String regex) 的工作方式好像是通过使用给定表达式和 zero 限制参数调用双参数拆分方法,因此您的空字符串将被丢弃。

解决方案,在 Natalia 的answer 中也提到过:

// collect each and every string
val cleanDept = loadDept.map(_.split(",", -1))  
// filter arrays with empty last string
val filledDateDept = cleanDept.filter(_.last.nonEmpty)  

【讨论】:

    【解决方案2】:
    1. 在访问其元素之前检查数组的大小

      sc.textFile("/file/path/dept.txt")
      .map(_.split(","))
      .filter(a => a.length > 3 && a(3) != null && !a(3).equals(""))
      
    2. 您可以使用groupBy对结果进行分组

      sc.textFile("/file/path/dept.txt")
      .map(_.split(","))
      .groupBy(a => a.length > 3 && a(3) != null && !a(3).equals(""))
      

    这将按groupBy 键对结果进行分组,在这种情况下它将是truefalse

    false 键将在 Buffer 中保存所有 null 和不存在的结果。

    true 键会将所有非空结果保存在缓冲区中。

    输出

    (false,CompactBuffer([Ljava.lang.String;@5bef517c, [Ljava.lang.String;@51ec0ad3))
    (true,CompactBuffer([Ljava.lang.String;@44a4871, [Ljava.lang.String;@16a375ad, [Ljava.lang.String;@37703dfd))
    

    【讨论】:

      【解决方案3】:

      拆分操作中的问题。

      "ab,dfd,".split(",") --> Array(ab, dfd)
      "ab,dfd,".split(",", -1) --> Array(ab, dfd, )
      

      如果您只使用一个参数调用 split,则使用默认限制。它等于0。

      用于拆分的 Java 文档

      limit 参数控制应用模式的次数,因此会影响结果数组的长度。如果限制 n 大于零,则模式将最多应用 n - 1 次,数组的长度将不大于 n,并且数组的最后一个条目将包含最后一个匹配分隔符之外的所有输入。如果 n 为非正数,则该模式将尽可能多地应用,并且数组可以具有任意长度。如果 n 为零,则该模式将被应用尽可能多的次数,数组可以有任意长度,并且尾随的空字符串将被丢弃。

      如您所见,如果为 0,则全部为 trailing empty strings will be discarded

      【讨论】:

      • 精湛。这解决了目的。如果可能的话,你能解释一下-1吗?我从未见过或使用过这样的。
      • 您的语句长度为0的子字符串被丢弃不正确。第二个参数表示模式将应用于拆分字符串的次数。
      • @philantrovert 谢谢,已修复复制粘贴 javadoc 以进行拆分
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 2016-01-11
      • 2011-05-01
      • 1970-01-01
      相关资源
      最近更新 更多