0

假设我有一个带有玩家 ID 的游戏。每个 id 可以有多个角色名称(playerNames),我们对每个名称都有一个分数。我想将每个 playerName 的所有分数加起来,并计算每个 id 每个玩家名称的百分比分数。

因此,例如:

id playerName playerScore
01 测试 45
01 测试2 15
02乔100

会输出

id {(playerName, playerScore, percentScore)}
01 {(Test, 45, .75), (Test2, 15, .25)}
02 {(乔, 100, 1.0)}

我是这样做的:

data = LOAD 'someData.data' AS (id:int, playerName:chararray, playerScore:int);
grouped = GROUP data BY id;

withSummedScore = FOREACH grouped GENERATE SUM(data.playerScore) AS summedPlayerScore, FLATTEN(data);

withPercentScore = FOREACH withSummedScore GENERATE data::id AS id, data::playerName AS playerName, (playerScore/summedPlayerScore) AS percentScore;

percentScoreIdroup = GROUP withPercentScore By id;

目前,我使用 2 个 GROUP BY 语句来执行此操作,我很好奇它们是否都是必要的,或者是否有更有效的方法来执行此操作。我可以将其减少为单个 GROUP BY 吗?或者,有没有一种方法可以遍历元组包并向所有元组添加 percentScore 而不会展平数据?

4

1 回答 1

1

不,没有 2 就无法做到这一点GROUP,原因比 Pig 更根本:

  1. 要获得总点数,您需要线性传递玩家的分数。
  2. 然后,您需要对玩家的分数进行另一次线性传递来计算分数。在知道总和之前,您不能这样做

话虽如此,如果玩家的playerNames 数量很少,我会编写一个 UDF,它接受一袋玩家分数并输出一袋 score-per-playerName 元组,因为每个元组GROUP都会生成一个 reducer,并且过程变得非常缓慢. 带走袋子的 UDF 也必须执行这 2 次线性传递,但如果袋子足够小,那没关系,它肯定比创建另一个减速器快一个数量级。

于 2013-04-06T13:52:13.200 回答