过滤字符串是否包含子字符串pyspark

时间:2019-11-29 11:46:53

标签: pyspark apache-spark-sql

我有2个数据集。在每一行中,我都有几列。但我想使用only 2 columns from each dataset, without doing any join, merge or combination between the both of the datasets.

示例数据集1:

column_dataset_1 <String>    |      column_dataset_1_normalized <String>
-----------------------------------------------------------------------
11882621-V021BRP161305-1     |      11882621V021BRP1613051
-----------------------------------------------------------------------
W-B.7120RP1605794            |      WB7120RP1605794
-----------------------------------------------------------------------
D/57RP.1534421               |      D57RP1534421
-----------------------------------------------------------------------
125858G_022BR/P070751        |      125858G022BRP070751
-----------------------------------------------------------------------
300B.5190C57/51507           |      300B5190C5751507
-----------------------------------------------------------------------

示例数据集2

column_dataset_2 <String>                                                           |       column_dataset_2_normalized <String>
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Por ejemplo, si W-B.7120RP1605794se trata de un archivo de texto,                   |  PorejemplosiWB7120RP1605794setratadeunarchivodetexto 
-------------------------------------------------------------------------------------------------------------------------------------------------------------     
se abrirá en un programa de procesamiento de texto.                                 |  seabrirenunprogramadeprocesamientodetexto
-------------------------------------------------------------------------------------------------------------------------------------------------------------
                                                                                    |
-------------------------------------------------------------------------------------------------------------------------------------------------------------
utilizados 125858G_022BR/P070751 frecuentemente (por ejemplo, un texto que describe |  utilizados125858G022BRP070751frecuentementeporejemplountextoquedescribe

--------------------------------------------------------------------------------------------------------------------------------------------------------------

column_dataset_1_normalized是标准化column_dataset_1的结果 column_dataset_2_normalized是column_dataset_2的结果已规范化

我想比较column_dataset_1_normalized中是否存在column_dataset_2_normalized。 如果是,我应该extract it from column_dataset_2

示例:

WB7120RP1605794位于second line的{​​{1}}中,并且存在于column_dataset_1_normalized中,所以我应该first line of column_dataset_2_normalizedextract,来自{ {1}}并将其存储在数据集2的新列中。

对于real value [W-B.7120RP1605794],同样是column_dataset_2,我应该125858G022BRP070751。 比较应该取in forth line in column_dataset_2_normalized的一个值,然后在extract it from column_dataset_2 [125858G_022BR/P070751]中进行搜索。

为了进行标准化,我使用以下代码仅保留数字和字母:

column_dataset_1_normalized

有人可以向我提出建议,我该怎么做? 谢谢

1 个答案:

答案 0 :(得分:1)

有多种方法可以连接两个数据框:

(1)使用SQL函数locateinstr,{{3}在 column_dataset_2_normalized 中找到字符串 column_dataset_1_normalized 的位置/位置}等,返回排名(从1开始)

    from pyspark.sql.functions import expr

    cond1 = expr('locate(column_dataset_1_normalized,column_dataset_2_normalized)>0')
    cond2 = expr('instr(column_dataset_2_normalized,column_dataset_1_normalized)>0')
    cond3 = expr('position(column_dataset_1_normalized IN column_dataset_2_normalized)>0')

(2)使用正则表达式position column_dataset_2_normalized 中查找 column_dataset_1_normalized ,这仅在 column_dataset_1_normalized中未显示正则表达式元字符的情况下有效

    cond4 = expr('column_dataset_2_normalized rlike column_dataset_1_normalized')

运行以下代码,并使用上述条件之一,例如:

df1.join(df2, cond1).select('column_dataset_1').show(truncate=False)
+---------------------+
|column_dataset_1     |
+---------------------+
|W-B.7120RP1605794    |
|125858G_022BR/P070751|
+---------------------+

编辑:根据注释,匹配的子字符串可能与 df1.column_dataset_1 不同,因此我们需要对子字符串进行反向工程规范化的字符串。根据进行标准化的方式,以下udf可能会有所帮助(请注意,这将不包括匹配项中可能存在的任何前导/后跟非数字)。基本上,我们将通过char遍历字符串,并在原始字符串中找到规范化字符串的开始/结束索引,然后采用子字符串:

from pyspark.sql.functions import udf

@udf('string')
def find_matched(orig, normalized):
  n, d = ([], [])
  for i in range(len(orig)):
    if orig[i].isalnum(): 
      n.append(orig[i])
      d.append(i)
  idx = ''.join(n).find(normalized)
  return orig[d[idx]:d[idx+len(normalized)]] if idx >= 0 else None

df1.join(df2, cond3) \
   .withColumn('matched', find_matched('column_dataset_2', 'column_dataset_1_normalized')) \
   .select('column_dataset_2', 'matched', 'column_dataset_1_normalized') \
   .show(truncate=False)

+------------------------------------------------------------------------------------+-----------------------+---------------------------+
|column_dataset_2                                                                    |matched                |column_dataset_1_normalized|
+------------------------------------------------------------------------------------+-----------------------+---------------------------+
|Por ejemplo, si W-B.7120RP-1605794se trata de un archivo de texto,                  |W-B.7120RP-1605794     |WB7120RP1605794            |
|utilizados 125858G_022BR/P-070751 frecuentemente (por ejemplo, un texto que describe|125858G_022BR/P-070751 |125858G022BRP070751        |
+------------------------------------------------------------------------------------+-----------------------+---------------------------+