← Назад к вопросам

Что такое LEFT ANTI JOIN в PySpark?

2.0 Middle🔥 191 комментариев
#Big Data и распределенные вычисления#SQL и базы данных

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

LEFT ANTI JOIN в PySpark

LEFT ANTI JOIN — это операция объединения двух таблиц, которая возвращает все строки из левой таблицы, которые НЕ имеют соответствия в правой таблице.

Синтаксис PySpark

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName("Example").getOrCreate()

# Левая таблица
left_df = spark.createDataFrame([
    (1, "Alice"),
    (2, "Bob"),
    (3, "Charlie"),
    (4, "David")
], ["user_id", "name"])

# Правая таблица
right_df = spark.createDataFrame([
    (1, "premium"),
    (3, "free"),
    (5, "admin")
], ["user_id", "plan"])

# LEFT ANTI JOIN
result = left_df.join(right_df, on="user_id", how="leftanti")

result.show()
# +-------+-------+
# |user_id|   name|
# +-------+-------+
# |      2|    Bob|
# |      4|  David|
# +-------+-------+

Почему 2 и 4?

  • user_id = 1: есть в правой таблице → исключена
  • user_id = 2: НЕТ в правой таблице → ВКЛЮЧЕНА
  • user_id = 3: есть в правой таблице → исключена
  • user_id = 4: НЕТ в правой таблице → ВКЛЮЧЕНА

Диаграмма

Левая таблица        Правая таблица
┌─────┬─────┐       ┌─────┬─────────┐
│ uid │name │       │ uid │  plan   │
├─────┼─────┤       ├─────┼─────────┤
│  1  │Alice│       │  1  │premium  │
│  2  │ Bob │       │  3  │ free    │
│  3  │Char │       │  5  │ admin   │
│  4  │David│       └─────┴─────────┘
└─────┴─────┘

LEFT ANTI JOIN:
┌─────┬─────┐
│ uid │name │  (только строки из левой,
├─────┼─────┤   которых нет в правой)
│  2  │ Bob │
│  4  │David│
└─────┴─────┘

Практические примеры

1. Найти пользователей без заказов

users = spark.createDataFrame([
    (1, "Alice"),
    (2, "Bob"),
    (3, "Charlie")
], ["user_id", "name"])

orders = spark.createDataFrame([
    (1, 100),
    (1, 200),
    (3, 300)
], ["user_id", "order_amount"])

# Пользователи БЕЗ заказов
users_no_orders = users.join(orders, on="user_id", how="leftanti")
users_no_orders.show()
# +-------+----+
# |user_id|name|
# +-------+----+
# |      2| Bob|
# +-------+----+

2. Найти товары, которые не были куплены

products = spark.createDataFrame([
    ("A", 100), ("B", 200), ("C", 300), ("D", 400)
], ["product_id", "price"])

purchases = spark.createDataFrame([
    ("A",), ("B",), ("C",)
], ["product_id"])

# Товары, которые никто не купил
unpopular = products.join(purchases, on="product_id", how="leftanti")
unpopular.show()
# +----------+-----+
# |product_id|price|
# +----------+-----+
# |         D|  400|
# +----------+-----+

3. Найти аномальные транзакции

transactions = spark.createDataFrame([
    ("T1", 100, "2024-01-01"),
    ("T2", 200, "2024-01-02"),
    ("T3", 50, "2024-01-03"),
    ("T4", 300, "2024-01-04")
], ["transaction_id", "amount", "date"])

legitimate = spark.createDataFrame([
    ("T1",), ("T2",), ("T4",)
], ["transaction_id"])

# Подозрительные транзакции (не в списке легитимных)
suspicious = transactions.join(
    legitimate, 
    on="transaction_id", 
    how="leftanti"
)
suspicious.show()
# +----------------+------+----------+
# |transaction_id  |amount|date      |
# +----------------+------+----------+
# |T3              |50    |2024-01-03|
# +----------------+------+----------+

LEFT ANTI JOIN vs другие JOINs

# Имеем:
left  = [(1, 'A'), (2, 'B'), (3, 'C')]
right = [(1, 'X'), (3, 'Y'), (5, 'Z')]

# INNER JOIN
# → [(1, 'A', 'X'), (3, 'C', 'Y')]  (только совпадения)

# LEFT JOIN
# → [(1, 'A', 'X'), (2, 'B', None), (3, 'C', 'Y')]
# (все из левой + совпадения)

# LEFT ANTI JOIN
# → [(2, 'B')]  (только строки из левой БЕЗ совпадений)

# LEFT SEMI JOIN (похож на ANTI, но без столбцов из правой)
# → [(1, 'A'), (3, 'C')]  (строки из левой, У КОТОРЫХ есть совпадения)

Performance примечание

# LEFT ANTI JOIN требует большой памяти на правую таблицу
# Оптимизация: broadcast небольшую правую таблицу

from pyspark.sql.functions import broadcast

result = left_df.join(
    broadcast(right_df),  # для маленьких таблиц
    on="user_id",
    how="leftanti"
)

Эквивалент в SQL

-- LEFT ANTI JOIN в PySpark
left_df.join(right_df, on="user_id", how="leftanti")

-- Эквивалент в SQL
SELECT * FROM left_table
WHERE user_id NOT IN (SELECT user_id FROM right_table);

-- или
SELECT left.*
FROM left_table left
LEFT ANTI JOIN right_table right ON left.user_id = right.user_id;

Резюме

LEFT ANTI JOIN:

  • Возвращает строки из левой таблицы без совпадений в правой
  • Полезен для: поиска отсутствующих данных, исключения записей
  • Синтаксис: df1.join(df2, on=key, how="leftanti")
  • Отличается от LEFT JOIN (который включает все из левой)
  • Эффективнее, чем NOT IN для больших данных