Apache spark 通过将函数应用于数据帧,将顶点添加到Tinkerpop图(gremlin)

Apache spark 通过将函数应用于数据帧,将顶点添加到Tinkerpop图(gremlin),apache-spark,dataframe,serialization,gremlin,tinkerpop3,Apache Spark,Dataframe,Serialization,Gremlin,Tinkerpop3,正如问题所表明的,我已经花了相当长的时间尝试编写一些代码,这些代码可以读取数据帧,并使用从数据帧提取的属性将顶点添加到gremlin图中。为此,我编写了以下代码: val graph = TinkerGraph.open() val g = graph.traversal def myFunction(field1:String,field2:String) ={ graph.addVertex(field1,field2) } val df = List( (1,"A"

正如问题所表明的,我已经花了相当长的时间尝试编写一些代码,这些代码可以读取数据帧,并使用从数据帧提取的属性将顶点添加到gremlin图中。为此,我编写了以下代码:

val graph = TinkerGraph.open()

val g = graph.traversal

def myFunction(field1:String,field2:String) ={

    graph.addVertex(field1,field2)
 }


val df = List(
  (1,"A","X",1),
  (2,"B","X",2),
  (3,"B","X",3),
  (4,"D","X",4),
  (5,"E","X",5),
  (6,"A","Y",1),
  (7,"C","Y",2)
).toDF("id","value","group","ts")


df.map(row => myFunction("id1", row.getAs[String]("value")))
问题是,我总是会遇到同样的错误:

org.apache.spark.SparkException: Task not serializable
    at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:304)
    at org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:294)
    at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:122)
    at org.apache.spark.SparkContext.clean(SparkContext.scala:2085)
    at org.apache.spark.rdd.RDD$$anonfun$map$1.apply(RDD.scala:324)
    at org.apache.spark.rdd.RDD$$anonfun$map$1.apply(RDD.scala:323)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:150)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:111)
    at org.apache.spark.rdd.RDD.withScope(RDD.scala:316)
    at org.apache.spark.rdd.RDD.map(RDD.scala:323)
    at org.apache.spark.sql.DataFrame.map(DataFrame.scala:1425)
    at $iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC.<init>(<console>:57

TL;DR像这样的代码在apachespark中没有一席之地

序列化问题是第二个问题。即使您解决了序列化问题,并使用类似于
foreach
的操作,Spark也没有共享状态来代替转换(
map

忽略
local
模式,每个执行器都使用自己的JVM(甚至物理主机)。没有共享内存,与驱动程序的唯一通信是与
运行作业的结果
或与
累加器
进行通信。这两种方法都可以在这里使用,但在这个问题中,有两种方法的好处(如果不是更糟的话)与从一开始就在本地计算所有东西一样


您的基本阅读:基于评论中的讨论。是Datastax Graph TinkerPop实现的工作示例。下面是基于的代码的草图。每个spark分区在一个远程执行器上处理。因此,您应该将内部foreachPartition调用连接到远程TP服务器并向其发送数据

df.foreachPartition(rows => {
     Cluster cluster = Cluster.open(); 
     Client client = cluster.connect();
      for (row <- rows) {
          val params = Map ("field1" -> "id1",
           "field2", row.getAs[String]("value"))
          client.submit("graph.addVertex(field1,field2)", params.asJava).all()
      }
      cluster.close()
})
df.foreachPartition(行=>{
Cluster=Cluster.open();
Client=cluster.connect();
对于(第“id1”行),
“field2”,row.getAs[String](“value”))
submit(“graph.addVertex(field1,field2)”,params.asJava.all()
}
cluster.close()
})

顺便说一句,在这种情况下,每个spark executor都可以远程连接到服务器,并通过gremlin驱动程序向服务器添加顶点。这是使用真正的TinkerPop基础数据库而不是玩具TinkerPop图的常见模式。这只是引用内存中的单个节点实现我试图以某种方式做同样的事情,我正在Spark中将文件加载到DataFrame中,我想使用Gremlin将其保存到我的图形中。我正在考虑使用scala Gremlin connector@ArtemAliev
,在这种情况下,每个Spark执行器将远程连接到服务器,并通过Gremlin驱动程序向其添加顶点->如何在每个工作进程内初始化连接@用户837195您对此有何看法?
df.foreachPartition(rows => {
     Cluster cluster = Cluster.open(); 
     Client client = cluster.connect();
      for (row <- rows) {
          val params = Map ("field1" -> "id1",
           "field2", row.getAs[String]("value"))
          client.submit("graph.addVertex(field1,field2)", params.asJava).all()
      }
      cluster.close()
})