如何在python中比较同一PCollection中两个键的所有值?

如何在python中比较同一PCollection中两个键的所有值?,python,google-cloud-dataflow,apache-beam,Python,Google Cloud Dataflow,Apache Beam,我不熟悉apachebeam/dataflow。我正在ApacheBeam中读取一个BigQuery表,我想按两个不同的列进行分组,并比较两个不同键的所有值。我创建了一个由两个不同列(ID、Date)组成的元组,作为键。下面是表格中的示例数据 ID Date P_id position "abc" 2019-08-01 "rt56" 5 "abc" 2019-08-01 "rt57" 6 "abc"

我不熟悉apachebeam/dataflow。我正在ApacheBeam中读取一个BigQuery表,我想按两个不同的列进行分组,并比较两个不同键的所有值。我创建了一个由两个不同列(ID、Date)组成的元组,作为键。下面是表格中的示例数据

  ID         Date        P_id    position
  "abc"    2019-08-01   "rt56"      5
  "abc"    2019-08-01   "rt57"      6
  "abc"    2019-08-01   "rt58"      7
  "abc"    2019-08-02   "rt56"      2 
  "abc"    2019-08-02   "rt57"      4
  "abc"    2019-08-02   "rt58"      7
现在,我想比较配对的p_id的位置(“abc”,2019-08-01)和(“abc”,2019-08-02),看看是否有任何p_id位置发生了变化,然后在表“status”中添加另一列为True。因此,我的新表应该如下所示

我正在尝试下面的代码

  ID         Date        P_id    position  Status
  "abc"    2019-08-01   "rt56"      5       False (as this is first date)
  "abc"    2019-08-01   "rt57"      6
  "abc"    2019-08-01   "rt58"      7
  "abc"    2019-08-02   "rt56"      2       True
  "abc"    2019-08-02   "rt57"      4
  "abc"    2019-08-02   "rt58"      7
但是我不知道应该如何进行函数compare_pos()


考虑到我有一个非常大的表和大量的ID,了解如何有效地比较位置并创建一个新列以了解状态将非常有帮助。

Beam的GroupByKey接受一个2元组的PCollection并返回一个PCollection,其中每个元素都是键和(无序)的2元组与该键关联的所有值的iterable。例如,如果您的原始集合包含元素

(k1, v1)
(k1, v2)
(k1, v3)
(k2, v4)
GroupByKey的结果将是包含以下元素的PCollection

(k1, [v1, v3, v2])
(k2, [v4])
在本例中,键和值本身就是元组。因此,您可以使用原始集合并应用
映射(lambda elt:((elt['Id'],elt['Date']),(elt['P_Id'],elt['position']))
,这将为您提供一个包含元素的PCollection

  ("abc", 2019-08-01),   ("rt56", 5)
  ("abc", 2019-08-01),   ("rt57", 6)
  ("abc", 2019-08-01),   ("rt58", 7)
  ("abc", 2019-08-02),   ("rt56", 2)
  ("abc", 2019-08-02),   ("rt57", 4)
  ("abc", 2019-08-02),   ("rt58", 7)
在应用GroupByKey时,它将成为

  ("abc", 2019-08-01),   [("rt56", 5), ("rt57", 6), ("rt58", 7)]
  ("abc", 2019-08-02),   [("rt56", 2), ("rt57", 4), ("rt58", 7)]

此时,您的
compare\u pos
函数可以检查与给定
id、Date
对相对应的所有
p\u id、position
元组,并执行所需的任何逻辑以发出需要更改的内容(使用其相应的键)

我可能对OP的解释是错误的,但如果@robertwb的建议不起作用,请尝试按以下方式分组:

| "Create k, v tuple" >> beam.Map(
                    lambda elem: ((elem["P_id"], elem["ID"]), [elem["Date"], elem["position"]]))
| "Group by key" >> beam.GroupByKey()
将输出以下结构:

(('rt56', 'abc'), [['2019-08-01', 5], ['2019-08-02', 2]])
(('rt57', 'abc'), [['2019-08-01', 6], ['2019-08-02', 4]])
(('rt58', 'abc'), [['2019-08-01', 7], ['2019-08-02', 7]])
这应该允许您单独比较结果PCollection中的每个元素,而不是交叉比较PCollection中的各个元素。如果我是正确的,这可能更适合Beam的执行模型


这是基于我的假设,即您希望检查给定p_id的位置是否在两个日期之间发生了更改。

谢谢您的帮助。但这并不能完全回答我的问题。我一直在用Python实现compare_pos函数(即如何比较PCollection中的元组以检查位置是否改变),这是我最初在问题中提出的。你能帮忙吗?我想我可能不明白你的问题。您是否真的要求在给定ID内,与数据关联的P_ID集是否从一个日期更改为下一个日期?(不确定位置列在何处。)如果是这样,我将应用Map(lambda元素:(元素['ID']:元素))和GBK,它将为单个ID提供所有元素,然后在compare_pos中,您可以进行进一步分组(例如,使用defaultdict(set)将日期映射到P_id,然后迭代排序的键以查看日期到日期的变化。)或者,如果您知道在日期上没有间隔(并且有太多的日期-P_id对无法放入单个id的内存中),您可以生成两个表,一个以(id,date)为键,另一个以(id,date+1)为键,然后做一个CoGropuByKey,它将生成一个PCollection,每个连续的日期对都有一个元素。是的,这看起来不错,但是我如何比较它们之间的位置,就像我做元素[1]时,它将一列中的所有三行作为一个元组
(('rt56', 'abc'), [['2019-08-01', 5], ['2019-08-02', 2]])
(('rt57', 'abc'), [['2019-08-01', 6], ['2019-08-02', 4]])
(('rt58', 'abc'), [['2019-08-01', 7], ['2019-08-02', 7]])