奇怪的杰克逊非法字符((CTRL-CHAR, code 0))在Map Reduce Combiner中引发异常。

23
我有一个Map-Reduce作业,其中mapper将记录转换为一个对象,即MyObject的实例,并使用Jackson将其编组为JSON。该值只是记录中的另一个文本字段。
以下是mapper的相关部分:
ObjectMapper mapper = new ObjectMapper();
MyObject val = new MyObject();
val.setA(stringA);
val.setB(stringB);
Writer strWriter = new StringWriter();
mapper.writeValue(strWriter, val);
key.set(strWriter.toString());

Mapper的输出被发送到Combiner,它会解组JSON对象并聚合键值对。这个过程在概念上非常简单,类似于:

public void reduce(Text key, Iterable<IntWritable> values, Context cxt) 
    throws IOException, InterruptedException {
    int count = 0;
    TermIndex x = _mapper.readValue(key.toString(), MyObject.class);
    for (IntWritable int : values) ++count;
    ...
    emit (key, value)
}

MyObject类由两个字段(均为字符串)、get/set方法和默认构造函数组成。其中一个字段基于网页爬取存储文本片段,但始终是字符串类型。
public class MyObject {
  private String A;
  private String B;

  public MyObject() {}

  public String getA() {
    return A;
  }
  public void setA(String A) {
    this.A = A;
  }
  public String getB() {
    return B;
  } 
  public void setIdx(String B) {
    this.B = B;
  }
}

我的MapReduce作业似乎运行良好,直到它处理到一些记录,这些记录很难访问(因为Mapper是从爬网生成这些记录),然后会抛出以下异常:

Error: com.fasterxml.jackson.core.JsonParseException: 

    Illegal character ((CTRL-CHAR, code 0)): only regular white space (\r, \n, \t) is allowed between tokens
     at [Source: java.io.StringReader@5ae2bee7; line: 1, column: 3]

有人对这个问题的原因有什么建议吗?

使用okhttp 1.5.1版本,希望能解决你的问题。 - SkyWalker
1
我知道你说你没有轻松的访问权限,但我建议在爬取之前进行前端处理,并从流中删除类似于0(NULL)的虚假控制字符,然后将其传递给Jackson。我曾经看到过各种证券的金融数据都有这样的虚假数据需要被清除。这很可能是发送方的缺陷。 - sagneta
在低级别上,某些东西正在向流中注入空字节(字节0),而解析器不接受它们(对于JSON来说是无效的)。你需要弄清楚这是如何发生的以及为什么会发生,可能有许多原因,包括并发问题或时间问题(尝试在内容加载到缓冲区之前解析内容)。 - StaxMan
1
如果可能的话,添加一些日志行,这样您就可以看到哪些记录失败了。另外,由于您正在爬取数据,您可能会遇到与此处(GZip编码)相同的问题:https://dev59.com/zV3Ua4cB1Zd3GeqP9iCe - Haris Osmanagić
2个回答

2
  • 你可以使用Apache Commons库中的StringUtils来转义字符串。
  • 或者,在JSON编组之前,选择性地替换字符串中的控制字符

你也可以参考这篇文章:Illegal character - CTRL-CHAR


0

我收到了一个UTF-16编码的响应,在每个byte[]中的简单字符后面都有一个((CTRL-CHAR, code 0)) 查看屏幕

对我来说这很有效:

StringUtils.toEncodedString(responseBodyAsByteArray, StandardCharsets.UTF_16LE)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接