Java 如何解析AnalysisException:Spark中已解析的属性

Java 如何解析AnalysisException:Spark中已解析的属性,java,scala,spark-dataframe,Java,Scala,Spark Dataframe,联合行动运作良好 但是,当我重用df2时,我面临着未解决的属性错误 val rdd = sc.parallelize(Seq(("vskp", Array(2.0, 1.0, 2.1, 5.4)),("hyd",Array(1.5, 0.5, 0.9, 3.7)),("hyd", Array(1.5, 0.5, 0.9, 3.2)),("tvm", Array(8.0, 2.9, 9.1, 2.5)))) val df1= rdd.toDF("id", "vals") val rdd1 = sc

联合行动运作良好 但是,当我重用df2时,我面临着未解决的属性错误

val rdd = sc.parallelize(Seq(("vskp", Array(2.0, 1.0, 2.1, 5.4)),("hyd",Array(1.5, 0.5, 0.9, 3.7)),("hyd", Array(1.5, 0.5, 0.9, 3.2)),("tvm", Array(8.0, 2.9, 9.1, 2.5))))
val df1= rdd.toDF("id", "vals")
val rdd1 = sc.parallelize(Seq(("vskp","ap"),("hyd","tel"),("bglr","kkt")))
val df2 = rdd1.toDF("id", "state")
val df3 = df1.join(df2,df1("id")===df2("id"),"left")
错误:org.apache.spark.sql.AnalysisException:已解析的attributesid426


正如我在评论中所提到的,它与,更具体地说,有关。重复使用引用将在命名中产生歧义,因此您必须克隆df-请参见中的最后一条注释以获取示例。

对于java开发人员,请尝试调用此方法:

val rdd2 = sc.parallelize(Seq(("vskp", "Y"),("hyd", "N"),("hyd", "N"),("tvm", "Y")))
val df4 = rdd2.toDF("id","existance")
val df5 = df4.join(df2,df4("id")===df2("id"),"left")
在连接之前的两个数据集上,它将数据集克隆到新的数据集:

private static Dataset<Row> cloneDataset(Dataset<Row> ds) {
    List<Column> filterColumns = new ArrayList<>();
    List<String> filterColumnsNames = new ArrayList<>();
    scala.collection.Iterator<StructField> it = ds.exprEnc().schema().toIterator();
    while (it.hasNext()) {
        String columnName = it.next().name();
        filterColumns.add(ds.col(columnName));
        filterColumnsNames.add(columnName);
    }
    ds = ds.select(JavaConversions.asScalaBuffer(filterColumns).seq()).toDF(scala.collection.JavaConverters.asScalaIteratorConverter(filterColumnsNames.iterator()).asScala().toSeq());
    return ds;
}

我在尝试在两个连续联接中使用一个数据帧时遇到了相同的问题

问题是:数据帧A有两列,我们称它们为x和y,数据帧B也有两列,我们称它们为w和z。我需要在x=z上连接A和B,然后在y=z上连接它们

df1 = cloneDataset(df1); 
df2 = cloneDataset(df2);
Dataset<Row> join = df1.join(df2, col("column_name"));
// if it didn't work try this
final Dataset<Row> join = cloneDataset(df1.join(df2, columns_seq)); 
我得到的确切错误是,在第二次连接中,它抱怨已解决的属性B.z1234

根据@Erik提供的链接以及其他一些博客和问题,我想我需要一个B

以下是我所做的:

val aDF=。。。 val bDF=。。。 val bCloned=spark.createDataFramebDF.rdd,bDF.schema aDF.joinbDF,aDFx==bDFz.joinbCloned,aDFy==bClonedz
如果df1和df2是从df1派生的,请尝试重命名df2中的所有列,以便在联接后没有两列具有相同的名称。因此,在加入之前:

所以不是df1.joindf2


如果您执行以下操作,它将起作用

假设您有一个数据帧。如果您想要交叉连接相同的数据帧,您可以使用下面的

# Step 1 rename shared column names in df2.
df2_renamed = df2.withColumnRenamed('columna', 'column_a_renamed').withColumnRenamed('columnb', 'column_b_renamed')

# Step 2 do the join on the renamed df2 such that no two columns have same name.
df1.join(df2_renamed)

根据我的经验,我们有两种解决方案 1克隆测向 2在联接表之前重命名具有歧义的列。不要忘记删除重复的连接密钥


就我个人而言,我更喜欢第二种方法,因为在第一种方法中克隆DF需要时间,尤其是在数据量很大的情况下

在我的例子中,这个错误出现在同一个表的自连接过程中。 我在使用Spark SQL而不是dataframe API时遇到了以下问题:

df1.toDF("ColA","ColB").as("f_df").join(df1.toDF("ColA","ColB").as("t_df"), 
   $"f_df.pcmdty_id" === 
   $"t_df.assctd_pcmdty_id").select($"f_df.pcmdty_id",$"f_df.assctd_pcmdty_id")
早些时候我使用了下面的查询

org.apache.spark.sql.AnalysisException: Resolved attribute(s) originator#3084,program_duration#3086,originator_locale#3085 missing from program_duration#1525,guid#400,originator_locale#1524,EFFECTIVE_DATETIME_UTC#3157L,device_timezone#2366,content_rpd_id#734L,originator_sublocale#2355,program_air_datetime_utc#3155L,originator#1523,master_campaign#735,device_provider_id#2352 in operator !Deduplicate [guid#400, program_duration#3086, device_timezone#2366, originator_locale#3085, originator_sublocale#2355, master_campaign#735, EFFECTIVE_DATETIME_UTC#3157L, device_provider_id#2352, originator#3084, program_air_datetime_utc#3155L, content_rpd_id#734L]. Attribute(s) with the same name appear in the operation: originator,program_duration,originator_locale. Please check if the right attribute(s) are used.;;
在加入之前只选择必需的列解决了我的问题

    SELECT * FROM DataTable as aext
             INNER JOIN AnotherDataTable LAO 
ON aext.device_provider_id = LAO.device_provider_id 
[TLDR]

通过将中间数据帧写入文件系统并再次读取,断开父数据帧和派生数据帧中的列之间共享的AttributeReference

例:

现在加入顶级数据帧将导致无法解决的属性错误

val df1 = spark.read.parquet("file1")
df1.createOrReplaceTempView("df1")
val df2 = spark.read.parquet("file2")
df2.createOrReplaceTempView("df2")

val df12 = spark.sql("""SELECT * FROM df1 as d1 JOIN df2 as d2 ON d1.a = d2.b""")
df12.createOrReplaceTempView("df12")

val df12_ = spark.sql(""" -- some transformation -- """)
df12_.createOrReplaceTempView("df12_")

val df3 = spark.read.parquet("file3")
df3.createOrReplaceTempView("df3")

val df123 = spark.sql("""SELECT * FROM df12_ as d12_ JOIN df3 as d3 ON d12_.a = d3.c""")
df123.createOrReplaceTempView("df123")
解决方案:d123.a和d1.a共享同一个属性引用 将中间表df123写入文件系统并再次读取。现在,df123write.a和d1.a不共享属性引用

val df1231 = spark.sql("""SELECT * FROM df123 as d123 JOIN df1 as d1 ON d123.a = d1.a""") 
长话短说:

我们有复杂的ETL,具有数据帧的转换和自连接,在多个级别上执行。我们经常遇到未解决的属性错误,我们通过选择所需的属性并在顶级表上执行联接(而不是直接与顶级表联接)来解决它。这暂时解决了问题,但当我们在这些数据帧上应用更多转换并与任何顶级数据帧联接时,未解决的属性错误再次抬头

这是因为底层的数据帧与派生它们的顶层数据帧共享相同的AttributeReference

因此,我们打破了这种引用共享,只编写了1个中间转换数据帧,然后再次读取它,然后继续进行ETL。这打破了底部数据帧和顶部数据帧之间的共享属性引用,我们再也不会遇到未解决的属性错误


这对我们来说很有效,因为当我们从顶层数据帧移动到底层执行转换和连接时,我们的数据比我们开始的初始数据帧缩小了,它还提高了我们的性能,因为数据量更小,spark不必一直向后遍历DAG到最后一个持久化的数据帧。

只需重命名列并使用相同的名称即可。 在Pypark中: 对于df.columns中的i:
df=df。有了ColumnRenamedi,我

这个问题真的浪费了我很多时间,我终于找到了一个简单的解决方案

在PySpark中,对于有问题的专栏,比如可乐,我们可以简单地使用

导入pyspark.sql.F函数 df=df.selectF.colcolA.aliascolA 在联接中使用df之前

我认为这也适用于Scala/Java Spark。

多亏了

对于scala,当我试图使用self-join子句中的列时,出现了这个问题,要解决这个问题,请使用

val df123 = spark.sql("""SELECT * FROM df12 as d12 JOIN df3 as d3 ON d12.a = d3.c""")
df123.createOrReplaceTempView("df123")

df123.write.parquet("df123.par")
val df123write = spark.read.parquet("df123.par")
spark.catalog.dropTempView("df123")
df123write.createOrReplaceTempView("df123")

val df1231 = spark.sql("""SELECT * FROM df123 as d123 JOIN df1 as d1 ON d123.a = d1.a""") 

在我的例子中,检查原始数据帧修复了这个问题。

@Json\u chan的答案非常好,因为它不需要任何资源密集型操作。无论如何,当处理大量的列时,您需要一些通用函数来动态处理这些内容,而不是手动编写数百个列

幸运的是,您可以从数据帧本身派生该函数,这样您就不需要除了 至少在Pybark中有一个衬里:

导入pyspark.sql.f函数 df某些数据帧您已解决属性错误 df=df。为df.columns中的列名称选择[f.col column\u name.别名column\u name]
由于列的正确字符串表示形式仍然存储在Dataframedf.columns:列表的columns属性中,因此您可以自行重置它-这是通过别名完成的。注意:这仍然会导致新的Dataframe,因为Dataframes是不可变的,这意味着它们无法更改。

这很可能与,也就是说,id列的命名不明确,但在第一种情况下,它可以正常工作。我还提到了参考资料。我尝试将df4中的id重命名为id_new。我仍然无法解决这个错误。这是因为JAVARDD的血统问题吗?我试着设置检查站。但仍然是相同的错误也请参见:-完整错误消息已解析属性丢失…这可能是有史以来最糟糕/最黑客的修复,但数据帧别名,即df_alias=df.alias'df_alias和反转连接顺序,即更改df1_alias.joindf2_alias。到df2_alias.joindf1_ailas。修正了melast评论的问题,相对而言。。。我不确定它是否适用。请在这里引用正确的,这将是一个:这是一个对这个错误的根本原因的解释不再是最后的评论,在这里它是在你们正在寻找的情况下:为我工作。感谢很容易理解。谢谢!!:这个很好用!优雅地解释。这节省了我的时间:非常感谢:在第一种方法中克隆DF需要时间,特别是在数据量很大的情况下:放弃克隆选项以解决大表的问题请再解释一点并提供代码以帮助回答我在不同的页面中浏览了所有注释,但我找不到答案。因此,首先我尝试通过复制键和更改列名来连接表。因此,表a中的x列对应于表b中的y列,错误消失了。然后,我在聚合器函数之后重命名了两侧的列,并使用了与前面相同的名称。它像魔法一样工作。因此,如果在聚合器函数之后有a、b、c列,请将它们重命名为a、b、c Ps。我已经提供了代码。感谢您提供这个简单但非常有效的解决方案。这应该更高!非常简单,可以解决这些耗时的问题。谢天谢地,派生表只有两列,所以这个解决方法很容易编写,但非常棘手。这是2016年SPARK 1.6.0版的旧SPARK-14948错误吗?
val df1231 = spark.sql("""SELECT * FROM df123 as d123 JOIN df1 as d1 ON d123.a = d1.a""") 
val df123 = spark.sql("""SELECT * FROM df12 as d12 JOIN df3 as d3 ON d12.a = d3.c""")
df123.createOrReplaceTempView("df123")

df123.write.parquet("df123.par")
val df123write = spark.read.parquet("df123.par")
spark.catalog.dropTempView("df123")
df123write.createOrReplaceTempView("df123")

val df1231 = spark.sql("""SELECT * FROM df123 as d123 JOIN df1 as d1 ON d123.a = d1.a""") 
// To `and` all the column conditions
def andAll(cols: Iterable[Column]): Column =
   if (cols.isEmpty) lit(true)
   else cols.tail.foldLeft(cols.head) { case (soFar, curr) => soFar.and(curr) }

// To perform join different col name
def renameColAndJoin(leftDf: DataFrame, joinCols: Seq[String], joinType: String = "inner")(rightDf: DataFrame): DataFrame = {

   val renamedCols: Seq[String]          = joinCols.map(colName => s"${colName}_renamed")
   val zippedCols: Seq[(String, String)] = joinCols.zip(renamedCols)

   val renamedRightDf: DataFrame = zippedCols.foldLeft(rightDf) {
     case (df, (origColName, renamedColName)) => df.withColumnRenamed(origColName, renamedColName)
   }

   val joinExpr: Column = andAll(zippedCols.map {
     case (origCol, renamedCol) => renamedRightDf(renamedCol).equalTo(rightDf(origCol))
   })

   leftDf.join(renamedRightDf, joinExpr, joinType)

}