2025, Oct 17 02:31

PySpark में array structs को wanted_ids से फ़िल्टर करने का सही तरीका

PySpark में array structs को per-row wanted_ids के आधार पर फ़िल्टर करना जानें: expr में Python in से होने वाली syntax error से बचें और filter में array_contains का सही उपयोग करें.

PySpark में Structs वाली array कॉलम को फ़िल्टर करना एक आम ज़रूरत है: हर पंक्ति में आपके पास events की एक array होती है और साथ में ids की एक दूसरी array, जो बताती है किन events को रखना है। मुश्किल तब आती है जब expr के अंदर Python का in ऑपरेटर लगाने की कोशिश करते हैं; जैसा आप उम्मीद करते हैं वैसा काम करने के बजाय यह syntax error दे देता है।

समस्या की रूपरेखा

कल्पना करें कि आपके पास एक DataFrame है, जिसमें activities नाम का कॉलम है, जिसका प्रकार array<struct<id, time>> है, और दूसरा कॉलम wanted_ids है जो हर पंक्ति के लिए रखने वाले ids की सूची रखता है। जब फ़िल्टर की शर्त किसी एक integer id को संदर्भित करती है, तो यह पैटर्न बिना बाधा के काम करता है।

from pyspark.sql import functions as Fn
dataset = dataset.withColumn(
    'kept_time',
    Fn.expr('filter(activities, it -> it.id == wanted_id)').getField('time')
)

लेकिन जैसे ही wanted_id एक array कॉलम बन जाता है और आप == को in में बदलने की कोशिश करते हैं, expression parser विफल हो जाता है।

from pyspark.sql import functions as Fn
dataset = dataset.withColumn(
    'kept_events',
    Fn.expr('filter(activities, it -> it.id in wanted_ids)')
)

यह क्यों काम नहीं करता

expr फ़ंक्शन Python के in ऑपरेटर को array सदस्यता जाँच के लिए किसी वैध Spark SQL कॉन्स्ट्रक्ट में रूपांतरित नहीं करता। Spark SQL में किसी तत्व के array में मौजूद होने की मानक जाँच array_contains है। इस संदर्भ में in का उपयोग वैध शर्त बनने के बजाय syntax error पैदा करता है।

समाधान

filter के lambda के अंदर expr में array_contains का इस्तेमाल करें। इससे लॉजिक प्रति-पंक्ति बना रहता है, हर struct.id की तुलना उसी पंक्ति वाली array से होती है, और केवल वे events लौटते हैं जो मेल खाते हैं।

from pyspark.sql import functions as Fn
dataset = dataset.withColumn(
    'kept_events',
    Fn.expr('filter(activities, it -> array_contains(wanted_ids, it.id))')
)

यदि आपको सिर्फ़ फ़िल्टर हुए events का time फ़ील्ड चाहिए, तो प्राप्त array of structs से उसे निकाल लें।

from pyspark.sql import functions as Fn
dataset = dataset.withColumn(
    'kept_times',
    Fn.expr('filter(activities, it -> array_contains(wanted_ids, it.id))').getField('time')
)

यह क्यों मायने रखता है

expr के भीतर array कॉलम पर सदस्यता जाँच प्रकट करने का भरोसेमंद तरीका array_contains ही है। यह parser त्रुटियों से बचाता है, पूरा लॉजिक Spark SQL में रखता है, और पंक्ति-दर-पंक्ति array<struct> डेटा को साफ़-सुथरे ढंग से फ़िल्टर करता है।

मुख्य बातें

जब किसी per-row ids सूची के आधार पर structs की array को फ़िल्टर करना हो, expr के अंदर Python का in ऑपरेटर न इस्तेमाल करें। शर्त को सीधे Spark SQL में व्यक्त करने के लिए filter के भीतर array_contains पर भरोसा करें। और यदि फ़िल्टर हुए structs से कोई विशेष फ़ील्ड चाहिए, तो परिणाम पर getField से उसे एक्सेस करें।

यह लेख StackOverflow पर प्रश्न (लेखक: Nourless) और jei के उत्तर पर आधारित है।