我使用pyspark和Kafka Receiver来处理推文流。我的应用程序的其中一个步骤包括调用Google Natural Language API以获得每条推文的情绪评分。但是,我发现API每个已处理的推文都会收到几个电话(我在Google云端控制台中看到号码呼叫)。
另外,如果我打印tweetIDs(在映射函数内),我得到相同的ID 3或4次。在我的应用程序结束时,推文被发送到Kafka的另一个主题,在那里我得到正确的推文数(没有重复的ID' s),所以原则上一切都正常,但我不是知道如何避免每条推文多次调用Google API。
这是否与Spark或Kafka中的某些配置参数有关?
以下是我的控制台输出示例:
TIME 21:53:36: Google Response for tweet 801181843500466177 DONE!
TIME 21:53:36: Google Response for tweet 801181854766399489 DONE!
TIME 21:53:36: Google Response for tweet 801181844808966144 DONE!
TIME 21:53:37: Google Response for tweet 801181854372012032 DONE!
TIME 21:53:37: Google Response for tweet 801181843500466177 DONE!
TIME 21:53:37: Google Response for tweet 801181854766399489 DONE!
TIME 21:53:37: Google Response for tweet 801181844808966144 DONE!
TIME 21:53:37: Google Response for tweet 801181854372012032 DONE!
但是在Kafka接收器中我只收到4条已处理的推文(这是正确的,因为它们只有4条独特的推文)。
执行此操作的代码是:
def sendToKafka(rdd,topic,address):
publish_producer = KafkaProducer(bootstrap_servers=address,\
value_serializer=lambda v: json.dumps(v).encode('utf-8'))
records = rdd.collect()
msg_dict = defaultdict(list)
for rec in records:
msg_dict["results"].append(rec)
publish_producer.send(resultTopic,msg_dict)
publish_producer.close()
kafka_stream = KafkaUtils.createStream(ssc, zookeeperAddress, "spark-consumer-"+myTopic, {myTopic: 1})
dstream_tweets=kafka_stream.map(lambda kafka_rec: get_json(kafka_rec[1]))\
.map(lambda post: add_normalized_text(post))\
.map(lambda post: tagKeywords(post,tokenizer,desired_keywords))\
.filter(lambda post: post["keywords"] == True)\
.map(lambda post: googleNLP.complementTweetFeatures(post,job_id))
dstream_tweets.foreachRDD(lambda rdd: sendToKafka(rdd,resultTopic,PRODUCER_ADDRESS))
答案 0 :(得分:1)
我已经找到了解决方法!我只需要用以下内容缓存DStream:
dstream_tweets.cache()
发生多个网络调用是因为Spark在我的脚本中执行后面的操作之前重新计算了DStream中的RDD。当我缓存()DStream时,只需要计算一次;并且由于它保存在内存中,以后的函数可以访问该信息而无需重新计算(在这种情况下,重新计算涉及再次调用API,因此值得支付更多内存使用的代价)。