【问题标题】:How to perform a DISTINCT in Pig Latin on a subset of columns?如何在 Pig Latin 中对列的子集执行 DISTINCT?
【发布时间】:2026-01-07 01:50:01
【问题描述】:

我想对列的子集执行 DISTINCT 操作。 documentation 说这可以通过嵌套的 foreach 实现:

您不能在字段子集上使用 DISTINCT;为此,请使用 FOREACH 和嵌套块首先选择字段,然后应用 DISTINCT(请参阅示例:嵌套块)。

对所有列执行 DISTINCT 操作很简单:

A = LOAD 'data' AS (a1,a2,a3,a4);
A_unique = DISTINCT A;

假设我有兴趣在 a1、a2 和 a3 上执行不同的操作。谁能提供一个示例,说明如何按照文档中的建议使用嵌套的 foreach 执行此操作?

这是输入和预期输出的示例:

A = LOAD 'data' AS(a1,a2,a3,a4);
DUMP A;

(1 2 3 4)
(1 2 3 4)
(1 2 3 5)
(1 2 4 4)

-- insert DISTINCT operation on a1,a2,a3 here:
-- ...

DUMP A_unique;

(1 2 3 4)
(1 2 4 4)

【问题讨论】:

  • 您能否提供示例输入和预期输出?
  • 好建议,我更新了问题。

标签: apache-pig


【解决方案1】:

对所有其他列进行分组,仅将感兴趣的列投影到一个包中,然后使用FLATTEN 再次展开它们:

A_unique =
    FOREACH (GROUP A BY a4) {
        b = A.(a1,a2,a3);
        s = DISTINCT b;
        GENERATE FLATTEN(s), group AS a4;
    };

【讨论】:

  • 非常好的例子!谢谢您的帮助。这与我使用 distinct 的答案非常相似,但更简洁。
  • 如何启用并行子句。我尝试在我的脚本中使用 DEFAULT_PARALLEL 512 但这不起作用,并且#of reducers 不限于 512。有什么建议吗?
【解决方案2】:

接受的答案是一个很好的解决方案,但如果您想重新排序输出中的字段(我最近必须做的事情),这可能不起作用。这是另一种选择:

A = LOAD '$input' AS (f1, f2, f3, f4, f5);
GP = GROUP A BY (f1, f2, f3);
OUTPUT = FOREACH GP GENERATE 
    group.f1, group.f2, f4, f5, group.f3 ;

当您对某些字段进行分组时,选择的每个元组中的组将具有唯一值。

【讨论】:

    【解决方案3】:

    对于您指定的输入/输出,以下工作。您可能会更新您的测试向量以阐明您需要的与此不同的内容。

    A_unique = DISTINCT A;
    

    【讨论】:

    • 是的,这可能会有所帮助:)。我更新了原始问题中的预期输出。
    【解决方案4】:

    这里有2个可能的解决方案,还有其他好的方法吗?

    解决方案 1(使用 LIMIT 1):

    A = LOAD 'test_data' AS (a1,a2,a3,a4);
    
    -- Combine the columns that I want to perform the distinct across into a tuple
    A2 = FOREACH A GENERATE TOTUPLE(a1,a2,a3) AS combined, a4 as a4
    
    -- Group by the combined column
    grouped_by_a4 = GROUP A2 BY combined;
    
    grouped_and_distinct = FOREACH grouped_by_a4 {
            single = LIMIT A2 1;
            GENERATE FLATTEN(single);
    };
    

    解决方案 2(使用 DISTINCT):

    A = LOAD 'test_data' AS (a1,a2,a3,a4);
    
    -- Combine the columns that I want to perform the distinct across into a tuple
    A2 = FOREACH A GENERATE TOTUPLE(a1,a2,a3) AS combined, a4 as a4
    
    -- Group by the other columns (those I don't want the distinct applied to)
    grouped_by_a4 = GROUP A2 BY a4;
    
    -- Perform the distinct on a projection of combined and flatten 
    grouped_and_distinct = FOREACH grouped_by_a4 {
            combined_unique = DISTINCT A2.combined;
            GENERATE FLATTEN(combined_unique);
    };
    

    【讨论】:

    • 这些解决方案并不等效。第一个只会给你两个元组,因为a1a2a3 只有两个独特的组合,a4 的值是不可预测的。第二个将提供与您的示例输出一致的输出。 (不过,它并没有尽可能简洁。)
    【解决方案5】:
    unique_A = FOREACH (GROUP A BY (a1, a2, a3)) {
        limit_a = LIMIT A 1;
        GENERATE FLATTEN(limit_a) AS (a1,a2,a3,a4);
    };
    

    【讨论】:

      【解决方案6】:

      我也想这样做:“我想对列的子集执行 DISTINCT 操作”。我的做法是:

      A = LOAD 'data' AS(a1,a2,a3,a4);
      interested_fields = FOREACH A GENERATE a1,a2,a3;
      distinct_fields= DISTINCT interested_fields;
      final_answer = FOREACH distinct_fields GENERATE FLATTEN($0);
      

      我知道这不是文档中建议的如何执行嵌套 foreach 的示例;但这是一种对字段子集进行区分的方法。希望它对像我一样来到这里的人有所帮助。

      【讨论】:

        最近更新 更多