从Spark错误Upsert到CosmosDB

时间:2018-04-05 09:50:21

标签: scala apache-spark pyspark spark-dataframe azure-cosmosdb

我是Spark / CosmosDB / Python的新手,所以我在尝试自己创建一些东西时,会从MS站点和GitHub中获取代码示例。经过与Spark-CosmosDB连接器的长期斗争,我能够从CosmosDB集合中读取数据。现在我想反过来(upsert),但发现了另一个障碍。这是一个例子,我正在努力: Writing to Cosmos DB section

我可以从Cosmos中读取数据,但是我无法插入Cosmos。以下是我稍加修改的代码:

%%configure
{ "name":"Spark-to-Cosmos_DB_Connector", 
  "jars": ["wasb:///example/jars/1.0.0/azure-cosmosdb-spark_2.2.0_2.11-1.1.0.jar", "wasb:///example/jars/1.0.0/azure-documentdb-1.14.0.jar", "wasb:///example/jars/1.0.0/azure-documentdb-rx-0.9.0-rc2.jar", "wasb:///example/jars/1.0.0/json-20140107.jar", "wasb:///example/jars/1.0.0/rxjava-1.3.0.jar", "wasb:///example/jars/1.0.0/rxnetty-0.4.20.jar"],
  "conf": {
    "spark.jars.excludes": "org.scala-lang:scala-reflect"
   }
}

# Read Configuration
readConfig = {
  "Endpoint" : "https://doctorwho.documents.azure.com:443/",
  "Masterkey" : "SPSVkSfA7f6vMgMvnYdzc1MaWb65v4VQNcI2Tp1WfSP2vtgmAwGXEPcxoYra5QBHHyjDGYuHKSkguHIz1vvmWQ==",
  "Database" : "DepartureDelays",
  "preferredRegions" : "Central US;East US2",
  "Collection" : "flights_pcoll", 
  "SamplingRatio" : "1.0",
  "schema_samplesize" : "1000",
  "query_pagesize" : "2147483647",
  "query_custom" : "SELECT c.date, c.delay, c.distance, c.origin, c.destination FROM c WHERE c.origin = 'SEA'"
}

# Connect via azure-cosmosdb-spark to create Spark DataFrame
flights = spark.read.format("com.microsoft.azure.cosmosdb.spark").options(**readConfig).load()
flights.count()

# Write configuration
writeConfig = {
 "Endpoint" : "https://doctorwho.documents.azure.com:443/",
 "Masterkey" : "SPSVkSfA7f6vMgMvnYdzc1MaWb65v4VQNcI2Tp1WfSP2vtgmAwGXEPcxoYra5QBHHyjDGYuHKSkguHIz1vvmWQ==",
 "Database" : "DepartureDelays",
 "Collection" : "flights_pcoll",
 "Upsert" : "true"
}

# Write to Cosmos DB from the flights DataFrame
flights.write.format("com.microsoft.azure.cosmosdb.spark").options(**writeConfig).save()

所以,当我尝试运行时,我得到:

An error occurred while calling o90.save.
: java.lang.UnsupportedOperationException: Writing in a non-empty collection.

快速谷歌搜索后,我尝试添加模式("追加")到我的最后一行:

flights.write.format("com.microsoft.azure.cosmosdb.spark").mode("append").options(**writeConfig).save()

不幸的是,这给我留下了一个我无法理解的错误:

An error occurred while calling o127.save.
: org.apache.spark.SparkException: Job aborted due to stage failure: Task 2 in stage 4.0 failed 4 times, most recent failure: Lost task 2.3 in stage 4.0 (TID 90, wn2-MDMstr.zxmmgisclg5udfemnv0v3qva3e.ax.internal.cloudapp.net, executor 2): java.lang.NoClassDefFoundError: com/microsoft/azure/documentdb/bulkexecutor/DocumentBulkExecutor

这是完整的堆栈跟踪:error in pastebin

有人可以帮我解决这个错误吗?在使用我自己的cosmosDB时,我也收到了完全相同的错误,而不是文档中的示例。

我正在使用带有PySpark3内核的Jupyter笔记本。 Spark版本2.2,HDInsight群集3.6。

修改 我不想等待回复,所以我尝试用Scala做同样的事情。你猜怎么着?相同的错误(或至少非常相似):Scala error

这是我的Scala代码:

%%configure
{ "name":"Spark-to-Cosmos_DB_Connector", 
  "jars": ["wasb:///example/jars/1.0.0/azure-cosmosdb-spark_2.2.0_2.11-1.1.0.jar", "wasb:///example/jars/1.0.0/azure-documentdb-1.14.0.jar", "wasb:///example/jars/1.0.0/azure-documentdb-rx-0.9.0-rc2.jar", "wasb:///example/jars/1.0.0/json-20140107.jar", "wasb:///example/jars/1.0.0/rxjava-1.3.0.jar", "wasb:///example/jars/1.0.0/rxnetty-0.4.20.jar"],
  "conf": {
    "spark.jars.excludes": "org.scala-lang:scala-reflect"
   }
}

import org.apache.spark.sql.types._
import org.apache.spark.sql.Row
import org.apache.spark.sql.SaveMode
import com.microsoft.azure.cosmosdb.spark.schema._
import com.microsoft.azure.cosmosdb.spark._
import com.microsoft.azure.cosmosdb.spark.config.Config

val readConfig = Config(Map(
  "Endpoint" -> "https://$my_cosmos_db.documents.azure.com:443/",
  "Masterkey" -> "$my_key",
  "Database" -> "test",
  "PreferredRegions" -> "West Europe",
  "Collection" -> "$my_collection", 
  "SamplingRatio" -> "1.0"
))
val docs = spark.read.cosmosDB(readConfig)

docs.show()

val writeConfig = Config(Map(
  "Endpoint" -> "https://$my_cosmos_db.documents.azure.com:443/",
  "Masterkey" -> "$my_key",
  "Database" -> "test",
  "PreferredRegions" -> "West Europe",
  "Collection" -> "$my_collection", 
  "WritingBatchSize" -> "100"
))




val someData = Seq(
    Row(8, "bat"),
    Row(64, "mouse"),
    Row(-27, "test_name")
)

val someSchema = List(
  StructField("number", IntegerType, true),
  StructField("name", StringType, true)
)

val someDF = spark.createDataFrame(
  spark.sparkContext.parallelize(someData),
  StructType(someSchema)
)

someDF.show()

someDF.write.mode(SaveMode.Append).cosmosDB(writeConfig)

也许这会对故障排除有所帮助。

谢谢!

3 个答案:

答案 0 :(得分:2)

对于使用python时的第一个问题,请注意您使用的是doctorwho Azure Cosmos数据库集合。这是一个演示集合,我们提供了只读密钥而不是写密钥。因此,您收到的错误是缺少对集合的写访问权。

对于第二个问题,来自pastebin的错误看起来是一样的。这样说,一些快速观察:

  • 您使用的是HDI 3.6,如果您使用的是Spark 2.1,则使用的JAR适用于Spark 2.2。如果您正在使用HDI 3.7,那么它在Spark 2.2上,然后您就可以使用正确的jar。
  • 您可能希望使用maven坐标来获取最新版本的JAR。请注意azure-cosmosdb-spark> Using Jupyter Notebooks了解更多信息。

答案 1 :(得分:2)

由于我找不到问题的正确答案解决方案,我想分享我的工作配置。我的配置适用于带有Spark 2.1的HDI 3.6。使用Jupyther Notebook的PySpark脚本成功读取和写入Cosmos Document DB中的数据。

%%configure
{
 "name":"Spark-to-Cosmos_DB_Connector", 
 "jars": ["wasb:///cosmos-libs/azure-cosmosdb-spark_2.1.0_2.11-1.0.0-uber.jar"],
 "conf": {"spark.jars.excludes": "org.scala-lang:scala-reflect,org.apache.spark:spark-tags_2.11"}
}

读取和写入配置,读取和保存命令完全相同,如问题中所述。 Write config具有描述为here的附加参数WritingBatchSize。我从这个location下载了Uber jar。

答案 2 :(得分:1)

在与微软工程师沟通并且我自己进行的测试很少之后,我发现有一些关于Spark-CosmosDB连接器的问题。基本上,所使用的连接器的最佳版本是 1.0.0 ,日期为2017年11月15日(两者均为 Spark 2.1和2.2 )。 Link to the repository以下是一些对我有用的解决方案/解决方法。您可以尝试使用它们来为您找到最佳解决方案。

1)如果使用Spark 2.1或2.2,请在版本1.0.0中使用连接器(上面的链接)。当我写这个答案时(18-May-2018),最新版本的连接器是日期为23-Mar-2018的1.1.1 - 当需要将数据帧写入Cosmos DB或尝试时从Cosmos读取超过50k的文档数据框(对于无SQL数据库,50k文档是什么?)。

2)如果您使用Spark 2.1 - > Jupter将使用1.0.0连接器。如果您使用Spark 2.2 - >不要使用Jupyter笔记本 - 它在使用外部软件包时遇到一些问题,特别是在Spark 2.2安装中。  请改用Zeppelin笔记本( 1.0.0连接器)。打开Zeppelin后,在右上角单击“用户”,然后单击“解释器”。转到Livy解释器设置单击编辑并添加包坐标:com.microsoft.azure:azure-cosmosdb-spark_2.2.0_2.11:1.0.0

enter image description here enter image description here

保存并重新启动解释器。然后使用livy2解释器创建一个新的笔记本。请注意,在Zeppelin的每个单元格中,您必须在第一行添加%pyspark魔术命令。由于启动整个应用程序,第一个单元格的运行将持续1-2分钟。

3)您可以直接使用群集,而不是使用笔记本。使用putty通过SSH创建群集,使用创建群集时提供的sshuser和密码:

enter image description here

然后启动pyspark附加uber-jar文件(你必须从存储库下载uber-jar文件,然后将其上传到连接到集群的blob存储。在我的情况下,文件位于名为example的文件夹中(来自root的第一级)容器)。这里我也使用1.0.0连接器。 这是命令:

pyspark --master yarn --jars wasb:///example/azure-cosmosdb-spark_2.2.0_2.11-1.0.0-uber.jar

当火花准备就绪时,您可以粘贴并运行命令,一切都应该正常工作。

如果您有任何疑问或有任何不明确的地方,请告知我们。