web-dev-qa-db-ja.com

寄木細工のファイルのメタデータを使用してHiveテーブルを作成する

DataFrameを寄木細工のファイルとして作成しました。そして、寄木細工のメタデータを使用して、Hiveを使用してファイルを読み取りたいと思います。

寄木細工の書き込みからの出力

_common_metadata  part-r-00000-0def6ca1-0f54-4c53-b402-662944aa0be9.gz.parquet  part-r-00002-0def6ca1-0f54-4c53-b402-662944aa0be9.gz.parquet  _SUCCESS
_metadata         part-r-00001-0def6ca1-0f54-4c53-b402-662944aa0be9.gz.parquet  part-r-00003-0def6ca1-0f54-4c53-b402-662944aa0be9.gz.parquet

ハイブテーブル

CREATE  TABLE testhive
ROW FORMAT SERDE
  'org.Apache.hadoop.Hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
  'org.Apache.hadoop.Hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
  'org.Apache.hadoop.Hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
  '/home/gz_files/result';



FAILED: SemanticException [Error 10043]: Either list of columns or a custom serializer should be specified

寄木細工のファイルからメタデータを推測するにはどうすればよいですか?

_common_metadataを開くと、以下のコンテンツがあります。

PAR1LHroot
%TSN%
%TS%
%Etype%
)org.Apache.spark.sql.parquet.row.metadata▒{"type":"struct","fields":[{"name":"TSN","type":"string","nullable":true,"metadata":{}},{"name":"TS","type":"string","nullable":true,"metadata":{}},{"name":"Etype","type":"string","nullable":true,"metadata":{}}]}

または、メタデータファイルを解析する方法は?

7
WoodChopper

これが、Hiveテーブルを作成するために寄木細工のファイルからメタデータを取得するために私が思いついた解決策です。

最初にspark-Shellを開始します(または、すべてをJarにコンパイルして、spark-submitで実行しますが、Shellの方がはるかに簡単です)

_import org.Apache.spark.sql.Hive.HiveContext
import org.Apache.spark.sql.DataFrame


val df=sqlContext.parquetFile("/path/to/_common_metadata")

def creatingTableDDL(tableName:String, df:DataFrame): String={
  val cols = df.dtypes
  var ddl1 = "CREATE EXTERNAL TABLE "+tableName + " ("
  //looks at the datatypes and columns names and puts them into a string
  val colCreate = (for (c <-cols) yield(c._1+" "+c._2.replace("Type",""))).mkString(", ")
  ddl1 += colCreate + ") STORED AS PARQUET LOCATION '/wherever/you/store/the/data/'"
  ddl1
}

val test_tableDDL=creatingTableDDL("test_table",df,"test_db")
_

これにより、Parquetに格納されるときにHiveが各列に使用するデータ型が提供されます。例:CREATE EXTERNAL TABLE test_table (COL1 Decimal(38,10), COL2 String, COL3 Timestamp) STORED AS PARQUET LOCATION '/path/to/parquet/files'

11
James Tobin

ジェームズ・トービンの答えをさらに詳しく説明したいと思います。文字列の置換を行わずにHiveのデータ型を提供するStructFieldクラスがあります。

// Tested on Spark 1.6.0.

import org.Apache.spark.sql.DataFrame

def dataFrameToDDL(dataFrame: DataFrame, tableName: String): String = {
    val columns = dataFrame.schema.map { field =>
        "  " + field.name + " " + field.dataType.simpleString.toUpperCase
    }

    s"CREATE TABLE $tableName (\n${columns.mkString(",\n")}\n)"
}

これにより、IntegerTypeの問題が解決されます。

scala> val dataFrame = sc.parallelize(Seq((1, "a"), (2, "b"))).toDF("x", "y")
dataFrame: org.Apache.spark.sql.DataFrame = [x: int, y: string]

scala> print(dataFrameToDDL(dataFrame, "t"))
CREATE TABLE t (
  x INT,
  y STRING
)

これは、Parquetだけでなく、すべてのDataFrameで機能するはずです。 (たとえば、これをJDBC DataFrameで使用しています。)

追加のボーナスとして、ターゲットDDLがNULL可能列をサポートしている場合は、StructField.nullableをチェックして関数を拡張できます。

8
Victor Lam

Victorを少し改善し(field.nameに引用符を追加)、テーブルをローカル寄木細工のファイルにバインドするように変更しました(spark 1.6.1)でテスト済み)

def dataFrameToDDL(dataFrame: DataFrame, tableName: String, absFilePath: String): String = {
    val columns = dataFrame.schema.map { field =>
      "  `" + field.name + "` " + field.dataType.simpleString.toUpperCase
    }
    s"CREATE EXTERNAL TABLE $tableName (\n${columns.mkString(",\n")}\n) STORED AS PARQUET LOCATION '"+absFilePath+"'"
  }

また、次の点にも注意してください。

  • SQLContextは外部テーブルの作成をサポートしていないため、HiveContextが必要です。
  • 寄木細工のフォルダーへのパスは絶対パスである必要があります
1
Jordi Atserias

ジェームズの答えを広げたいのですが、

次のコードは、ARRAY、MAP、STRUCTを含むすべてのデータ型で機能します。

SPARK 2.2でテスト済み

val df=sqlContext.parquetFile("parquetFilePath")
val schema = df.schema
var columns = schema.fields
var ddl1 = "CREATE EXTERNAL TABLE " tableName + " ("
val cols=(for(column <- columns) yield column.name+" "+column.dataType.sql).mkString(",")
ddl1=ddl1+cols+" ) STORED AS PARQUET LOCATION '/tmp/Hive_test1/'"
spark.sql(ddl1)
1

同じ質問がありました。ただし、Parquetはスキーマの進化をサポートしているため、実用的な側面から実装するのは難しいかもしれません。

http://www.cloudera.com/content/www/en-us/documentation/archive/impala/2-x/2-0-x/topics/impala_parquet.html#parquet_schema_evolution_unique_1

たとえば、テーブルに新しい列を追加でき、テーブルに既に存在するデータに触れる必要はありません。新しいデータファイルに新しいメタデータ(以前のバージョンと互換性がある)があるのはそれだけです。

Spark 1.5.0は「比較的コストのかかる操作」であるため、スキーマのマージはデフォルトでオフになっています http://spark.Apache.org/docs/latest/sql-programming -guide.html#schema-merging したがって、最新のスキーマを推測することは、思ったほど簡単ではない可能性があります。

$ parquet-tools schema /home/gz_files/result/000000_0
0
Tagar

実際、Impalaはサポートしています

CREATE TABLE LIKE PARQUET

(列セクションはまったくありません):

http://www.cloudera.com/content/www/en-us/documentation/archive/impala/2-x/2-1-x/topics/impala_create_table.html

あなたの質問のタグには「Hive」と「spark」があり、これがHiveに実装されているとは思いませんが、CDHを使用している場合は、探していたものである可能性があります。

0
Tagar