在 PySpark 中使用 regexp_extract 提取多个单词

Posted

技术标签:

【中文标题】在 PySpark 中使用 regexp_extract 提取多个单词【英文标题】:Extract multiple words using regexp_extract in PySpark 【发布时间】:2019-05-28 12:00:25 【问题描述】:

我有一个包含一些单词的列表,我需要从文本行中提取匹配的单词,我找到了this,但它只提取了一个单词。

密钥文件内容

这是一个关键字

part_description 文件内容

32015 这是一个关键字 hello world

代码

import pyspark.sql.functions as F

keywords = sc.textFile('file:///home/description_search/keys') #1
part_description =  sc.textFile('file:///description_search/part_description') #2
keywords = keywords.map(lambda x: x.split(' ')) #3
keywords = keywords.collect()[0] #4
df = part_description.map(lambda r: Row(r)).toDF(['line']) #5
df.withColumn('extracted_word', F.regexp_extract(df['line'],'|'.join(keywords), 0)).show() #6

输出

+--------------------+--------------+
|                line|extracted_word|
+--------------------+--------------+
|32015   this is a...|          this|
+--------------------+--------------+

预期输出

+--------------------+-----------------+
|                line|   extracted_word|
+--------------------+-----------------+
|32015   this is a...|this,is,a,keyword|
+--------------------+-----------------+

我想要

    返回所有匹配的关键字及其计数

    如果step #4 是最有效的方式

可重现的例子:

keywords = ['this','is','a','keyword']
l = [('32015 this is a keyword hello world'      , ),
('keyword this'      ,   ),
('32015 this is a keyword hello world 32015 this is a keyword hello world'      ,   ),
('keyword keyword'      ,   ),
('is a'      , )]

columns = ['line']

df=spark.createDataFrame(l, columns)

【问题讨论】:

你能解释一下 1. 多一点吗?最终的数据框应该是什么样子?你有多少个关键词? @cronoik,我更新了问题 当一行包含'keyword keyword'时你想发生什么? 顺便说一句。 regexp_extract_all 尚未发布,因此需要解决方法。 【参考方案1】:

Spark 3.1+regexp_extract_all 可用:

regexp_extract_all(str, regexp[, idx]) - 提取str 中与regexp 表达式匹配并对应于正则表达式组索引的所有字符串。

你原来的问题现在可以这样解决:

re_pattern = '(' + '|'.join([f'\\\\bk\\\\b' for k in keywords]) + ')'
df = df.withColumn('matched', F.expr(f"regexp_extract_all(line, 're_pattern', 1)"))
df = df.withColumn('count', F.size('matched'))

df.show()
#+--------------------+--------------------+-----+
#|                line|             matched|count|
#+--------------------+--------------------+-----+
#|32015 this is a k...|[this, is, a, key...|    4|
#|        keyword this|     [keyword, this]|    2|
#|32015 this is a k...|[this, is, a, key...|    8|
#|     keyword keyword|  [keyword, keyword]|    2|
#|                is a|             [is, a]|    2|
#+--------------------+--------------------+-----+

【讨论】:

只是不知道需要多少转义。我试图通过 "#[^ ,\n]+" 提取哈希标签,但失败并回退到 UDF【参考方案2】:

我设法通过使用 UDF 来解决它,如下所示

def build_regex(keywords):
    res = '('
    for key in keywords:
        res += '\\b' + key + '\\b|'
    res = res[0:len(res) - 1] + ')'

    return res


def get_matching_string(line, regex):
    matches = re.findall(regex, line)
    return matches if matches else None


udf_func = udf(lambda line, regex: get_matching_string(line, regex),
               ArrayType(StringType()))

df = df.withColumn('matched', udf_func(df['line'], F.lit(build_regex(keywords)))).withColumn('count', F.size('matched'))

结果

+--------------------+--------------------+-----+
|                line|             matched|count|
+--------------------+--------------------+-----+
|32015    this is ...|[this, is, this, ...|    5|
|12832    Shb is a...|             [is, a]|    2|
|35015    this is ...|          [this, is]|    2|
+--------------------+--------------------+-----+

【讨论】:

【参考方案3】:

带有临时视图的 pyspark REGEXP_EXTRACT_ALL

创建一个临时视图:

df.select("user_id","line").createOrReplaceTempView("temp")

从临时视图中选择,创建一个新的临时视图或数据集:

spark.sql("SELECT user_id,REGEXP_EXTRACT_ALL(line,'(#[a-zA-Z]+)',1) as MATCHED FROM temp").createOrReplaceTempView("temp2")

对于这个例子,我使用 REGEXP_EXTRACT_ALL 来提取主题标签

【讨论】:

以上是关于在 PySpark 中使用 regexp_extract 提取多个单词的主要内容,如果未能解决你的问题,请参考以下文章

Apache Spark:如何在Python 3中使用pyspark

PySpark:如何在列中使用 Or 进行分组

如何在 Pyspark 中使用 Scala 函数?

如何在 Databricks 的 PySpark 中使用在 Scala 中创建的 DataFrame

在 PySpark 中使用列条件替换空值

Pyspark 使用自定义函数