了解apache pig性能

vjhs03f7  于 2021-06-21  发布在  Pig
关注(0)|答案(1)|浏览(364)

这个问题涉及到几个部分。首先有两种模式:

data = FOREACH source GENERATE
    json#'id_str' AS post_id:chararray,
    json#'user'#'id_str' AS user_id:chararray,
    json#'created_at_str' AS tstamp_str:chararray,
    FLATTEN(json#'entities'#'hashtags') AS hashtag:chararray;

stopwords = FOREACH another_source GENERATE
    token AS stopword_hashtag:chararray;
``` `stopwords` 表包含一些重复项和空值,所以我首先要做的是

stopwords = FILTER stopwords BY stopword_hashtag IS NOT NULL;
stopwords = DISTINCT stopwords;

然后我想过滤掉 `stopwords` 从 `data` 的hashtags,所以我使用filter进行连接,然后将其投影回 `data` :

joined = JOIN data BY hashtag LEFT, stopwords BY stopword_hashtag;
joined = FILTER joined BY stopwords::stopword_hashtag IS NULL;

data = FOREACH joined GENERATE
data::post_id AS post_id:chararray,
data::user_id AS user_id:chararray,
parse_time(data::tstamp_str) AS tstamp:long,
data::hashtag AS hashtag:chararray;
``` parse_time(char array) 是一个 Jython 我编写的udf将datetime字符串转换为unix长时间戳。所有这些之后,我将进行分组+排序:

user_groups = FOREACH (GROUP data BY user_id) GENERATE
    group AS user_id:chararray,
    data.(hashtag, tstamp) AS time_series:bag{tuple:(tag:chararray,tstamp:long)};
user_groups = FOREACH user_groups {
    sorted = ORDER time_series BY tstamp ASC;
    GENERATE user_id, sorted;
}

所有这些都是在一个Pig脚本。我在大数据上运行此进程时遇到性能问题。我知道它适用于小玩具的例子。对于大型示例,其中 data 以及 stopwords 如果时间长,它会占用太多的内存,并且变得非常慢。
据我所知,我正在尽可能早地做过滤,也只做左连接。对性能优化有什么建议吗?
很抱歉更新太晚了。我试过@ran locar方法,效果很不错!
在过滤步骤中,pig中有一个错误:

output = FILTER data_with_count BY from_stopwords_count==0;

报告

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

我花了一些时间才想出解决办法。我通过显式地将\u stopwords \u count和0转换为long来解决这个问题,即:

data_with_count = FOREACH data_with_count GENERATE
     $0.., (long) from_stopwords_count AS from_stopwords_count:long;
 output = FILTER data_with_count BY from_stopwords_count==0L;

我想我本可以将两者都转换为int,这可能会提高性能,但考虑到我拥有的表的大小,我觉得更安全。
我输入的一些数据:
数据源是gzip格式的1.1tb
stopwords的源代码是400gb的gzip格式,但我只取了其中的一列。
查询运行2.3小时,占用550gb内存和180个vCore。最后成功完成,真的救了我一天!

vd8tlhqk

vd8tlhqk1#

有一种方法可以完全避免stopwords和数据之间的连接。基本上你需要做的是:
不需要区分,也不需要过滤停止词。
获取数据和stopwords以共享同一架构

stopwords = FOREACH another_source GENERATE
'' as post_id,
'' as user_id,
'' as tstamp_str,
token AS hashtag:chararray,
0 as from_data,
1 as from_stopwords;

将from\ data和from\ stopwords字段添加到数据架构中

data = FOREACH data GENERATE
$0..,
1 as from_data,
0 as from_stopwords;

两种关系的结合

data_with_stopwords = UNION data, stopwords;

按令牌分组。在每个组中,两个关系都有行。

data_with_stopwords_and_counts = foreach (group data_with_stopwords by hashtag) generate
$0.., SUM(data_with_stopwords.from_data) as from_data_sum, SUM(data_with_stopwords.from_stopwords) as from_stopwords_sum;

现在,每一行都有组键、属于该组的所有行和两个数字。您只需要from\u stopwords\u sum==0的行,因为这些行不会出现在stop words列表中(这就是您不再需要distinct。。。你不介意单词不止一次出现在停止词中;您只需获得from\u stopwords\u sum>=1,并忽略该行)
按from\u stopwords\u sum==0筛选并展平列表

data_with_stopwords_and_counts = foreach (filter data_with_stopwords_and_counts by from_stopwords_sum==0) generate
flatten($1);

这种方法将join替换为groupby。当我在许多gbs的数据上测试它时,它在<10分钟内完成,而使用join只需几个小时。您的行最后会有额外的sum字段,但您可以在之后删除它们。

相关问题