当尝试在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报告了大型数据框和仓库连接器的问题。
并且:
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处配置此设置,尽管我不确定增加该值会对性能产生影响
答案 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 的示例]