Spark: Dataframe.subtract возвращает все, когда ключ не является первым в строке

Я пытаюсь использовать SQLContext.subtract () в Spark 1.6.1 для удаления строк из фреймворка данных на основе столбца из другого фреймворка данных. Давайте воспользуемся примером:

from pyspark.sql import Row df1 = sqlContext.createDataFrame([ Row(name='Alice', age=2), Row(name='Bob', age=1), ]).alias('df1') df2 = sqlContext.createDataFrame([ Row(name='Bob'), ]) df1_with_df2 = df1.join(df2, 'name').select('df1.*') df1_without_df2 = df1.subtract(df1_with_df2) 

Поскольку мне нужны все строки из df1 которые не включают name='Bob' я ожидаю Row(age=2, name='Alice') . Но я также забираю Боба:

 print(df1_without_df2.collect()) # [Row(age='1', name='Bob'), Row(age='2', name='Alice')] 

После различных экспериментов, чтобы перейти к этому MCVE , я узнал, что проблема связана с age . Если я опустил это:

 df1_noage = sqlContext.createDataFrame([ Row(name='Alice'), Row(name='Bob'), ]).alias('df1_noage') df1_noage_with_df2 = df1_noage.join(df2, 'name').select('df1_noage.*') df1_noage_without_df2 = df1_noage.subtract(df1_noage_with_df2) print(df1_noage_without_df2.collect()) # [Row(name='Alice')] 

Тогда я получаю Алису, как ожидалось. Самое странное замечание, которое я сделал, это то, что можно добавлять ключи, если они после (в смысле лексикографического порядка) ключ, который я использую в соединении:

 df1_zage = sqlContext.createDataFrame([ Row(zage=2, name='Alice'), Row(zage=1, name='Bob'), ]).alias('df1_zage') df1_zage_with_df2 = df1_zage.join(df2, 'name').select('df1_zage.*') df1_zage_without_df2 = df1_zage.subtract(df1_zage_with_df2) print(df1_zage_without_df2.collect()) # [Row(name='Alice', zage=2)] 

Я правильно получаю Алису (с ее zage)! В моих реальных примерах меня интересуют все столбцы, а не только те, которые после name .

One Solution collect form web for “Spark: Dataframe.subtract возвращает все, когда ключ не является первым в строке”

Ну, здесь есть некоторые ошибки (первая проблема похожа на ту же проблему, что и SPARK-6231 ), и JIRA выглядит неплохо, но SUBTRACT / EXCEPT не является правильным выбором для частичных совпадений. Вместо этого вы можете использовать anti-join:

 df1.join(df1_with_df2, ["name"], "leftanti").show() 

В 1.6 вы можете сделать почти то же самое со стандартным внешним соединением:

 import pyspark.sql.functions as F ref = df1_with_df2.select("name").alias("ref") (df1 .join(ref, ref.name == df1.name, "leftouter") .filter(F.isnull("ref.name")) .drop(F.col("ref.name"))) 
 
Interesting Posts for Van-Lav

Разделение кадра данных на несколько фреймов данных

Celery @task не работает с методами экземпляра

Дескриптор FREAK с Opencv Python

копировать значения из одного кадра данных в другой фрейм данных (разная длина) путем сравнения значений строк в python

Расширения Python C – Почему вызываемые C-функции принимают аргументы и возвращают PyObject *

Почему lxml.etree.iterparse () съедает всю мою память?

Повседневное поведение аутентификации PyPI

Как разбить смешанную строку с числами

Практический пример полиморфизма

Сколько NumPy и SciPy находится в C?

Фляга-Беспокойные свалки Десятичное значение от фляги-шквалы

Как проверить свою реализацию кодов LT?

Python Нажмите: пользовательское сообщение об ошибке

Отображение структур данных iplimage OpenCV с помощью wxPython

Как публиковать в google плюс использовать общедоступный ключ API (я хочу публиковать все действия, созданные на моем сайте, чтобы публиковать на моей + странице)

Python - лучший язык программирования в мире.