来自Apache Spark Streaming中

时间:2017-04-11 02:06:41

标签: java apache-spark neo4j streaming spark-streaming

摘要

我的问题是Apache Spark Streaming如何通过改进并行化或将许多写入组合成单个更大的写入来处理需要很长时间的输出操作。在这种情况下,写入是对Neo4J的密码请求,但它可以应用于其他数据存储。

<小时/>

环境

我在Java中有一个Apache Spark Streaming应用程序,它写入2个数据存储区:Elasticsearch和Neo4j。以下是版本:

  • Java 8
  • Apache Spark 2.11
  • Neo4J 3.1.1
  • Neo4J Java Bolt Driver 1.1.2

当我使用Elasticsearch-Hadoop for Apache Spark库时,Elasticsearch输出很简单。

<小时/>

我们的流

我们的输入是来自Kafka的特定主题的流,我通过map函数反序列化流的元素以创建JavaDStream<[OurMessage]> dataStream。然后我对此消息进行转换以创建一个密码查询String cypherRequest(使用OurMessage to String转换),该查询被发送到管理与Neo4j的Bolt Driver连接的单例(我知道我应该使用连接池,但是也许这是另一个问题)。密码查询根据OurMessage的内容生成许多节点和/或边。

代码如下所示。

dataStream.foreachRDD( rdd -> {
    rdd.foreach( cypherQuery -> {
        BoltDriverSingleton.getInstance().update(cypherQuery);
    });
});

<小时/>

优化的可能性

我对如何提高吞吐量有两点想法:

  1. 我不确定Spark Streaming并行化是否归结为RDD元素级别。意思是,RDD的输出可以并行化(在`stream.foreachRDD()`中,但是RDD的每个元素都可以并行化(在`rdd.foreach()`中。)如果是后者,那么会减少` ``dataStream`的转换增加了Spark并行输出这些数据的能力(每个JavaRDD只包含一个密码查询)?
  2. 即使改进了并行化,如果我可以实现某种类型的构建器,使RDD的每个元素创建一个单个密码查询来添加所有元素的节点/边缘,而不是每个RDD的一个密码查询。但是,如果不使用另一个可能过度的kafka实例,我怎么能够做到这一点呢?

我在想这个吗?我试图研究这么多,以至于我可能太深了。

<小时/> 旁白:如果其中任何一个完全错误,我会提前道歉。你不知道自己不知道什么,而且我刚刚开始使用Apache Spark和Java 8 w / lambdas。正如Spark用户现在必须知道的那样,要么Spark有一个陡峭的学习曲线,因为它的范例非常不同,或者我是一个白痴:)。

感谢任何可能提供帮助的人;这是我在很长一段时间内的第一个StackOverflow问题,所以请留下反馈,我会根据需要做出回应并纠正这个问题。

1 个答案:

答案 0 :(得分:0)

我认为我们所需要的只是一个简单的Map / Reduce。以下内容应该允许我们解析RDD中的每条消息,然后一次性将其写入Graph DB。

dataStream.map( message -> {
    return (ParseResult) Neo4JMessageParser.parse(message);
}).foreachRDD( rdd -> {
    List<ParseResult> parseResults = rdd.collect();
    String cypherQuery = Neo4JMessageParser.buildQuery(parseResults);
    Neo4JRepository.update(cypherQuery);
    // commit offsets
});

通过这样做,我们应该能够减少与每个传入消息进行写入相关的开销。