จะตรวจสอบได้อย่างไรว่า spark dataframe ว่างเปล่า


105

ตอนนี้ฉันต้องใช้df.count > 0เพื่อตรวจสอบว่าDataFrameว่างหรือไม่ แต่มันไม่มีประสิทธิภาพ มีวิธีไหนที่ดีกว่านี้ไหม?

ขอบคุณ.

PS: ฉันต้องการตรวจสอบว่าว่างหรือไม่เพื่อที่ฉันจะบันทึกเฉพาะDataFrameถ้ามันไม่ว่าง

คำตอบ:


157

สำหรับ Spark 2.1.0 ข้อเสนอแนะของฉันคือใช้head(n: Int)หรือtake(n: Int)กับข้อisEmptyใดก็ได้ที่มีเจตนาชัดเจนที่สุดสำหรับคุณ

df.head(1).isEmpty
df.take(1).isEmpty

เทียบเท่ากับ Python:

len(df.head(1)) == 0  # or bool(df.head(1))
len(df.take(1)) == 0  # or bool(df.take(1))

การใช้df.first()และdf.head()ทั้งสองจะส่งคืนjava.util.NoSuchElementExceptionหาก DataFrame ว่างเปล่า first()โทรhead()โดยตรงซึ่งโทรhead(1).head.

def first(): T = head()
def head(): T = head(1).head

head(1)ส่งคืน Array ดังนั้นการรับheadArray จะทำให้java.util.NoSuchElementExceptionเมื่อ DataFrame ว่างเปล่า

def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)

ดังนั้นแทนที่จะโทรhead()ให้ใช้head(1)โดยตรงเพื่อรับอาร์เรย์จากนั้นคุณสามารถisEmptyใช้ได้

take(n)ยังเทียบเท่ากับhead(n)...

def take(n: Int): Array[T] = head(n)

และlimit(1).collect()เทียบเท่ากับhead(1)(ข้อสังเกตlimit(n).queryExecutionในhead(n: Int)วิธีการ) ดังนั้นสิ่งต่อไปนี้จึงเทียบเท่าทั้งหมดอย่างน้อยก็จากสิ่งที่ฉันบอกได้และคุณจะไม่ต้องพบjava.util.NoSuchElementExceptionข้อยกเว้นเมื่อ DataFrame ว่างเปล่า

df.head(1).isEmpty
df.take(1).isEmpty
df.limit(1).collect().isEmpty

ฉันรู้ว่านี่เป็นคำถามที่เก่ากว่าดังนั้นหวังว่าจะช่วยให้ผู้ใช้ Spark เวอร์ชันใหม่กว่านี้ได้


20
สำหรับผู้ที่ใช้ pyspark isEmpty ไม่ใช่สิ่งของ ทำ len (d.head (1))> 0 แทน
AntiPawn79

5
ทำไมถึงดีกว่านี้df.rdd.isEmpty?
Dan Ciborowski - MSFT

1
df.head (1) .isEmpty ใช้เวลามากมีวิธีอื่นที่เหมาะสมที่สุดสำหรับสิ่งนี้หรือไม่
Rakesh Sabbani

1
เฮ้ @Rakesh Sabbani ถ้าdf.head(1)ใช้เวลามากอาจเป็นเพราะdfแผนการดำเนินการของคุณกำลังทำบางสิ่งที่ซับซ้อนซึ่งป้องกันไม่ให้ประกายไฟจากการใช้ทางลัด ตัวอย่างเช่นหากคุณเพิ่งอ่านจากไฟล์ไม้ปาร์เก้df = spark.read.parquet(...)ฉันค่อนข้างมั่นใจว่า spark จะอ่านพาร์ติชันไฟล์เดียวเท่านั้น แต่ถ้าคุณdfกำลังทำสิ่งอื่น ๆ เช่นการรวมคุณอาจถูกบังคับโดยไม่ได้ตั้งใจบังคับให้ Spark อ่านและประมวลผลแหล่งข้อมูลส่วนใหญ่หากไม่ใช่ทั้งหมด
hulin003

เพียงแค่รายงานประสบการณ์ของฉันเพื่อหลีกเลี่ยง: ฉันใช้df.limit(1).count()อย่างไร้เดียงสา ในชุดข้อมูลขนาดใหญ่ต้องใช้เวลามากกว่าตัวอย่างที่รายงานโดย @ hulin003 ซึ่งเกือบจะเกิดขึ้นในทันที
Vzzarr

47

RDDผมจะบอกว่าเพียงแค่คว้าพื้นฐาน ใน Scala:

df.rdd.isEmpty

ใน Python:

df.rdd.isEmpty()

ที่พูดมาทั้งหมดนี้คือการโทรtake(1).lengthดังนั้นมันจะทำแบบเดียวกับที่โรฮันตอบ ... อาจจะชัดเจนกว่านี้เล็กน้อย?


6
นี่ช้ากว่า df.count () == 0 อย่างน่าตกใจในกรณีของฉัน
สถาปัตยกรรม

2
การแปลง rdd เป็นงานหนักไม่ใช่เหรอ
Alok

1
ไม่จริง. RDD ยังคงเป็นส่วนสำคัญของทุกสิ่งที่ Spark เป็นส่วนใหญ่
Justin Pihony

28
อย่าแปลง df เป็น RDD มันทำให้กระบวนการช้าลง หากคุณแปลงจะแปลง DF ทั้งหมดเป็น RDD และตรวจสอบว่าว่างเปล่า ลองคิดดูว่าถ้า DF มีแถวเป็นล้านแถวจะต้องใช้เวลามากในการแปลงเป็น RDD เอง
Nandakishore

3
.rdd ทำให้กระบวนการทำงานช้าลงมาก
Raul H

14

คุณสามารถใช้ประโยชน์จากฟังก์ชันhead()(หรือfirst()) เพื่อดูว่าDataFrameมีแถวเดียวหรือไม่ ถ้าเป็นเช่นนั้นก็ไม่ว่างเปล่า


10
ถ้า dataframe ว่างเปล่ามันจะพ่น "java.util.NoSuchElementException: next on empty iterator"; [Spark 1.3.1]
FelixHo

8

ตั้งแต่ Spark 2.4.0 มีDataset.isEmpty.

มันดำเนินการคือ

def isEmpty: Boolean = 
  withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
    plan.executeCollect().head.getLong(0) == 0
}

โปรดทราบว่า a DataFrameไม่ใช่คลาสใน Scala อีกต่อไป แต่เป็นเพียงนามแฝงประเภท (อาจเปลี่ยนด้วย Spark 2.0):

type DataFrame = Dataset[Row]

1
isEmpty ช้ากว่า df.head (1) .isEmpty
Sandeep540

@ Sandeep540 จริงเหรอ? เกณฑ์มาตรฐาน? ข้อเสนอของคุณสร้างอินสแตนซ์อย่างน้อยหนึ่งแถว การใช้งาน Spark เพียงแค่ส่งข้อมูลตัวเลข head () ใช้ขีด จำกัด () เช่นกัน groupBy () ไม่ได้ทำอะไรเลยจำเป็นต้องได้รับ RelationalGroupedDataset ซึ่งจะให้ count () ดังนั้นไม่ควรช้าลงอย่างมาก อาจเร็วกว่าในกรณีของชุดข้อมูลที่มีคอลัมน์จำนวนมาก (อาจเป็นข้อมูลที่ซ้อนกันโดยปกติ) คุณต้องพิมพ์น้อยลง :-)
Beryllium

7

ถ้าคุณทำdf.count > 0. จะนับพาร์ติชันทั้งหมดในตัวดำเนินการทั้งหมดและเพิ่มที่ Driver การดำเนินการนี้ใช้เวลาสักครู่เมื่อคุณจัดการกับแถวนับล้าน

วิธีที่ดีที่สุดคือดำเนินการdf.take(1)และตรวจสอบว่าโมฆะหรือไม่ สิ่งนี้จะกลับมาjava.util.NoSuchElementExceptionดีกว่าที่จะลองdf.take(1)ใช้

dataframe ส่งคืนข้อผิดพลาดเมื่อtake(1)เสร็จสิ้นแทนที่จะเป็นแถวว่าง ฉันได้เน้นบรรทัดรหัสเฉพาะที่มันแสดงข้อผิดพลาด

ป้อนคำอธิบายภาพที่นี่


1
หากคุณเรียกใช้สิ่งนี้บนดาต้าเฟรมขนาดใหญ่ที่มีระเบียนนับล้านรายการcountวิธีนี้จะใช้เวลาพอสมควร
TheM00s3

2
ฉันก็พูดเหมือนกันฉันไม่แน่ใจว่าทำไมคุณถึงยกนิ้วให้
Nandakishore

สิทธิ์ของคุณคุณพูดเหมือนกันโชคร้ายฉันไม่ได้ลงคะแนนให้คุณ
TheM00s3

โอเค ฉันขอโทษ TheMoos3 แต่ใครก็ตามที่ทำโปรดสังเกตคำตอบและทำความเข้าใจแนวคิด
Nandakishore

โดยใช้ df.take (1) เมื่อ df เป็นผลลัพธ์ว่างในการรับ ROW ที่ว่างเปล่าซึ่งไม่สามารถเปรียบเทียบกับ null ได้
LetsPlayYahtzee

5

สำหรับผู้ใช้ Java คุณสามารถใช้สิ่งนี้กับชุดข้อมูล:

public boolean isDatasetEmpty(Dataset<Row> ds) {
        boolean isEmpty;
        try {
            isEmpty = ((Row[]) ds.head(1)).length == 0;
        } catch (Exception e) {
            return true;
        }
        return isEmpty;
}

สิ่งนี้ตรวจสอบสถานการณ์ที่เป็นไปได้ทั้งหมด (ว่างเปล่าว่าง)


4

ใน Scala คุณสามารถใช้นัยเพื่อเพิ่มวิธีการisEmpty()และnonEmpty()ไปยัง DataFrame API ซึ่งจะทำให้โค้ดอ่านง่ายขึ้น

object DataFrameExtensions {
  implicit def extendedDataFrame(dataFrame: DataFrame): ExtendedDataFrame = 
    new ExtendedDataFrame(dataFrame: DataFrame)

  class ExtendedDataFrame(dataFrame: DataFrame) {
    def isEmpty(): Boolean = dataFrame.head(1).isEmpty // Any implementation can be used
    def nonEmpty(): Boolean = !isEmpty
  }
}

ที่นี่สามารถเพิ่มวิธีการอื่น ๆ ได้เช่นกัน หากต้องการใช้การแปลงโดยนัยให้ใช้import DataFrameExtensions._ในไฟล์ที่คุณต้องการใช้ฟังก์ชันเพิ่มเติม หลังจากนั้นสามารถใช้วิธีการได้โดยตรงดังนี้:

val df: DataFrame = ...
if (df.isEmpty) {
  // Do something
}

3

ฉันมีคำถามเดียวกันและฉันทดสอบ 3 วิธีแก้ปัญหาหลัก:

  1. df! = null df.count> 0
  2. df.head (1) .isEmpty () ตามที่ @ hulin003 แนะนำ
  3. df.rdd.isEmpty ตามที่ @Justin Pihony แนะนำ

และแน่นอนว่าทั้ง 3 ทำงานได้อย่างไรก็ตามในแง่ของความสมบูรณ์นี่คือสิ่งที่ฉันพบเมื่อดำเนินการตามวิธีการเหล่านี้บน DF เดียวกันในเครื่องของฉันในระยะเวลาดำเนินการ:

  1. ใช้เวลา ~ 9366ms
  2. ใช้เวลา ~ 5607ms
  3. ใช้เวลา ~ 1921ms

ดังนั้นฉันคิดว่าทางออกที่ดีที่สุดคือdf.rdd.isEmpty ตามที่ @Justin Pihony แนะนำ


1
ตัวเลือกที่ 3 ใช้เวลาน้อยลงทำไมถึงเลือกที่สอง?
คิด

อ๊ะคุณใช่ฉันใช้ครั้งที่ 3 ฉันอัปเดตคำตอบ
aName

1
ด้วยความอยากรู้อยากเห็น ... สิ่งนี้ทดสอบด้วย DataFrames ขนาดใด
aiguofer

1

ฉันพบว่าในบางกรณี:

>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>

>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty'

สิ่งนี้เหมือนกันสำหรับ "length" หรือแทนที่ take () by head ()

[วิธีแก้ไข] สำหรับปัญหาที่เราสามารถใช้ได้

>>>df.limit(2).count() > 1
False


1

เมื่อวันที่ PySpark คุณยังสามารถใช้วิธีนี้bool(df.head(1))จะได้รับTrueของFalseมูลค่า

จะส่งคืนFalseหาก dataframe ไม่มีแถว


0
df1.take(1).length>0

วิธีการส่งกลับอาร์เรย์ของแถวดังนั้นถ้าขนาดอาร์เรย์เท่ากับศูนย์มีบันทึกในไม่มีtakedf


-1

dataframe.limit(1).count > 0

สิ่งนี้ยังทำให้เกิดงาน แต่เนื่องจากเรากำลังเลือกระเบียนเดียวแม้ว่าในกรณีที่มีการบันทึกระดับพันล้านการใช้เวลาอาจลดลงมาก

จาก: https://medium.com/checking-emptiness-in-distributed-objects/count-vs-isempty-surprised-to-see-the-impact-fa70c0246ee0


ทั้งหมดนี้เป็นตัวเลือกที่ไม่ดีที่ใช้เวลาเกือบเท่ากัน
Pushpendra Jaiswal

@PushpendraJaiswal ใช่และในโลกแห่งตัวเลือกที่ไม่ดีเราควรเลือกตัวเลือกที่ไม่ดีที่สุด
Jordan Morris

-2

คุณสามารถทำได้เช่น:

val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
    println("empty df ")
else 
    println("normal df")

1
จะไม่ต้องการให้schemaสองดาต้าเฟรม ( sqlContext.emptyDataFrame& df) เหมือนกันเพื่อที่จะกลับมาอีกtrueหรือไม่?
y2k-shubham

1
วิธีนี้ใช้ไม่ได้ eqได้รับการสืบทอดมาจากAnyRefและทดสอบว่าอาร์กิวเมนต์ (นั้น) เป็นการอ้างอิงถึงวัตถุตัวรับหรือไม่ (สิ่งนี้)
Alper t. Turker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.