如何在不使用HDP 3.1中的仓库连接器的情况下编写表格以实现蜂巢状态

时间:2019-10-16 05:11:45

标签: apache-spark hive apache-spark-sql hdp hadoop3

当尝试在HDP 3.1上使用spark 2.3写入Hive表时,没有使用以下命令将仓库连接器直接进入蜂房模式时:

spark-shell --driver-memory 16g --master local[3] --conf spark.hadoop.metastore.catalog.default=hive
val df = Seq(1,2,3,4).toDF
spark.sql("create database foo")
df.write.saveAsTable("foo.my_table_01")

失败:

Table foo.my_table_01 failed strict managed table checks due to the following reason: Table is marked as a managed table but is not transactional

但一个:

val df = Seq(1,2,3,4).toDF.withColumn("part", col("value"))
df.write.partitionBy("part").option("compression", "zlib").mode(SaveMode.Overwrite).format("orc").saveAsTable("foo.my_table_02")

使用spark.sql("select * from foo.my_table_02").show闪烁效果很好。 现在去蜂巢/蜂巢:

0: jdbc:hive2://hostname:2181/> select * from my_table_02;
Error: java.io.IOException: java.lang.IllegalArgumentException: bucketId out of range: -1 (state=,code=0)

A

 describe extended my_table_02;

返回

 +-----------------------------+----------------------------------------------------+----------+
|          col_name           |                     data_type                      | comment  |
+-----------------------------+----------------------------------------------------+----------+
| value                       | int                                                |          |
| part                        | int                                                |          |
|                             | NULL                                               | NULL     |
| # Partition Information     | NULL                                               | NULL     |
| # col_name                  | data_type                                          | comment  |
| part                        | int                                                |          |
|                             | NULL                                               | NULL     |
| Detailed Table Information  | Table(tableName:my_table_02, dbName:foo, owner:hive/bd-sandbox.t-mobile.at@SANDBOX.MAGENTA.COM, createTime:1571201905, lastAccessTime:0, retention:0, sd:StorageDescriptor(cols:[FieldSchema(name:value, type:int, comment:null), FieldSchema(name:part, type:int, comment:null)], location:hdfs://bd-sandbox.t-mobile.at:8020/warehouse/tablespace/external/hive/foo.db/my_table_02, inputFormat:org.apache.hadoop.hive.ql.io.orc.OrcInputFormat, outputFormat:org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat, compressed:false, numBuckets:-1, serdeInfo:SerDeInfo(name:null, serializationLib:org.apache.hadoop.hive.ql.io.orc.OrcSerde, parameters:{path=hdfs://bd-sandbox.t-mobile.at:8020/warehouse/tablespace/external/hive/foo.db/my_table_02, compression=zlib, serialization.format=1}), bucketCols:[], sortCols:[], parameters:{}, skewedInfo:SkewedInfo(skewedColNames:[], skewedColValues:[], skewedColValueLocationMaps:{}), storedAsSubDirectories:false), partitionKeys:[FieldSchema(name:part, type:int, comment:null)], parameters:{numRows=0, rawDataSize=0, spark.sql.sources.schema.partCol.0=part, transient_lastDdlTime=1571201906, bucketing_version=2, spark.sql.create.version=2.3.2.3.1.0.0-78, totalSize=740, spark.sql.sources.schema.numPartCols=1, spark.sql.sources.schema.part.0={\"type\":\"struct\",\"fields\":[{\"name\":\"value\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}},{\"name\":\"part\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}}]}, numFiles=4, numPartitions=4, spark.sql.partitionProvider=catalog, spark.sql.sources.schema.numParts=1, spark.sql.sources.provider=orc, transactional=true}, viewOriginalText:null, viewExpandedText:null, tableType:MANAGED_TABLE, rewriteEnabled:false, catName:hive, ownerType:USER, writeId:-1) |

如何在不使用仓库连接器的情况下使用spark来写入蜂巢,但仍写入同一个元存储库,以便以后可以由蜂巢读取? 据我所知,应该可以使用外部表(不进行管理,不进行ACID事务处理),但是我不确定如何告诉saveAsTable如何处理这些表。

编辑

相关问题:

可能像https://github.com/qubole/spark-acid这样的变通办法,例如https://docs.cloudera.com/HDPDocuments/HDP3/HDP-3.1.4/integrating-hive/content/hive_hivewarehouseconnector_for_handling_apache_spark_data.html,但是我不喜欢使用更多胶带的想法,因为我还没有看到任何大规模的性能测试。另外,这意味着更改所有现有的火花作业。

实际上Cant save table to hive metastore, HDP 3.0报告了大型数据框和仓库连接器的问题。

编辑

我刚刚发现了https://community.cloudera.com/t5/Support-Questions/Spark-hive-warehouse-connector-not-loading-data-when-using/td-p/243613

并且:

  

execute()与executeQuery()

     

ExecuteQuery()将始终使用Hiveserver2-interactive / LLAP,因为它   使用快速箭头协议。当jdbc URL指向   非LLAP Hiveserver2将产生错误。

     

Execute()使用JDBC,并且不依赖于LLAP,但是具有   内置限制,最多只能返回1.000条记录。但是对于大多数   查询(INSERT INTO ... SELECT,计数,总和,平均值)不是   问题。

但这不会杀死蜂巢和Spark之间的任何高性能互操作性吗?尤其是如果没有足够的LLAP节点用于大规模ETL。

事实上,这是事实。可以在https://github.com/hortonworks-spark/spark-llap/blob/26d164e62b45cfa1420d5d43cdef13d1d29bb877/src/main/java/com/hortonworks/spark/sql/hive/llap/HWConf.java#L39处配置此设置,尽管我不确定增加该值会对性能产生影响

4 个答案:

答案 0 :(得分:0)

您尝试过

    data.write \
        .mode("append") \
        .insertInto("tableName")

答案 1 :(得分:0)

在Ambari内部,仅禁用默认情况下创建事务表的选项即可解决我的问题。

两次设置为false(tez,lap)

hive.strict.managed.tables = false

,并根据需要在每个table property中手动启用(以使用事务表)。

答案 2 :(得分:0)

创建一个外部表(作为一种解决方法)似乎是我的最佳选择。 这仍然需要HWC来注册列元数据或更新分区信息。

遵循以下原则:

val df:DataFrame = ...
val externalPath = "/warehouse/tablespace/external/hive/my_db.db/my_table"
import com.hortonworks.hwc.HiveWarehouseSession
val hive = HiveWarehouseSession.session(spark).build()
dxx.write.partitionBy("part_col").option("compression", "zlib").mode(SaveMode.Overwrite).orc(externalPath)
val columns = dxx.drop("part_col").schema.fields.map(field => s"${field.name} ${field.dataType.simpleString}").mkString(", ")
val ddl =
      s"""
         |CREATE EXTERNAL TABLE my_db.my_table ($columns)
         |PARTITIONED BY (part_col string)
         |STORED AS ORC 
         |Location '$externalPath'
       """.stripMargin

hive.execute(ddl)
hive.execute(s"MSCK REPAIR TABLE $tablename SYNC PARTITIONS")

不幸的是,这引发了:

java.sql.SQLException: The query did not generate a result set!

来自HWC

答案 3 :(得分:0)

<块引用>

“如何在不使用仓库连接器的情况下使用 spark 写入 hive,但仍写入相同的 Metastore,以便稍后由 hive 读取?”

我们正在处理相同的设置(HDP 3.1 和 Spark 2.3)。使用下面的代码,我们收到了与“bucketId 超出范围:-1”相同的错误消息。解决方案是在尝试查询表之前在 Hive shell 中运行 set hive.fetch.task.conversion=none;

在没有 HWC 的情况下将数据写入 Hive 的代码:

  val warehouseLocation = new File("spark-warehouse").getAbsolutePath

  case class Record(key: Int, value: String)

  val spark = SparkSession.builder()
    .master("yarn")
    .appName("SparkHiveExample")
    .config("spark.sql.warehouse.dir", warehouseLocation)
    .enableHiveSupport()
    .getOrCreate()

  spark.sql("USE databaseName")
  val recordsDF = spark.createDataFrame((1 to 100).map(i => Record(i, s"val_$i")))
  recordsDF.write.mode(SaveMode.Overwrite).format("orc").saveAsTable("sparkhive_records")

[来自 https://spark.apache.org/docs/latest/sql-data-sources-hive-tables.html 的示例]