Spark——Spark读Elasticsearch Index索引报错存在重复列名

问题背景

在通过Spark读取Elasticsearch的索引并映射成结构化的表,写入到Hive的时候,报错存在同名的列名/字段名。查看Elasticsearch对应index发现,index存在字段名相同但其中某些字母大小写不同的字段(例如,同一个index存在gmtCreate和gmtcreate)。

因为Elasticsearch index中字段默认是大小写敏感的,也就是说,可以存在我们刚才描述的那种情况。而Hive中表列名是大小写不敏感的,Spark读Elasticsearch index转成Dataframe之后,会将index中的字段名全都转成小写,那么在写入Hive的时候,就会报错说存在重名的列。

此处也给出,Spark整合Elasticsearch的Maven依赖:

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch-spark_2.11</artifactId>
    <version>2.4.1</version>
</dependency>

解决方法

那么,如果想要把ES index索引存入Hive,我们需要对重名列进行重命名。

  1. 当通过Spark将Elasticsearch index转成DataFrame的时候,我们需要保持列名的大小写敏感,而Spark SQL默认情况下对列名是大小写不敏感的,所以我们需要配置参数spark.sql.caseSensitive来开启列名的大小写敏感;
    val spark = SparkSession
                   .builder()
                   .appName("es index")
                   .config("es.nodes", "node-1,node-2,node-3,node-4,node-5")
                   .config("es.port", "9200")
                   .config("pushdown", "true")
                   .config("spark.sql.caseSensitive", "true") //列名大小写敏感
                   .enableHiveSupport()
                   .getOrCreate()
    
  2. 找出重名的列,并进行相应的处理
    import org.elasticsearch.spark._ 
    
    def process(spark: SparkSession): Unit = {
        import spark.implicits._
        //读取Elasticsearch索引加载为Spark RDD
        val rdd: RDD[(String, String)] = spark.sparkContext.esJsonRDD(index)
                    .map(m => (m._1.toString, m._2.toString))
        
        //将Tuple类型的RDD转成Dataset
        val ds = spark.createDataset(rdd)
        			.toDF("doc_id", "source")
                    .mapPartitions(iterator => {
                        iterator.map(m => {
                            JSON.parseObject(m.getAs("source").toString).toString
                        })
                    })
            var df = spark.read.json(ds)
    		//获取Dataframe中所有列名
            val columns = df.columns
            //将所有列名都转成小写
            val columnsDistinct = columns.map(_.toLowerCase()).distinct
    
            //是否有重复列
            if (columns.length != columnsDistinct) {
                val set = new mutable.HashSet[String]()
                //保存重复列
                val duplicatedCols = mutable.ArrayBuffer[String]()
                for (col <- columns) {
                    if (set.contains(col.toLowerCase)) {
                        duplicatedCols.append(col)
                    } else {
                        set.add(col.toLowerCase)
                    }
                }
                //对重复列进行重命名
                for (col <- duplicatedCols) {
                    df = df.withColumnRenamed(col, col + "_1")
                }
            }
    
            df
                        .repartition(3)
                        .write
                        .mode("overwrite")
                        .format("parquet")
                        .saveAsTable(s"db.table")
    }
    

参考

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要清洗Elasticsearch(ES)索引中的数据,您可以使用Spark来执行以下步骤: 1. 首先,您需要使用Elasticsearch Hadoop库将Spark与ES进行集成。您可以通过将以下依赖项添加到您的Spark项目中的build.sbt文件来实现此目的: ```scala libraryDependencies += "org.elasticsearch" % "elasticsearch-hadoop" % "7.10.2" ``` 2. 在Spark应用程序中,导入必要的库: ```scala import org.elasticsearch.spark._ ``` 3. 使用以下代码片段在Spark中清洗ES索引数据: ```scala val sparkConf = new SparkConf().setAppName("CleanESData").setMaster("local") sparkConf.set("es.index.auto.create", "false") // 防止自动创建索引 val spark = SparkSession.builder().config(sparkConf).getOrCreate() val esOptions = Map( "es.nodes" -> "localhost", // ES节点地址 "es.port" -> "9200", // ES端口号 "es.resource" -> "your_index_name/your_document_type", // 索引名称和文档类型(如果有) "es.query" -> "?q=your_query" // 查询条件,用于筛选要清洗的文档 ) val rdd = spark.sparkContext.emptyRDD[Int] rdd.saveToEs(esOptions) ``` 在上面的代码中,将`your_index_name`替换为您要清洗数据的ES索引名称,并将`your_document_type`替换为相应的文档类型。如果没有指定文档类型,请将其留空。将`your_query`替换为适合您的需求的查询条件,以筛选要清洗的文档。 4. 运行Spark应用程序以清洗ES索引中的数据。确保您的Spark应用程序具有足够的权限来访问和修改ES索引。 请注意,这种方法会根据查询条件删除符合条件的文档。请谨慎使用查询条件,以确保只删除您想要清洗的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值