Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb MongoSpark仅在海量数据集上出现重复密钥错误_Mongodb_Apache Spark - Fatal编程技术网

Mongodb MongoSpark仅在海量数据集上出现重复密钥错误

Mongodb MongoSpark仅在海量数据集上出现重复密钥错误,mongodb,apache-spark,Mongodb,Apache Spark,使用MongoSpark,在两个大小不同的数据集上运行相同的代码,导致其中一个抛出E11000重复键错误 在我们继续之前,以下是代码: object ScrapeHubCompanyImporter { def importData(path: String, companyMongoUrl: String): Unit = { val spark = SparkSession.builder() .master("local[*]") .config("sp

使用MongoSpark,在两个大小不同的数据集上运行相同的代码,导致其中一个抛出
E11000重复键错误

在我们继续之前,以下是代码:

object ScrapeHubCompanyImporter {
  def importData(path: String, companyMongoUrl: String): Unit = {
    val spark = SparkSession.builder()
      .master("local[*]")
      .config("spark.mongodb.input.uri", companyMongoUrl)
      .config("spark.mongodb.output.uri", companyMongoUrl)
      .config("spark.mongodb.input.partitionerOptions.partitionKey", "profileUrl")
      .getOrCreate()
    import spark.implicits._

    val websiteToDomainTransformer = udf((website: String) => {
      val tldExtract = SplitHost.fromURL(website)
      if (tldExtract.domain == "") {
        null
      } else {
        tldExtract.domain + "." + tldExtract.tld
      }
    })

    val jsonDF =
      spark
        .read
        .json(path)
        .filter { row =>
          row.getAs[String]("canonical_url") != null
        }
        .dropDuplicates(Seq("canonical_url"))
        .select(
          toHttpsUdf($"canonical_url").as("profileUrl"),
          $"city",
          $"country",
          $"founded",
          $"hq".as("headquartes"),
          $"industry",
          $"company_id".as("companyId"),
          $"name",
          $"postal",
          $"size",
          $"specialties",
          $"state",
          $"street_1",
          $"street_2",
          $"type",
          $"website"
        )
        .filter { row => row.getAs[String]("website") != null }
        .withColumn("domain", websiteToDomainTransformer($"website"))
        .filter(row => row.getAs[String]("domain") != null)
        .as[ScrapeHubCompanyDataRep]

    val jsonColsSet = jsonDF.columns.toSet

    val mongoData = MongoSpark
      .load[LinkedinCompanyRep](spark)
      .withColumn("companyUrl", toHttpsUdf($"companyUrl"))
      .as[CompanyRep]

    val mongoColsSet = mongoData.columns.toSet

    val union = jsonDF.joinWith(
      mongoData,
      jsonDF("companyUrl") === mongoData("companyUrl"),
      joinType = "left")
      .map { t =>
        val scrapeHub = t._1
        val liCompanyRep = if (t._2 != null ) {
          t._2
        } else {
          CompanyRep(domain = scrapeHub.domain)
        }

        CompanyRep(
          _id = pickValue(liCompanyRep._id, None),
          city = pickValue(scrapeHub.city, liCompanyRep.city),
          country = pickValue(scrapeHub.country, liCompanyRep.country),
          postal = pickValue(scrapeHub.postal, liCompanyRep.postal),
          domain = scrapeHub.domain,
          founded = pickValue(scrapeHub.founded, liCompanyRep.founded),
          headquartes = pickValue(scrapeHub.headquartes, liCompanyRep.headquartes),
          headquarters = liCompanyRep.headquarters,
          industry = pickValue(scrapeHub.industry, liCompanyRep.industry),
          linkedinId = pickValue(scrapeHub.companyId, liCompanyRep.companyId),
          companyUrl = Option(scrapeHub.companyUrl),
          name = pickValue(scrapeHub.name, liCompanyRep.name),
          size = pickValue(scrapeHub.size, liCompanyRep.size),
          specialties = pickValue(scrapeHub.specialties, liCompanyRep.specialties),
          street_1 = pickValue(scrapeHub.street_1, liCompanyRep.street_1),
          street_2 = pickValue(scrapeHub.street_2, liCompanyRep.street_2),
          state = pickValue(scrapeHub.state, liCompanyRep.state),
          `type` = pickValue(scrapeHub.`type`, liCompanyRep.`type`),
          website = pickValue(scrapeHub.website, liCompanyRep.website),
          updatedDate = None,
          scraped = Some(true)
        )
      }

    val idToMongoId = udf { st: String =>
      if (st != null) {
        ObjectId(st)
      } else {
        null
      }
    }

    val saveReady =
      union
      .map { rep =>
          rep.copy(
            updatedDate = Some(new Timestamp(System.currentTimeMillis)),
            scraped = Some(true),
            headquarters = generateCompanyHeadquarters(rep)
          )
      }
      .dropDuplicates(Seq("companyUrl"))

    MongoSpark.save(
      saveReady.withColumn("_id", idToMongoId($"_id")),
      WriteConfig(Map(
        "uri" -> companyMongoUrl
      )))
  }

  def generateCompanyHeadquarters(companyRep: CompanyRep): Option[CompanyHeadquarters] = {
    val hq = CompanyHeadquarters(
      country = companyRep.country,
      geographicArea = companyRep.state,
      city = companyRep.city,
      postalCode = companyRep.postal,
      line1 = companyRep.street_1,
      line2 = companyRep.street_2
    )

    CompanyHeadquarters
      .unapply(hq)
      .get
      .productIterator.toSeq.exists {
        case a: Option[_] => a.isDefined
        case _ => false
      } match {
        case true => Some(hq)
        case false => None
      }
  }

  def pickValue(left: Option[String], right: Option[String]): Option[String] = {
    def _noneIfNull(opt: Option[String]): Option[String] = {
      if (opt != null) {
        opt
      } else {
        None
      }
    }

    val lOpt = _noneIfNull(left)
    val rOpt = _noneIfNull(right)

    lOpt match {
      case Some(l) => Option(l)
      case None => rOpt match {
        case Some(r) => Option(r)
        case None => None
      }
    }
  }
}
此问题与
companyUrl
有关,它是集合中唯一的键之一,另一个是
\u id
键。问题是Spark会尝试在700gb数据集上保存大量的重复数据,但是如果我在本地运行一个非常小的数据集,我永远无法复制这个问题。我试图了解发生了什么,如何确保将
companyUrl
上的所有现有公司分组,并确保数据集中的重复项确实被全局删除

编辑 以下是出现的一些情况:

  • 公司位于Mongo,读取的文件已更新数据->此处可能出现重复密钥错误
  • 公司不在Mongo,但在文件->重复键错误也可能发生在这里 EDIT2 重复错误发生在
    companyUrl
    字段附近

    编辑3
    在合并阶段,我把这个问题缩小了。查看已标记为具有重复的
    公司URL
    的记录,其中一些记录不在目标集合中,但不知何故,仍在将重复记录写入集合中。在其他情况下,新记录的
    \u id
    字段与具有相同
    公司URL

    Spark版本的旧记录不匹配?什么版本的火花连接器?@Ross Spark_2.11 2.0.0和Mongo-Spark-Connector_2.11 2.0.0什么类型的
    saveReady
    idToMongoId
    可以生成空值-为什么不创建一个
    ObjectId
    ?Null可以是有效的Bson值,因此请确保这不是重复的原因。最后,您已经通过“companyUrl”删除了重复项。为什么不也删除
    \u id
    呢?@Ross我添加了一个编辑,重复键位于我试图重复的
    companyUrl
    周围,我想知道这是否是因为Mongo使用
    forEachPartition
    进行保存的缘故,它可以再次重复重复
    SaveReady
    是一个
    DS[CompanyRep]
    @Ross我添加了一个更深入的编辑,关于我认为正在发生的事情。什么版本的Spark?什么版本的火花连接器?@Ross Spark_2.11 2.0.0和Mongo-Spark-Connector_2.11 2.0.0什么类型的
    saveReady
    idToMongoId
    可以生成空值-为什么不创建一个
    ObjectId
    ?Null可以是有效的Bson值,因此请确保这不是重复的原因。最后,您已经通过“companyUrl”删除了重复项。为什么不也删除
    \u id
    呢?@Ross我添加了一个编辑,重复键位于我试图重复的
    companyUrl
    周围,我想知道这是否是因为Mongo使用
    forEachPartition
    进行保存的缘故,它可以再次重复重复
    SaveReady
    是一个
    DS[CompanyRep]
    @Ross我添加了一个更深入的编辑,关于我认为正在发生的事情。