我需要计算所有成对的文本行的Jaccard相似度。我只希望输出相似度高于80%的线对。 过去,我研究了Hadoop MapReduce框架,这就是我将如何使用map和reduce函数解决此问题的方法:
map(lineID, text):
for each word in text:
emit(word, (len(text), lineID))
reduce(word, list(v)):
if len(list(v)) < 2:
do nothing
else
for each pair ((len1, 1), (len2, 2)):
emit ((1, 2, len, len2), 1)
map(k, v):
emit (k, v)
reduce(k, v):
similarity = len(v)/(k[2]+k[3]-len(v))
if similarity > 0.80
emit((k[0], k[1]), similarity)
现在,我需要在PySpark中实现此伪代码,但是我有些卡住了。我要做的只是第一张地图,例如:
def mapping(line):
length = len(line.split())-1
jobID = line.split()[0]
return (length, jobID)
c = textFile.map(lambda line: [(c, (mapping(line))) for c in line.split()[1:]])
我不考虑第一个单词,因为该单词是lineID。我还有另一个疑问,如何获取输入文本行的索引? 任务如何分配给工人?我对Apache Spark的工作方式非常困惑。
您对我可以使用哪些方法以及在MapReduce中获得结果的顺序有何建议?
答案 0 :(得分:0)
除非您的数据非常大,否则最简单,最简单的方法也可能是最快的。让我们分而治之:
使用crossJoin
获取所有线对的数据框。
由于您不在乎自我比较,因此删除左手线与右手线相同的行。
使用简单的UDF jaccard(左,右)返回Jaccard相似度。
按相似度> 0.8过滤
我通过Scala使用Spark,因此我将为此提供Scala代码。 Python DSL应该非常相似。
val lines = spark.read.text(...)
lines.alias("lhs").crossJoin(lines.alias("rhs"))
.where($"lhs.value" =!= $"rhs.value")
.withColumn("similarity", jaccard($"lhs.value", $"rhs.value"))
.where($"similarity" > 0.8)