2015-09-21 22 views
13

Sử dụng Spark 1.5.0 và đưa ra mã sau, tôi hy vọng unionAll thành union DataFrame s dựa trên tên cột của chúng. Trong đoạn mã, tôi đang sử dụng một số FunSuite để thông qua trong SparkContext sc:Điều gì đang xảy ra với `unionAll` của Spark` DataFrame`?

object Entities { 

    case class A (a: Int, b: Int) 
    case class B (b: Int, a: Int) 

    val as = Seq(
    A(1,3), 
    A(2,4) 
) 

    val bs = Seq(
    B(5,3), 
    B(6,4) 
) 
} 

class UnsortedTestSuite extends SparkFunSuite { 

    configuredUnitTest("The truth test.") { sc => 
    val sqlContext = new SQLContext(sc) 
    import sqlContext.implicits._ 
    val aDF = sc.parallelize(Entities.as, 4).toDF 
    val bDF = sc.parallelize(Entities.bs, 4).toDF 
    aDF.show() 
    bDF.show() 
    aDF.unionAll(bDF).show 
    } 
} 

Output:

+---+---+ 
| a| b| 
+---+---+ 
| 1| 3| 
| 2| 4| 
+---+---+ 

+---+---+ 
| b| a| 
+---+---+ 
| 5| 3| 
| 6| 4| 
+---+---+ 

+---+---+ 
| a| b| 
+---+---+ 
| 1| 3| 
| 2| 4| 
| 5| 3| 
| 6| 4| 
+---+---+ 

Tại sao kết quả chứa trộn lẫn "b" và "a" cột, thay vì sắp xếp cột dựa trên tên cột? Có vẻ như một lỗi nghiêm trọng lỗi !?

Trả lời

26

Trông không giống như lỗi. Những gì bạn thấy là hành vi SQL chuẩn và mọi RDMBS chính, bao gồm PostgreSQL, MySQL, OracleMS SQL hoạt động giống hệt nhau. Bạn sẽ tìm thấy các ví dụ SQL Fiddle được liên kết với các tên.

Để báo PostgreSQL manual:

Để tính toán các công đoàn, ngã tư, hay sự khác biệt của hai truy vấn, hai truy vấn phải "tương thích công đoàn", có nghĩa là họ trở về cùng số cột và các cột tương ứng có các loại dữ liệu tương thích

Tên cột, không bao gồm bảng đầu tiên trong thao tác thiết lập, đơn giản bị bỏ qua.

Hành vi này trực tiếp tạo thành Đại số quan hệ nơi khối xây dựng cơ bản là một bộ tuple. Kể từ khi bộ dữ liệu được đặt hàng một công đoàn của hai bộ tuples là tương đương (bỏ qua xử lý trùng lặp) để sản lượng bạn nhận được ở đây.

Nếu bạn muốn kết hợp sử dụng tên bạn có thể làm một cái gì đó như thế này

import org.apache.spark.sql.DataFrame 
import org.apache.spark.sql.functions.col 

def unionByName(a: DataFrame, b: DataFrame): DataFrame = { 
    val columns = a.columns.toSet.intersect(b.columns.toSet).map(col).toSeq 
    a.select(columns: _*).unionAll(b.select(columns: _*)) 
} 

Để kiểm tra cả hai tên và các loại đó là nên có đủ để thay thế columns với:

a.dtypes.toSet.intersect(b.dtypes.toSet).map{case (c, _) => col(c)}.toSeq 
+1

Thx! Nó không phải là một vấn đề thực sự, như ít nhất trong trường hợp của tôi, thứ tự cột cần được thay đổi. Mặc dù, có thông tin này trong tài liệu Scala sẽ hữu ích và ngăn ngừa lỗi. Tuy nhiên, tôi sẽ cung cấp một 'unionAllVia ColumnNames' sắp xếp lại các cột, sao cho chúng phù hợp theo kiểu 1: 1, nếu có thể. –

+0

@MartinSenne Trên thực tế, tài liệu Scala cung cấp cho bạn thông tin đủ để tìm ra hành vi chính xác được mô tả trong câu trả lời được chấp nhận. Cụ thể, 'Điều này tương đương với UNION ALL trong SQL ' – kasur

+0

@MartinSenne để chỉ ra thứ tự các hàng. Điều này cần phải được đề cập trong tài liệu. –

0

Như được thảo luận trong SPARK-9813, có vẻ như miễn là các loại dữ liệu và số lượng cột giống nhau trên các khung, thì công thức Tất cả sẽ hoạt động. Vui lòng xem các ý kiến ​​để thảo luận thêm.

+1

Nếu thứ tự các cột khác nhau thì phải không? – sau

2

Vấn đề này là nhận được cố định trong spark2.3. Họ đang thêm hỗ trợ của unionByName trong tập dữ liệu.

https://issues.apache.org/jira/browse/SPARK-21043 
Các vấn đề liên quan