Performance 理解apachepig性能

Performance 理解apachepig性能,performance,join,filter,apache-pig,Performance,Join,Filter,Apache Pig,本问题中的查询涉及几个部分。首先有两种模式: data=FOREACH源生成 json#'id_str'作为post_id:chararray, json#'user'#'id_str'作为用户_id:chararray, json#“在"str"创建"为tstamp"str:chararray, 扁平化(json#'实体'#'hashtags')作为hashtag:chararray; stopwords=FOREACH另一个源生成 作为stopword_标签的令牌:chararray; s

本问题中的查询涉及几个部分。首先有两种模式:

data=FOREACH源生成
json#'id_str'作为post_id:chararray,
json#'user'#'id_str'作为用户_id:chararray,
json#“在"str"创建"为tstamp"str:chararray,
扁平化(json#'实体'#'hashtags')作为hashtag:chararray;
stopwords=FOREACH另一个源生成
作为stopword_标签的令牌:chararray;
stopwords
表包含一些重复项和空值,所以我做的第一件事是

stopwords=按stopwords筛选stopwords\u hashtag不为空;
停止字=不同的停止字;
然后我想从
数据的hashtag中过滤掉
停止字
,所以我用filter进行连接,然后再投影回
数据

joined=JOIN data BY hashtag LEFT,stopwords BY stopword\u hashtag;
joined=由stopwords::stopwords\u hashtag连接的筛选器为空;
数据=FOREACH连接生成
数据::post_id作为post_id:chararray,
数据::user\u id作为user\u id:chararray,
将_时间(data::tstamp_str)解析为tstamp:long,
数据::hashtag作为hashtag:chararray;
parse_-time(char-array)
是一个
Jython
UDF,我编写它是为了将datetime字符串转换为UNIX时间戳长度。所有这些之后,我将进行分组+排序:

user\u groups=FOREACH(按用户id分组数据)生成
组作为用户\u id:chararray,
数据(hashtag,tstamp)作为时间序列:bag{tuple:(tag:chararray,tstamp:long)};
用户组=每个用户组{
排序=按tstamp ASC排序的时间序列;
生成用户标识,已排序;
}
所有这些都是在一个猪脚本。我在大数据上运行此进程时遇到性能问题。我知道它适用于小玩具的例子。对于大型示例,如果
数据
停止字
都很长,则会占用太多内存并变得非常慢

据我所知,我正在尽可能早地进行过滤,也只做左连接。对性能优化有什么建议吗


我为更新太晚而道歉。我尝试过@Ran-Locar方法,效果很好

在过滤步骤中,清管器中出现错误:

output=通过from\u stopwords\u count==0过滤数据;
报告

java.lang.ClassCastException:java.lang.Integer不能转换为java.lang.Long
我花了一些时间才想出解决办法。我通过显式地从\u stopwords\u count和0转换为long解决了这个问题,即:

data\u with\u count=FOREACH data\u with\u count生成
$0..,(长)from_stopwords_count作为from_stopwords_count:long;
输出=过滤数据,\u使用\u count BY from\u stopwords\u count==0L;
我想我可以将两者都转换为int,这可能会提高性能,但考虑到我拥有的表的大小,我觉得更安全

我投入的一些统计数据:

  • 数据源是gzip格式的1.1TB
  • stopwords的源代码是400GB的gzip格式,但我只选了一列

  • 查询运行2.3小时,占用550GB内存和180个vCore。最后成功完成,真的救了我一天

    有一种方法可以完全避免停止字和数据之间的连接。基本上,您需要做的是:

    • 不需要区分,也不需要过滤停止词
    • 获取数据和停止字以共享同一架构

      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的行,因为这些行不会出现在停止词列表中(这就是您不再需要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);
      

    这种方法将联接替换为GROUP by。当我在很多GB的数据上测试它时,它是在一个
    左外连接中完成的?默认情况下,left表示内部连接,它永远不会有任何带有
    stopwords::stopwords\的记录,hashtag为NULL
    @rahulbmv我认为left-join等同于left-outer-join。至少我一直在考虑SQL中的左连接。让我回去检查pig文档。@rahulbmv
    col LEFT的JOIN table
    是Apache pig中的一个左外连接,根据0.14.0 Doc()让我今天下午在我的数据集上试用,并报告我的案例中性能的改进。但不管怎样,我认为这是巧妙的!如果你能给我一些提示的话,我想问你一些问题:你的问题的基本原理是什么?为什么这样更快、更高效?你读了什么来获得那一点知识?我很想和你一样好@Mai,我非常高兴它成功了。我会告诉你我是怎么想到这个的——在我的工作中(Outbrain;‘你可能还想看’内容推荐;好的推荐。不是裸体女人的推荐…),我经常需要‘两天都访问过的用户’和‘在某段时间访问过的用户,但不是在那之前的两周’。对于第一个查询,左连接是有意义的;对于第二种情况,你只对“最终结果”感兴趣——访问,或者不访问。因此,总结每个用户和过滤器在每个时段的访问次数是非常有意义的。你的情况真的是一样的。。。如有问题,另作说明。至于“为什么”它工作得更快——Hadoop中的连接可以是映射端(大表与内存中的小表连接)或缩减端(将同一个键的所有值发送到同一个缩减器)。我读了足够多的文献