使用RDD和DataFrames的结果不同

时间:2018-01-26 01:54:27

标签: regex apache-spark pyspark apache-spark-sql

我使用Spark RDD和DataFrame创建了文本文件的字数,但答案略有不同。我正在使用的数据可用here。 为什么答案不同?

from pyspark.sql.functions import col, trim, lower, regexp_replace, explode, split, length
 from pyspark.sql import Row

 from nltk.corpus import stopwords
 stopwords = stopwords.words('english')

数据帧

def clean1(line):
   return trim(lower(regexp_replace(line, '[^a-zA-Z0-9\s]','')))

 df1 = (spark.read.text("Quran.txt")
   .select(clean1('value').alias('line'))
   .select(explode(split('line', ' ')).alias('word'))
   .filter(length(col("word")) > 0)
   .filter(~col('word').isin(stopwords))
   .groupBy('word').count()
   .orderBy('count', ascending = False)
  )

  df1.show(10)

enter image description here

RDD

 import re

 def cleanline(line):
    return re.sub('[^a-zA-Z0-9\s]', '', line).lower().strip()

df2 = (sc.textFile('Quran.txt')
   .map(lambda x: cleanline(x))
   .flatMap(lambda x: x.split(' '))
   .filter(lambda x: len(x) > 0)
   .filter(lambda x: x not in stopwords)
   .map(lambda x: (x, 1))
   .reduceByKey(lambda a, b: a + b)
   .sortBy(lambda x: -x[1])
   .map(lambda x: Row(word = x[0], count = x[1]))
   .toDF()
   .select(['word','count'])
  )

  df2.show(10)

enter image description here

更新

我发现如果我在' [^ a-zA-Z0-9 \ s]'更改DataFrame部分中的正则表达式到' [^ a-zA-Z0-9]',答案变得相同。这两个正则表达式是不一样的吗?

1 个答案:

答案 0 :(得分:4)

如果你看一下trim

的功能定义
'ltrim': 'Trim the spaces from left end for the specified string value.',
'rtrim': 'Trim the spaces from right end for the specified string value.',
'trim': 'Trim the spaces from both ends for the specified string column.',

表示修剪仅删除空格而不删除标签(\ t) 。但是在下面的某些行中有标签trim函数不会将其删除。

God could destroy him if He chose, v. 19 (488)

这就是上面一行中god的原因不计算在前面有标签。虽然strip()函数删除了所有空格,包括前面的标签。

类似的情况也适用于其他计数。

因此,定义udf函数可以使用strip() python函数是您的解决方案。

from pyspark.sql import functions as F
from pyspark.sql import types as T

def stripUdf(x):
    return x.strip()

callStripUdf = F.udf(stripUdf, T.StringType())

def clean1(line):
    return callStripUdf(F.trim(F.lower(F.regexp_replace(line, '[^a-zA-Z0-9\s]',''))))

正如您所提到的,从[^a-zA-Z0-9\s]更改为[^a-zA-Z0-9 ]解决了这个问题,因为 \ s 意味着所有空白包括 tab(\ t),因此在应用trim之前,更改将标签替换为字符。

我希望答案很有帮助