gpt4 book ai didi

java - Hadoop 序列文件 : process key/value only up to a certain size?

转载 作者:可可西里 更新时间:2023-11-01 16:44:00 25 4
gpt4 key购买 nike

我有一个包含大约 12,000 个键/值对的序列文件。最大值为 143MB,其他均小于 1MB。 mapred.child.java.opts设置为 -Xmx500m .我得到一个 Error: Java heap space在处理这个文件时。这是我的映射器:

public class MyMapper extends Mapper<Text, BytesWritable, Text, Text> {
@Override
protected void setup(Context context) throws IOException, InterruptedException {
super.setup(context);
}

@Override
protected void map(Text key, BytesWritable value, Context context) throws IOException, InterruptedException {
Configuration conf = context.getConfiguration();
String content = new String(value.getBytes());
// remove HTML tags (content is a HTML document)
String content_no_html = Jsoup.parse(content).text();

// try to find a regex match
}
}
}

我认为这可能是因为我的 Map 类正在将值从 BytesWritable 转换为 String,然后处理该字符串。但是我试图只在映射器中处理一个键/值对,如果 value.getLength() < 8388608 (8 MB),内存仍然不足。

我可以增加 -Xmx500m ,但我担心这不会解决我的问题,因为我有几千个序列文件需要处理而且我不知道最大的键/值对有多大(我对大的不感兴趣键/值对,因此是上面的 8MB 限制)。作为记录,我尝试了一些序列文件,导致 ~2500 个映射步骤,并且错误发生在第一个 1990 年左右成功之后,这让我认为单个键/值对大小是这里的问题.

有没有办法只将键/值对传递给 Mapper 达到大小限制?为什么我什至得到 Error: Java heap space首先?

编辑

我尝试按照建议创建一个自定义的SequenceFileInputFormat,发现在调用map函数之前出现了Heap space error。准确地说,SequenceFileRecordReaders nextKeyValue()是导致错误的原因。我通过运行一个什么都不做的 map 函数仔细检查了这一点,但它仍然崩溃了。我找不到修复那里错误的方法,所以我想增加内存是我在这里唯一的机会。

最佳答案

8 MB 的 HTML 仍然太大了!

例如,假设您的 8 MB html 文本是一个包含 80 字节长元素的 ul 列表,您将有 1,000,000 个元素:

<ul>
<li class="item" data-index="000000">This is the <b>first</b> line.</li>
<li class="item" data-index="000001">This is the <b>second</b> line.</li>
[...]
<li class="item" data-index="999999">This is the <b>last</b> line.</li>
</ul>

Jsoup Element每个 li 元素的类(它是 Node 的子类)具有以下结构,我们可以从中估计(理论上和近似地)我示例的 html 列表的内存占用量:

  • Element.tag:对 Tag 对象的引用(其中 1 个字符串 + 8 个 boolean 值)=> 64 字节
  • Element.classNames:类名集 => 56 字节
  • Node.parentNode:对Node的引用=> 8字节
  • Node.attributes:对 Attributes 对象的引用 => 152 字节
    • 包含 LinkedHashMap<String, Attribute>有 1 个条目(48 字节)
      • 属性包含 2 个字符串(~56*2=112 字节)
  • Node.childNodes:节点列表
    • 3 个文本节点(因为 b 标签)=> 大约。每个 100 个字节(再次是文本内容 + 节点字段,这是内存初始化!)

所以链表的单个元素占用的内存在580字节左右。

这 1,000,000 个元素使用的总内存约为 580 MB。

此外,主要的 ul 元素在其 childrenNodes 字段中包含对那些 li 元素的 1,000,000 个引用的列表,因此它需要 8 MB 的内存。

最后,当调用 text()如果删除标签后留下的文本对应于 5MB 的序列化字符,那么您需要 String 500万char s,占用 5,000,000*2 = 10 MB。

因此,如果您的 html 就像我显示的列表一样,那么您需要在对 map() 的单次调用期间存储在堆中。功能:

  • new String(value.getBytes()) => ~ 16MB
  • Jsoup.parse(content) => ~ 590 MB
  • .text() => ~ 10MB
  • 总计 => 606 MB

难怪你会得到一个只有 500 MB 的堆的 java 堆空间错误!

“内存爆炸”发生在用JSoup解析文件时,因为它要创建很多对象,而java对象,尤其是Strings,是很重的。

这完全取决于您的 html 的外观。如果您的 html 具有与我的示例大致相同的 html 标签/属性浓度,我认为您可以将阈值定义为 2 MB 左右以确保安全。

如果value.getLength() < 2_000_000可以一开始就退出map函数和你一样。或者,如果不浪费数据对您来说很重要,您可以做一些更有趣的事情,比如运行正则表达式来计算 content 中标签或属性的数量。字符串。如果您有 20 MB 的文本,但其中只有 1 个标签,它仍然适合内存,无需跳过它。

关于java - Hadoop 序列文件 : process key/value only up to a certain size?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38081654/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com